diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 74c58fe..b43c104 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,4 +1,4 @@ -# Architecture: ContextCortex (v2.14.0) +# Architecture: ContextCortex (v2.15.0) ContextCortex provides fast, local, syntax-aware semantic and hybrid search over codebases, git repositories, markdown notes, architecture documents, and system documentation. It is built natively on the **Model Context Protocol (MCP) SDK 2.0.0+** using `FastMCP`, with an integrated FastAPI web engine, real-time diagnostic logging, pluggable relational and vector store backends (PostgreSQL 16 with pgvector, Qdrant, ChromaDB, and SQLite), automatic polling daemons, multi-provider webhooks, interactive dependency topology graph explorer, RFC 9728 OAuth 2.1 Protected Resource Server, 3-tier API key RBAC, and a React 19 administrative dashboard. diff --git a/DEVELOPER_DOCS.md b/DEVELOPER_DOCS.md index 6a247a5..b61c309 100644 --- a/DEVELOPER_DOCS.md +++ b/DEVELOPER_DOCS.md @@ -1,4 +1,4 @@ -# Developer Documentation: ContextCortex (v2.14.0) +# Developer Documentation: ContextCortex (v2.15.0) This document provides instructions for developing, testing, configuring, and running ContextCortex locally. diff --git a/README.md b/README.md index 86dab54..93739c2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ContextCortex (v2.14.0) +# ContextCortex (v2.15.0) [![Build and Publish Docker Image](https://github.com/spelech/contextcortex/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/spelech/contextcortex/actions/workflows/docker-publish.yml) diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md index 517253e..d480db4 100644 --- a/REQUIREMENTS.md +++ b/REQUIREMENTS.md @@ -1,8 +1,8 @@ -# Software Requirements Specification: ContextCortex (v2.14.0) +# Software Requirements Specification: ContextCortex (v2.15.0) > **Note:** This document is automatically generated and verified against the live test suite by `scripts/generate_requirements.py` and `tests/backend/test_requirements_sync.py`. -**Test Verification Baseline:** **934 Automated Tests** (619 Pytest Backend + 269 Vitest Frontend + 46 Playwright E2E). +**Test Verification Baseline:** **968 Automated Tests** (651 Pytest Backend + 271 Vitest Frontend + 46 Playwright E2E). --- @@ -934,6 +934,29 @@ classDiagram - `test_embedding_cache_invalidation` - `test_embedding_cache_empty_inputs` +#### `tests/test_file_mcp_and_api.py` (5 tests) +- `test_env` +- `test_mcp_handle_read_file` +- `test_mcp_handle_summarize_file` +- `test_api_read_file` +- `test_api_summarize_file` + +#### `tests/test_file_reader.py` (8 tests) +- `test_safe_path_resolution_local_storage` +- `test_safe_path_resolution_indexed_paths` +- `test_path_traversal_and_invalid_paths_rejected` +- `test_read_text_file_full_and_line_slicing` +- `test_read_file_capping_max_lines_and_truncation` +- `test_binary_file_detection_and_rejection` +- `test_read_nonexistent_file_raises_not_found` +- `test_get_file_reader_service_singleton` + +#### `tests/test_file_settings.py` (4 tests) +- `test_file_summaries_table_has_summary_text_column` +- `test_file_settings_defaults` +- `test_set_file_settings_persists` +- `test_file_settings_api_endpoints` + #### `tests/test_git_incremental.py` (6 tests) - `test_compute_git_repo_delta` - `test_compute_git_repo_delta_custom_extensions` @@ -1100,12 +1123,31 @@ and leaves the prior indexed state intact without data loss._ - `test_process_file_content_doc_caching` - `test_process_file_content_file_size_guard` +#### `tests/test_processor_summarization.py` (3 tests) +- `test_env` +- `test_large_file_auto_summarization` +- `test_large_file_disabled_summarization` + #### `tests/test_storage_api_routes.py` (4 tests) - `test_storage_upload_and_get_file` - `test_storage_upload_multipart_and_put` - `test_storage_validation_and_errors` - `test_ingestion_catalog_endpoint` +#### `tests/test_summarizer.py` (12 tests) +- `test_db` - _Sets up an isolated SQLite database for summarizer testing._ +- `test_generate_file_summary_success` +- `test_generate_file_summary_handles_litellm_exception` +- `test_get_or_create_summary_returns_cached_summary` +- `test_get_or_create_summary_cache_miss_reads_disk_and_persists` +- `test_get_or_create_summary_force_refresh_updates_existing_cache` +- `test_get_or_create_summary_litellm_failure_does_not_crash` +- `test_get_summarizer_service_uses_settings_model` +- `test_get_or_create_summary_nonexistent_file_raises_not_found` +- `test_get_or_create_summary_vector_store_failure_resilience` +- `test_get_or_create_summary_reads_via_file_reader` +- `test_generate_file_summary_truncates_huge_content` + #### `tests/test_webhooks.py` (12 tests) - `test_github_webhook_no_secret` - `test_github_webhook_with_secret_valid_and_invalid` @@ -1176,6 +1218,10 @@ and leaves the prior indexed state intact without data loss._ - switches to manual input when Custom is selected from dropdown or link clicked - disables discover button and shows spinner while isDiscovering is true +#### `FileSettings.test.tsx` (2 tests) +- renders settings fields and loads data from api +- submits updated settings when Save button is clicked + #### `GitRepoManager.test.tsx` (13 tests) - renders repository list with status badges, auto-sync buttons, and details - shows empty state when no repositories are registered diff --git a/app/api/routers/files.py b/app/api/routers/files.py new file mode 100644 index 0000000..e00bf8b --- /dev/null +++ b/app/api/routers/files.py @@ -0,0 +1,77 @@ +import logging +from typing import Optional +from pydantic import BaseModel, Field +from fastapi import APIRouter, Query +from fastapi.responses import JSONResponse + +from app.services.file_reader import get_file_reader_service +from app.services.summarizer import get_summarizer_service +from app.services.auth import ForbiddenError + +logger = logging.getLogger("contextcortex.api.files") +router = APIRouter() + + +class FileSummarizePayload(BaseModel): + path: str = Field(..., description="Path to the file to summarize") + repo: Optional[str] = Field(None, description="Optional repository or storage namespace") + force_refresh: bool = Field(False, description="Whether to bypass cache and regenerate summary") + + +@router.get("/admin/api/files/read") +async def api_read_file( + path: str = Query(..., description="Target file path (relative to repo/storage or absolute within indexed root)"), + repo: Optional[str] = Query(None, description="Optional repo or storage namespace"), + start_line: Optional[int] = Query(None, description="1-based starting line number"), + end_line: Optional[int] = Query(None, description="1-based ending line number"), +): + try: + reader = get_file_reader_service() + res = reader.read_file( + path=path, + repo=repo, + start_line=start_line, + end_line=end_line + ) + return res + except ForbiddenError as fe: + logger.warning(f"Forbidden access reading file '{path}': {fe}") + return JSONResponse(status_code=403, content={"error": "Access denied. Path is outside allowed repositories."}) + except FileNotFoundError as fne: + logger.warning(f"File not found reading '{path}': {fne}") + return JSONResponse(status_code=404, content={"error": "File not found."}) + except ValueError as ve: + logger.warning(f"Validation error reading file '{path}': {ve}") + return JSONResponse(status_code=400, content={"error": "Invalid file parameters."}) + except Exception as e: + logger.error(f"Error reading file '{path}': {e}") + return JSONResponse(status_code=500, content={"error": "Internal server error reading file."}) + + +@router.post("/admin/api/files/summarize") +async def api_summarize_file(payload: FileSummarizePayload): + try: + summarizer = get_summarizer_service() + summary_text = summarizer.get_or_create_summary( + filepath=payload.path, + repo=payload.repo, + force_refresh=payload.force_refresh + ) + return { + "path": payload.path, + "repo": payload.repo, + "summary": summary_text, + "status": "success" + } + except ForbiddenError as fe: + logger.warning(f"Forbidden access summarizing file '{payload.path}': {fe}") + return JSONResponse(status_code=403, content={"error": "Access denied. Path is outside allowed repositories."}) + except FileNotFoundError as fne: + logger.warning(f"File not found summarizing '{payload.path}': {fne}") + return JSONResponse(status_code=404, content={"error": "File not found."}) + except ValueError as ve: + logger.warning(f"Validation error summarizing file '{payload.path}': {ve}") + return JSONResponse(status_code=400, content={"error": "Invalid file parameters."}) + except Exception as e: + logger.error(f"Error summarizing file '{payload.path}': {e}") + return JSONResponse(status_code=500, content={"error": "Internal server error summarizing file."}) diff --git a/app/api/routers/settings.py b/app/api/routers/settings.py index d14d265..cffa42e 100644 --- a/app/api/routers/settings.py +++ b/app/api/routers/settings.py @@ -10,7 +10,8 @@ from app.models.schemas import ( TokenRequest, HostCredentialRequest, VectorStoreTestRequest, VectorStoreSwitchRequest, - AutoSyncSettingsRequest, EmbeddingSettingsRequest + AutoSyncSettingsRequest, EmbeddingSettingsRequest, + FileSettingsRequest ) import app.services.database as db_service import app.services.git_manager as gm_service @@ -363,3 +364,23 @@ async def api_save_embedding_settings(payload: EmbeddingSettingsRequest): logger.error(f"Error updating embedding settings: {e}") return JSONResponse(status_code=500, content={"status": "error", "error": str(e), "message": str(e)}) +@router.get("/admin/api/settings/files") +async def api_get_file_settings(): + try: + cfg = db_service.get_file_settings() + return cfg + except Exception as e: + logger.error(f"Error reading file settings: {e}") + return JSONResponse(status_code=500, content={"error": "Failed to read file settings."}) + +@router.post("/admin/api/settings/files") +async def api_save_file_settings(payload: FileSettingsRequest): + try: + data = payload.model_dump(exclude_unset=True) + updated = db_service.set_file_settings(data) + return updated + except Exception as e: + logger.error(f"Error saving file settings: {e}") + return JSONResponse(status_code=500, content={"error": "Failed to save file settings."}) + + diff --git a/app/api/routes.py b/app/api/routes.py index d00fb88..79594ca 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -42,6 +42,7 @@ from app.api.routers.storage import router as storage_router from app.api.routers.ingestion import router as ingestion_router from app.api.routers.navigator import router as navigator_router +from app.api.routers.files import router as files_router logger = logging.getLogger("contextcortex.api") @@ -54,6 +55,7 @@ router.include_router(storage_router) router.include_router(ingestion_router) router.include_router(navigator_router) +router.include_router(files_router) __all__ = [ "router", diff --git a/app/mcp/handlers/__init__.py b/app/mcp/handlers/__init__.py index 194888f..90fa55d 100644 --- a/app/mcp/handlers/__init__.py +++ b/app/mcp/handlers/__init__.py @@ -27,6 +27,10 @@ handle_manage_local_file, handle_what_is_ingested, ) +from app.mcp.handlers.file_handlers import ( + handle_read_file, + handle_summarize_file, +) __all__ = [ "handle_search_code", @@ -46,4 +50,6 @@ "handle_manage_adr", "handle_manage_local_file", "handle_what_is_ingested", + "handle_read_file", + "handle_summarize_file", ] diff --git a/app/mcp/handlers/file_handlers.py b/app/mcp/handlers/file_handlers.py new file mode 100644 index 0000000..060f0d4 --- /dev/null +++ b/app/mcp/handlers/file_handlers.py @@ -0,0 +1,88 @@ +import logging +import sys +from typing import Optional, Annotated +from pydantic import Field + +from app.services.auth import enforce_tool_permission, Role, ForbiddenError +from app.services.file_reader import get_file_reader_service, FileReaderService +from app.services.summarizer import get_summarizer_service, SummarizerService + +logger = logging.getLogger("contextcortex.mcp.files") + + +def _get_tools_attr(name, default): + t_mod = sys.modules.get("app.mcp.tools") + return getattr(t_mod, name, default) if t_mod else default + + +async def handle_read_file( + path: Annotated[str, Field(description="Relative or absolute file path within a watched local directory or uploaded local storage.")], + repo: Annotated[Optional[str], Field(description="Optional repository identifier or storage namespace to target.")] = None, + start_line: Annotated[Optional[int], Field(description="1-based starting line number (inclusive).")] = None, + end_line: Annotated[Optional[int], Field(description="1-based ending line number (inclusive).")] = None +) -> str: + """Read entire file content or bounded line ranges from monitored local directories or local storage with safety limits.""" + try: + enforce_tool_permission(Role.VIEWER) + reader_fn = _get_tools_attr("get_file_reader_service", get_file_reader_service) + reader = reader_fn() + + result = reader.read_file( + path=path, + repo=repo, + start_line=start_line, + end_line=end_line + ) + + trunc_msg = f" (truncated at line limit)" if result.get("truncated") else "" + header = ( + f"### File: `{result['filepath']}` ({result['size_bytes']} bytes, " + f"lines {result['start_line']}-{result['end_line']} of {result['total_lines']}{trunc_msg})\n" + f"- **Source:** `{result['source']}`\n\n" + ) + return f"{header}```\n{result['content']}\n```" + + except ForbiddenError as fe: + logger.warning(f"Forbidden error in handle_read_file ({path}): {fe}") + return f"Forbidden: {str(fe)}" + except FileNotFoundError as fne: + return f"Error: File not found: {str(fne)}" + except ValueError as ve: + return f"Error: {str(ve)}" + except Exception as e: + logger.error(f"Error reading file '{path}': {e}") + return f"Error reading file: {str(e)}" + + +async def handle_summarize_file( + path: Annotated[str, Field(description="Path to the file to summarize (monitored local path or uploaded local storage).")], + repo: Annotated[Optional[str], Field(description="Optional repository or storage namespace filter.")] = None, + force_refresh: Annotated[bool, Field(description="If True, bypasses SQLite cache and regenerates a fresh LLM summary.")] = False +) -> str: + """Retrieve an existing summary or generate a structured LLM executive summary for a large file.""" + try: + enforce_tool_permission(Role.VIEWER) + summarizer_fn = _get_tools_attr("get_summarizer_service", get_summarizer_service) + summarizer = summarizer_fn() + + summary_text = summarizer.get_or_create_summary( + filepath=path, + repo=repo, + force_refresh=force_refresh + ) + + if not summary_text or not summary_text.strip(): + return f"Notice: Could not generate summary for `{path}` (file may be empty or summarization failed)." + + return f"### Summary: `{path}`\n\n{summary_text.strip()}" + + except ForbiddenError as fe: + logger.warning(f"Forbidden error in handle_summarize_file ({path}): {fe}") + return f"Forbidden: {str(fe)}" + except FileNotFoundError as fne: + return f"Error: File not found: {str(fne)}" + except ValueError as ve: + return f"Error: {str(ve)}" + except Exception as e: + logger.error(f"Error summarizing file '{path}': {e}") + return f"Error summarizing file: {str(e)}" diff --git a/app/mcp/tools.py b/app/mcp/tools.py index 1c62bff..dedf98b 100644 --- a/app/mcp/tools.py +++ b/app/mcp/tools.py @@ -28,6 +28,8 @@ handle_manage_adr, handle_manage_local_file, handle_what_is_ingested, + handle_read_file, + handle_summarize_file, ) logger = logging.getLogger("contextcortex.mcp") @@ -124,6 +126,19 @@ def register_mcp_tools_and_resources(server=None): description="Inspect all ingested Git repositories, monitored local paths, and uploaded local storage files with optional filtering and detailed file trees." )(handle_what_is_ingested) + if "read_file" not in existing_tools: + server.tool( + name="read_file", + description="Read entire file content or bounded line ranges from monitored local directories or local storage with safety limits." + )(handle_read_file) + + if "summarize_file" not in existing_tools: + server.tool( + name="summarize_file", + description="Retrieve an existing summary or generate a structured LLM executive summary for a large file." + )(handle_summarize_file) + + existing_resources = {str(r.uri) for r in server._resource_manager.list_resources()} if "knowledge://catalog/summary" not in existing_resources: server.resource( diff --git a/app/models/schemas.py b/app/models/schemas.py index 1bb8e59..2422f0f 100644 --- a/app/models/schemas.py +++ b/app/models/schemas.py @@ -51,6 +51,14 @@ class ApiClientCallRecord(BaseModel): line_number: int created_at: Optional[str] = None +class FileSettingsRequest(BaseModel): + summary_enabled: Optional[bool] = None + summary_threshold_kb: Optional[int] = None + summary_max_file_size_mb: Optional[int] = None + read_file_max_lines: Optional[int] = None + summary_chat_model: Optional[str] = None + + class CodeSymbol(BaseModel): name: str full_symbol: str diff --git a/app/services/database/__init__.py b/app/services/database/__init__.py index 1d19857..ddb0b7b 100644 --- a/app/services/database/__init__.py +++ b/app/services/database/__init__.py @@ -38,6 +38,9 @@ set_embedding_db_config, get_vision_ocr_model, get_chat_model, + get_file_settings, + set_file_settings, + ensure_file_summaries_columns, ) from app.services.database.credentials import ( list_git_host_credentials, @@ -105,6 +108,9 @@ "set_embedding_db_config", "get_vision_ocr_model", "get_chat_model", + "get_file_settings", + "set_file_settings", + "ensure_file_summaries_columns", "list_git_host_credentials", "get_git_host_credential", "save_git_host_credential", diff --git a/app/services/database/connection.py b/app/services/database/connection.py index 521e4cd..5292aab 100644 --- a/app/services/database/connection.py +++ b/app/services/database/connection.py @@ -320,3 +320,52 @@ def get_chat_model() -> str: if stored and stored.strip(): return stored.strip() return (os.getenv("CHAT_MODEL") or "gemini-2.5-flash").strip() + + +def ensure_file_summaries_columns(conn=None): + """Ensures summary_text column exists on file_summaries table.""" + try: + raw_conn = get_db_connection() + try: + cols = [r["name"] for r in raw_conn.execute("PRAGMA table_info(file_summaries)").fetchall()] + if cols and "summary_text" not in cols: + raw_conn.execute("ALTER TABLE file_summaries ADD COLUMN summary_text TEXT") + raw_conn.commit() + finally: + raw_conn.close() + except Exception as e: + logger.debug(f"Migration error for file_summaries: {e}") + + + +def get_file_settings() -> Dict[str, Any]: + """Retrieves file reading and large file summarization settings.""" + enabled_val = get_metadata("file_summary_enabled") + threshold_val = get_metadata("file_summary_threshold_kb") + max_size_val = get_metadata("file_summary_max_size_mb") + max_lines_val = get_metadata("file_read_max_lines") + model_val = get_metadata("file_summary_model") + + return { + "summary_enabled": enabled_val != "0", + "summary_threshold_kb": int(threshold_val) if threshold_val and threshold_val.isdigit() else 500, + "summary_max_file_size_mb": int(max_size_val) if max_size_val and max_size_val.isdigit() else 10, + "read_file_max_lines": int(max_lines_val) if max_lines_val and max_lines_val.isdigit() else 2000, + "summary_chat_model": (model_val or get_chat_model()).strip(), + } + + +def set_file_settings(payload: Dict[str, Any]) -> Dict[str, Any]: + """Updates file reading and summarization settings.""" + if "summary_enabled" in payload: + set_metadata("file_summary_enabled", "1" if payload["summary_enabled"] else "0") + if "summary_threshold_kb" in payload: + set_metadata("file_summary_threshold_kb", str(max(10, int(payload["summary_threshold_kb"])))) + if "summary_max_file_size_mb" in payload: + set_metadata("file_summary_max_size_mb", str(max(1, int(payload["summary_max_file_size_mb"])))) + if "read_file_max_lines" in payload: + set_metadata("file_read_max_lines", str(max(10, int(payload["read_file_max_lines"])))) + if "summary_chat_model" in payload and payload["summary_chat_model"]: + set_metadata("file_summary_model", str(payload["summary_chat_model"]).strip()) + return get_file_settings() + diff --git a/app/services/database/engine.py b/app/services/database/engine.py index 2531607..23b9a1f 100644 --- a/app/services/database/engine.py +++ b/app/services/database/engine.py @@ -287,7 +287,15 @@ def init_db(vault_path: str = "/docs", engine: Optional[Engine] = None) -> Engin # Create all defined tables idempotently metadata.create_all(bind=eng) + try: + from app.services.database.connection import ensure_file_summaries_columns + with eng.connect() as conn: + ensure_file_summaries_columns(conn) + except Exception as me: + logger.debug(f"Column migration check: {me}") + # Seed default data _seed_defaults(eng, vault_path=vault_path) return eng + diff --git a/app/services/database/schema.py b/app/services/database/schema.py index e4f7638..24571b9 100644 --- a/app/services/database/schema.py +++ b/app/services/database/schema.py @@ -96,6 +96,7 @@ Column("tags", Text, nullable=True), Column("headings", Text, nullable=True), Column("keywords", Text, nullable=True), + Column("summary_text", Text, nullable=True), Column("mtime", Float, nullable=True), ) diff --git a/app/services/file_reader.py b/app/services/file_reader.py new file mode 100644 index 0000000..10c8a55 --- /dev/null +++ b/app/services/file_reader.py @@ -0,0 +1,267 @@ +import os +import logging +from typing import Optional, Tuple, Dict, Any, List + +from app.services.database.connection import get_db_connection, get_file_settings +from app.services.local_storage import get_default_storage_path + +logger = logging.getLogger("contextcortex.file_reader") + + +class FileReaderService: + """Service for securely resolving and reading files across local storage and watched paths.""" + + def __init__(self, storage_root: Optional[str] = None): + self._storage_root = storage_root + + @property + def storage_root(self) -> str: + return os.path.abspath(self._storage_root or get_default_storage_path()) + + def _validate_path_security(self, path: str) -> None: + if not path or not isinstance(path, str) or "\x00" in path: + raise ValueError("Path traversal or invalid path detected") + + norm = path.replace("\\", "/") + parts = norm.split("/") + if any(part == ".." for part in parts): + raise ValueError("Path traversal or invalid path detected") + + def _is_within_root(self, target: str, root: str) -> bool: + target_abs = os.path.abspath(target) + root_abs = os.path.abspath(root) + + if os.path.isfile(root_abs): + return ( + target_abs == root_abs + and os.path.realpath(target_abs) == os.path.realpath(root_abs) + ) + + try: + if os.path.commonpath([target_abs, root_abs]) != root_abs: + return False + except ValueError: + return False + + # Verify symlink containment to prevent symlink breakouts + target_real = os.path.realpath(target_abs) + root_real = os.path.realpath(root_abs) + try: + if os.path.commonpath([target_real, root_real]) != root_real: + return False + except ValueError: + return False + + return True + + def _get_authorized_indexed_paths(self) -> List[Dict[str, Any]]: + try: + with get_db_connection() as conn: + rows = conn.execute( + "SELECT path, repo FROM indexed_paths WHERE enabled = 1" + ).fetchall() + return [{"path": r["path"], "repo": r["repo"]} for r in rows] + except Exception as e: + logger.warning(f"Failed to fetch authorized indexed_paths: {e}") + return [] + + def resolve_safe_path(self, path: str, repo: Optional[str] = None) -> Tuple[str, str]: + """Resolves target path safely within authorized watched paths or local storage. + + Returns: + Tuple[str, str]: (abs_path, source_type) where source_type is 'indexed_path' or 'local_storage'. + """ + self._validate_path_security(path) + storage_root = self.storage_root + indexed_paths = self._get_authorized_indexed_paths() + + # 1. repo specified as local_storage + if repo == "local_storage": + target = ( + os.path.abspath(path) + if os.path.isabs(path) + else os.path.abspath(os.path.join(storage_root, path)) + ) + if not self._is_within_root(target, storage_root): + raise ValueError("Path outside authorized roots") + return target, "local_storage" + + # 2. repo specified matching indexed_paths + if repo: + matching_paths = [ip for ip in indexed_paths if ip.get("repo") == repo] + if not matching_paths: + raise ValueError(f"Repository '{repo}' not found or not authorized") + + if os.path.isabs(path): + target = os.path.abspath(path) + for ip in matching_paths: + root = os.path.abspath(ip["path"]) + if self._is_within_root(target, root): + return target, "indexed_path" + raise ValueError("Path outside authorized roots") + else: + for ip in matching_paths: + root = os.path.abspath(ip["path"]) + candidate = os.path.abspath(os.path.join(root, path)) + if os.path.lexists(candidate): + if not self._is_within_root(candidate, root): + raise ValueError("Path outside authorized roots") + return candidate, "indexed_path" + + for ip in matching_paths: + root = os.path.abspath(ip["path"]) + candidate = os.path.abspath(os.path.join(root, path)) + if self._is_within_root(candidate, root): + return candidate, "indexed_path" + raise ValueError("Path outside authorized roots") + + # 3. repo is None + if os.path.isabs(path): + target = os.path.abspath(path) + if self._is_within_root(target, storage_root): + return target, "local_storage" + for ip in indexed_paths: + root = os.path.abspath(ip["path"]) + if self._is_within_root(target, root): + return target, "indexed_path" + raise ValueError("Path outside authorized roots") + + # Relative path without repo specified: + cand_storage = os.path.abspath(os.path.join(storage_root, path)) + if os.path.lexists(cand_storage): + if not self._is_within_root(cand_storage, storage_root): + raise ValueError("Path outside authorized roots") + return cand_storage, "local_storage" + + for ip in indexed_paths: + root = os.path.abspath(ip["path"]) + cand_ip = os.path.abspath(os.path.join(root, path)) + if os.path.lexists(cand_ip): + if not self._is_within_root(cand_ip, root): + raise ValueError("Path outside authorized roots") + return cand_ip, "indexed_path" + + # If not existing on disk, check if it falls inside valid storage root + if self._is_within_root(cand_storage, storage_root): + return cand_storage, "local_storage" + + for ip in indexed_paths: + root = os.path.abspath(ip["path"]) + cand_ip = os.path.abspath(os.path.join(root, path)) + if self._is_within_root(cand_ip, root): + return cand_ip, "indexed_path" + + raise ValueError("Path outside authorized roots") + + def is_binary_file(self, abs_path: str) -> bool: + """Detects binary files by checking for null bytes in the initial sample.""" + with open(abs_path, "rb") as f: + chunk = f.read(8192) + return b"\x00" in chunk + + def read_file( + self, + path: str, + repo: Optional[str] = None, + start_line: Optional[int] = None, + end_line: Optional[int] = None, + max_lines: Optional[int] = None, + ) -> Dict[str, Any]: + """Reads a file with safe path resolution, binary checking, and line slicing.""" + abs_path, source_type = self.resolve_safe_path(path, repo=repo) + + if not os.path.exists(abs_path): + raise FileNotFoundError(f"File not found: {path}") + if os.path.isdir(abs_path): + raise IsADirectoryError(f"Target path is a directory: {path}") + + if self.is_binary_file(abs_path): + raise ValueError(f"Cannot read binary file: {path}") + + size_bytes = os.path.getsize(abs_path) + with open(abs_path, "r", encoding="utf-8", errors="replace") as f: + text = f.read() + + settings = get_file_settings() + settings_max_lines = settings.get("read_file_max_lines", 2000) + effective_max_lines = ( + max_lines if (max_lines is not None and max_lines > 0) else settings_max_lines + ) + + if not text: + return { + "filepath": path, + "content": "", + "start_line": 1, + "end_line": 0, + "total_lines": 0, + "size_bytes": size_bytes, + "truncated": False, + "source": source_type, + } + + lines = text.splitlines() + total_lines = len(lines) + + s_line = start_line if (start_line is not None and start_line >= 1) else 1 + e_line = end_line if end_line is not None else total_lines + + if s_line > e_line: + raise ValueError( + f"start_line cannot be greater than end_line ({s_line} > {e_line})" + ) + + if s_line > total_lines: + return { + "filepath": path, + "content": "", + "start_line": s_line, + "end_line": min(e_line, total_lines), + "total_lines": total_lines, + "size_bytes": size_bytes, + "truncated": False, + "source": source_type, + } + + requested_count = min(e_line, total_lines) - s_line + 1 + if effective_max_lines is not None and requested_count > effective_max_lines: + truncated = True + actual_end = s_line + effective_max_lines - 1 + else: + truncated = False + actual_end = min(e_line, total_lines) + + start_idx = s_line - 1 + end_idx = actual_end + sliced_content = "\n".join(lines[start_idx:end_idx]) + + return { + "filepath": path, + "content": sliced_content, + "start_line": s_line, + "end_line": actual_end, + "total_lines": total_lines, + "size_bytes": size_bytes, + "truncated": truncated, + "source": source_type, + } + + +_file_reader_service: Optional[FileReaderService] = None + + +def get_file_reader_service( + reset: bool = False, storage_root: Optional[str] = None +) -> FileReaderService: + """Singleton / factory for FileReaderService.""" + global _file_reader_service + if reset or _file_reader_service is None: + _file_reader_service = FileReaderService(storage_root=storage_root) + return _file_reader_service + + +def reset_file_reader_service(): + """Resets the singleton instance for testing.""" + global _file_reader_service + _file_reader_service = None + diff --git a/app/services/indexing/git_syncer.py b/app/services/indexing/git_syncer.py index 1ddd341..dd41a78 100644 --- a/app/services/indexing/git_syncer.py +++ b/app/services/indexing/git_syncer.py @@ -323,7 +323,7 @@ def sync_single_git_repo(repo_id: int): batch_indexed_files.clear() if batch_summaries: conn.executemany( - "INSERT OR REPLACE INTO file_summaries (filepath, repo, title, folder, category, tags, headings, keywords, mtime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + "INSERT OR REPLACE INTO file_summaries (filepath, repo, title, folder, category, tags, headings, keywords, summary_text, mtime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", batch_summaries ) batch_summaries.clear() diff --git a/app/services/indexing/local_syncer.py b/app/services/indexing/local_syncer.py index 96206b2..40a0dbe 100644 --- a/app/services/indexing/local_syncer.py +++ b/app/services/indexing/local_syncer.py @@ -164,7 +164,7 @@ def sync_local_paths(): ) if all_summaries: conn.executemany( - "INSERT OR REPLACE INTO file_summaries (filepath, repo, title, folder, category, tags, headings, keywords, mtime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + "INSERT OR REPLACE INTO file_summaries (filepath, repo, title, folder, category, tags, headings, keywords, summary_text, mtime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", all_summaries ) if all_symbols: diff --git a/app/services/indexing/processor.py b/app/services/indexing/processor.py index 43eaa29..6664214 100644 --- a/app/services/indexing/processor.py +++ b/app/services/indexing/processor.py @@ -175,12 +175,51 @@ def process_file_content( folder = os.path.dirname(rel_path) or "root" category = category_override or folder + file_settings = {} + try: + from app.services.database.connection import get_file_settings + file_settings = get_file_settings() + except Exception: + pass + + summary_enabled = file_settings.get("summary_enabled", True) + summary_threshold = file_settings.get("summary_threshold_kb", 500) * 1024 + summary_max_size = file_settings.get("summary_max_file_size_mb", 10) * 1024 * 1024 + is_pdf_file = doc_type == "pdf" or filepath.lower().endswith(".pdf") - size_limit = MAX_PDF_SIZE_BYTES if is_pdf_file else MAX_FILE_SIZE_BYTES - if content and len(content.encode("utf-8")) > size_limit: - limit_desc = f"{MAX_PDF_SIZE_BYTES // (1024*1024)}MB" if is_pdf_file else "500KB" - logger.warning(f"Skipping file {filepath} exceeding {limit_desc} size limit ({len(content.encode('utf-8'))} bytes)") - mtime = os.path.getmtime(filepath) if os.path.exists(filepath) else 0.0 + content_bytes_len = len(content.encode("utf-8")) if content else 0 + + if is_pdf_file and content_bytes_len > MAX_PDF_SIZE_BYTES: + logger.warning(f"Skipping PDF file {filepath} exceeding {MAX_PDF_SIZE_BYTES // (1024*1024)}MB limit") + mtime = 0.0 + summary_tuple = (filepath, repo, title, folder, category, json.dumps([]), json.dumps([]), json.dumps([]), None, mtime) + return points, ast_symbols, summary_tuple, ast_relationships, api_routes, api_calls + + if not is_pdf_file and content_bytes_len > summary_max_size: + logger.warning(f"Skipping file {filepath} exceeding {summary_max_size // (1024*1024)}MB max limit ({content_bytes_len} bytes)") + mtime = 0.0 + summary_tuple = (filepath, repo, title, folder, category, json.dumps([]), json.dumps([]), json.dumps([]), None, mtime) + return points, ast_symbols, summary_tuple, ast_relationships, api_routes, api_calls + + if not is_pdf_file and content_bytes_len > summary_threshold: + mtime = 0.0 + summary_text = None + if summary_enabled: + try: + from app.services.summarizer import get_summarizer_service + summarizer = get_summarizer_service() + gen_summary, summary_doc = summarizer.generate_file_summary( + filepath=filepath, + content=content, + repo=repo, + category=category + ) + summary_text = gen_summary or None + if summary_doc: + points.append(summary_doc) + except Exception as se: + logger.warning(f"Auto-summarization failed for {filepath}: {se}") + summary_tuple = ( filepath, repo, @@ -190,6 +229,7 @@ def process_file_content( json.dumps([]), json.dumps([]), json.dumps([]), + summary_text, mtime ) return points, ast_symbols, summary_tuple, ast_relationships, api_routes, api_calls @@ -350,6 +390,7 @@ def process_file_content( json.dumps(tags), json.dumps(list(set(headings[:20]))), json.dumps(keywords), + None, mtime ) diff --git a/app/services/local_storage.py b/app/services/local_storage.py index bb8dc2a..41c9dd6 100644 --- a/app/services/local_storage.py +++ b/app/services/local_storage.py @@ -157,8 +157,8 @@ def index_file( # Insert file summary if summary_tuple: conn.execute( - """INSERT INTO file_summaries (filepath, repo, title, folder, category, tags, headings, keywords, mtime) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", + """INSERT INTO file_summaries (filepath, repo, title, folder, category, tags, headings, keywords, summary_text, mtime) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", summary_tuple ) diff --git a/app/services/summarizer.py b/app/services/summarizer.py new file mode 100644 index 0000000..f35ac37 --- /dev/null +++ b/app/services/summarizer.py @@ -0,0 +1,325 @@ +import os +import uuid +import logging +from typing import Optional, Dict, Any, Tuple +from openai import OpenAI + +from app.services.database.connection import ( + get_db_connection, + get_file_settings, + get_chat_model, + get_embedding_db_config, +) +from app.services.vector_store.base import VectorDocument, VectorStore +from app.services.vector_store.manager import get_vector_store + +logger = logging.getLogger("contextcortex.summarizer") + +DEFAULT_SYSTEM_PROMPT = ( + "You are an expert software architect and technical documentation assistant. " + "Analyze the provided file content and produce a concise, structured markdown summary covering:\n" + "- **Overview & Purpose**: High-level purpose and core responsibility of this file.\n" + "- **Key Components**: Main classes, functions, interfaces, or sections.\n" + "- **Architectural Dependencies & Data Flow**: Key imports, integrations, and interactions with other modules.\n\n" + "Keep the summary clear, accurate, and formatted in clean markdown. Do not include introductory or concluding conversational filler." +) + + +def format_user_prompt(filepath: str, content: str, repo: str = "local") -> str: + """Formats user prompt containing target file path, repo context, and content.""" + # Truncate content at reasonable limit (e.g. 200k chars) to prevent context window overflow + max_chars = 200_000 + if len(content) > max_chars: + content_snippet = content[:max_chars] + truncation_note = " (truncated for LLM context ceiling)" + else: + content_snippet = content + truncation_note = "" + + return ( + f"File: {filepath}{truncation_note}\n" + f"Repository: {repo}\n\n" + f"```\n{content_snippet}\n```\n\n" + "Please provide the structured markdown summary." + ) + + +def get_summary_point_id(repo: str, rel_path: str) -> str: + """Computes a deterministic UUID for the file's summary vector document.""" + namespace = uuid.uuid5(uuid.NAMESPACE_DNS, "contextcortex.lan") + return str(uuid.uuid5(namespace, f"{repo}:{rel_path}#summary")) + + +class SummarizerService: + """ + Summarizes source files and documents using LiteLLM / OpenAI chat completions, + caches summaries in SQLite file_summaries table, and indexes them in the VectorStore. + """ + + def __init__( + self, + client: Optional[Any] = None, + vector_store: Optional[VectorStore] = None, + ): + self._client = client + self._vector_store = vector_store + + @property + def client(self) -> Any: + if self._client is not None: + return self._client + + db_cfg = {} + try: + db_cfg = get_embedding_db_config() + except Exception: + pass + + litellm_url = ( + (db_cfg.get("litellm_url") if db_cfg else None) + or os.getenv("LITELLM_URL") + or "http://litellm:4000/v1" + ).strip() + litellm_key = ( + (db_cfg.get("litellm_api_key") if db_cfg else None) + or os.getenv("LITELLM_API_KEY") + or "dummy" + ).strip() + + self._client = OpenAI(base_url=litellm_url, api_key=litellm_key) + return self._client + + @client.setter + def client(self, client_instance: Any): + self._client = client_instance + + @property + def vector_store(self) -> Optional[VectorStore]: + if self._vector_store is not None: + return self._vector_store + try: + return get_vector_store() + except Exception as e: + logger.debug(f"Vector store unavailable: {e}") + return None + + @vector_store.setter + def vector_store(self, store_instance: Optional[VectorStore]): + self._vector_store = store_instance + + def _get_active_chat_model(self) -> str: + """Resolves chat model from file settings or general chat model settings.""" + try: + settings = get_file_settings() + model = settings.get("summary_chat_model") + if model and str(model).strip(): + return str(model).strip() + except Exception as e: + logger.debug(f"Failed to fetch file settings for chat model: {e}") + + return get_chat_model() + + def generate_file_summary( + self, + filepath: str, + content: str, + repo: str = "local", + category: Optional[str] = None, + ) -> Tuple[str, Optional[VectorDocument]]: + """ + Invokes LiteLLM / OpenAI chat completions to generate a structured markdown summary. + Returns a tuple of (summary_text, vector_document). + """ + rel_path = filepath + if os.path.isabs(filepath): + try: + rel_path = os.path.relpath(filepath, os.getcwd()) + if rel_path.startswith(".."): + rel_path = os.path.basename(filepath) + except Exception: + rel_path = os.path.basename(filepath) + + title = os.path.basename(filepath) + folder = os.path.dirname(rel_path) or "" + + active_model = self._get_active_chat_model() + user_prompt = format_user_prompt(filepath=rel_path, content=content, repo=repo) + + try: + response = self.client.chat.completions.create( + model=active_model, + messages=[ + {"role": "system", "content": DEFAULT_SYSTEM_PROMPT}, + {"role": "user", "content": user_prompt}, + ], + ) + summary_text = (response.choices[0].message.content or "").strip() + except Exception as e: + logger.warning(f"LiteLLM summarization failed for '{filepath}' using {active_model}: {e}") + return ("", None) + + if not summary_text: + return ("", None) + + # Generate embedding vectors if available + dense_v = None + s_indices = None + s_values = None + try: + from app.services.embeddings import get_hybrid_embeddings + emb = get_hybrid_embeddings(summary_text) + dense_v = emb.get("dense") + sparse = emb.get("sparse") + if sparse is not None: + s_indices = getattr(sparse, "indices", None) + s_values = getattr(sparse, "values", None) + except Exception: + pass + + point_id = get_summary_point_id(repo=repo, rel_path=rel_path) + vector_doc = VectorDocument( + id=point_id, + text=summary_text, + dense_vector=dense_v, + sparse_indices=s_indices, + sparse_values=s_values, + repo=repo, + doc_type="summary", + path=filepath, + rel_path=rel_path, + title=title, + folder=folder, + category=category, + heading="Summary", + start_line=1, + end_line=1, + metadata={ + "doc_type": "summary", + "is_summary": True, + "repo": repo, + "rel_path": rel_path, + "title": title, + "folder": folder, + }, + ) + + return (summary_text, vector_doc) + + def get_or_create_summary( + self, + filepath: str, + repo: Optional[str] = None, + force_refresh: bool = False, + ) -> str: + """ + Retrieves cached summary from SQLite file_summaries table if available. + On cache miss or force_refresh=True, reads the file, generates summary, + updates SQLite and VectorStore, and returns summary text. + """ + resolved_repo = repo or "local" + + # Check cached summary if not forcing refresh + if not force_refresh: + try: + with get_db_connection() as conn: + row = conn.execute( + "SELECT summary_text FROM file_summaries WHERE filepath = ?", + (filepath,), + ).fetchone() + if row and row["summary_text"]: + return str(row["summary_text"]) + except Exception as e: + logger.debug(f"Failed to query cached summary for '{filepath}': {e}") + + # Read file content from FileReaderService or disk + content = None + try: + from app.services.file_reader import get_file_reader_service + reader = get_file_reader_service() + read_res = reader.read_file(filepath, repo=resolved_repo) + if isinstance(read_res, dict) and "content" in read_res: + content = read_res["content"] + except Exception: + content = None + + if content is None: + if os.path.exists(filepath): + try: + with open(filepath, "r", encoding="utf-8", errors="replace") as f: + content = f.read() + except Exception as e: + logger.warning(f"Failed to read file from disk '{filepath}': {e}") + else: + try: + from app.services.local_storage import get_default_storage_path + storage_cand = os.path.join(get_default_storage_path(), filepath) + if os.path.exists(storage_cand): + with open(storage_cand, "r", encoding="utf-8", errors="replace") as f: + content = f.read() + except Exception: + pass + + if content is None: + raise FileNotFoundError(f"File not found on disk or storage: {filepath}") + + # Generate summary + summary_text, vector_doc = self.generate_file_summary( + filepath=filepath, + content=content, + repo=resolved_repo, + ) + + if not summary_text: + return "" + + # Persist summary in SQLite file_summaries + try: + with get_db_connection() as conn: + existing = conn.execute( + "SELECT filepath FROM file_summaries WHERE filepath = ?", + (filepath,), + ).fetchone() + if existing: + conn.execute( + "UPDATE file_summaries SET summary_text = ? WHERE filepath = ?", + (summary_text, filepath), + ) + else: + title = os.path.basename(filepath) + folder = os.path.dirname(filepath) + conn.execute( + """INSERT INTO file_summaries (filepath, repo, title, folder, summary_text) + VALUES (?, ?, ?, ?, ?)""", + (filepath, resolved_repo, title, folder, summary_text), + ) + conn.commit() + except Exception as e: + logger.warning(f"Failed to persist summary in SQLite for '{filepath}': {e}") + + # Upsert summary vector document to VectorStore + if vector_doc is not None: + try: + store = self.vector_store + if store is not None: + store.upsert_documents([vector_doc]) + except Exception as e: + logger.warning(f"Failed to upsert summary vector document for '{filepath}': {e}") + + return summary_text + + +_summarizer_service: Optional[SummarizerService] = None + + +def get_summarizer_service() -> SummarizerService: + """Retrieves or creates the SummarizerService singleton instance.""" + global _summarizer_service + if _summarizer_service is None: + _summarizer_service = SummarizerService() + return _summarizer_service + + +def reset_summarizer_service() -> None: + """Resets the singleton instance (primarily for test isolation).""" + global _summarizer_service + _summarizer_service = None diff --git a/docs/TEST_COVERAGE.md b/docs/TEST_COVERAGE.md index dce31aa..15f4ca2 100644 --- a/docs/TEST_COVERAGE.md +++ b/docs/TEST_COVERAGE.md @@ -1,4 +1,4 @@ -# Test Coverage Report: ContextCortex (v2.14.0) +# Test Coverage Report: ContextCortex (v2.15.0) This document provides comprehensive test coverage metrics and verification baselines for ContextCortex following the modular architectural restructuring, Codebase Navigator implementation, and test suite expansion. diff --git a/docs/reference/rest-api.md b/docs/reference/rest-api.md index d64dab0..3cae194 100644 --- a/docs/reference/rest-api.md +++ b/docs/reference/rest-api.md @@ -16,7 +16,7 @@ All administrative routes are prefixed with `/admin/api`. ```json { "status": "ok", - "version": "2.14.0", + "version": "2.15.0", "database": "connected", "vector_store": "healthy" } diff --git a/docs/requirements/index.md b/docs/requirements/index.md index 82bd290..f451314 100644 --- a/docs/requirements/index.md +++ b/docs/requirements/index.md @@ -1,6 +1,6 @@ # Software Requirements Specification (SRS) -This document establishes the Software Requirements Specification for ContextCortex (version 2.14.0). +This document establishes the Software Requirements Specification for ContextCortex (version 2.15.0). This specification is written in accordance with the **ASD-STE100 Simplified Technical English (Issue 9)** standard and ISO/IEC/IEEE 29148 requirements engineering standards. diff --git a/docs/superpowers/plans/2026-09-18-file-reading-and-large-file-summarization.md b/docs/superpowers/plans/2026-09-18-file-reading-and-large-file-summarization.md new file mode 100644 index 0000000..9edab3d --- /dev/null +++ b/docs/superpowers/plans/2026-09-18-file-reading-and-large-file-summarization.md @@ -0,0 +1,151 @@ +# File Reading and Large File Summarization Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Implement full and sliced file retrieval (`read_file`), automated and on-demand large file LLM summarization (`summarize_file`), and configurable UI thresholds for ContextCortex. + +**Architecture:** +- `FileReaderService` securely reads and line-slices files across watched paths and local storage. +- `SummarizerService` queries LiteLLM to generate structured markdown summaries for large files (>500KB or on-demand), stores them in SQLite (`file_summaries.summary_text`), and embeds them into the vector store. +- FastMCP exposes `read_file` and `summarize_file` tools. +- Settings UI and backend provide configurable thresholds (`summary_enabled`, `summary_threshold_kb`, `summary_max_file_size_mb`, `read_file_max_lines`, `summary_chat_model`). + +**Tech Stack:** Python 3.11, FastAPI, SQLite / SQLAlchemy, FastMCP, LiteLLM / OpenAI client, React, TypeScript, TailwindCSS, Vite. + +## Global Constraints +- Do not introduce breaking changes to existing MCP tools or APIs. +- Path resolution must strictly prevent directory traversal (`..`, null bytes, symlink escape). +- Large file summarization failure (e.g. LiteLLM timeout) must not abort indexing. +- Maintain test coverage across new services, tools, and endpoints. + +--- + +### Task 1: Database Schema Migration & Settings Configuration + +**Files:** +- Modify: `app/services/database/schema.py` +- Modify: `app/services/database/connection.py` +- Modify: `app/api/routers/settings.py` +- Test: `tests/test_file_settings.py` + +**Interfaces:** +- Produces: + - `ensure_file_summaries_columns(conn)` + - `get_file_settings() -> Dict[str, Any]` + - `set_file_settings(payload: Dict[str, Any])` + - Endpoints: `GET /admin/api/settings/files`, `POST /admin/api/settings/files` + +- [ ] **Step 1: Write the failing test for schema and file settings** +- [ ] **Step 2: Run pytest to verify test failure** +- [ ] **Step 3: Add `summary_text` column to schema and migration in `connection.py`** +- [ ] **Step 4: Implement `get_file_settings` and `set_file_settings` in `connection.py`** +- [ ] **Step 5: Add `GET/POST /admin/api/settings/files` in `settings.py`** +- [ ] **Step 6: Run tests and verify they pass** +- [ ] **Step 7: Commit changes** + +--- + +### Task 2: File Reader Service & MCP Tool (`read_file`) + +**Files:** +- Create: `app/services/file_reader.py` +- Create: `app/mcp/handlers/file_handlers.py` +- Modify: `app/mcp/tools.py` +- Create: `app/api/routers/files.py` +- Modify: `main.py` (include files router) +- Test: `tests/test_file_reader.py` + +**Interfaces:** +- Produces: + - `FileReaderService.read_file(path: str, repo: Optional[str] = None, start_line: Optional[int] = None, end_line: Optional[int] = None, max_lines: Optional[int] = None) -> Dict[str, Any]` + - `handle_read_file(...) -> str` + - `GET /admin/api/files/read` + +- [ ] **Step 1: Write unit tests for `FileReaderService` (path traversal, line slicing, binary check)** +- [ ] **Step 2: Run pytest to verify tests fail** +- [ ] **Step 3: Implement `FileReaderService` with path security and line slicing** +- [ ] **Step 4: Implement `handle_read_file` in `file_handlers.py` and register in `tools.py`** +- [ ] **Step 5: Create `app/api/routers/files.py` with `GET /admin/api/files/read`** +- [ ] **Step 6: Register files router in `main.py`** +- [ ] **Step 7: Run tests and verify they pass** +- [ ] **Step 8: Commit changes** + +--- + +### Task 3: Large File Summarizer Service & MCP Tool (`summarize_file`) + +**Files:** +- Create: `app/services/summarizer.py` +- Modify: `app/mcp/handlers/file_handlers.py` +- Modify: `app/mcp/tools.py` +- Modify: `app/api/routers/files.py` +- Test: `tests/test_summarizer.py` + +**Interfaces:** +- Produces: + - `SummarizerService.generate_file_summary(filepath: str, content: str, repo: str = "local") -> Tuple[str, VectorDocument]` + - `SummarizerService.get_or_create_summary(filepath: str, repo: Optional[str] = None, force_refresh: bool = False) -> str` + - `handle_summarize_file(...) -> str` + - `POST /admin/api/files/summarize` + +- [ ] **Step 1: Write unit tests for `SummarizerService` (mocking LiteLLM completion, caching, vector doc generation)** +- [ ] **Step 2: Run pytest to verify tests fail** +- [ ] **Step 3: Implement `SummarizerService` in `app/services/summarizer.py`** +- [ ] **Step 4: Implement `handle_summarize_file` in `file_handlers.py` and register in `tools.py`** +- [ ] **Step 5: Add `POST /admin/api/files/summarize` in `app/api/routers/files.py`** +- [ ] **Step 6: Run tests and verify they pass** +- [ ] **Step 7: Commit changes** + +--- + +### Task 4: Ingestion & Indexing Processor Integration + +**Files:** +- Modify: `app/services/indexing/processor.py` +- Modify: `app/services/local_storage.py` +- Test: `tests/test_processor_summarization.py` + +**Interfaces:** +- Consumes: `SummarizerService`, `get_file_settings()` +- Updates: `process_file_content` to auto-summarize files > threshold instead of skipping them + +- [ ] **Step 1: Write integration tests for `processor.py` with large file auto-summarization** +- [ ] **Step 2: Run pytest to verify test failure** +- [ ] **Step 3: Update `process_file_content` in `processor.py` to trigger `SummarizerService` when file exceeds `summary_threshold_kb`** +- [ ] **Step 4: Ensure vector points include the summary doc and SQLite `file_summaries` records `summary_text`** +- [ ] **Step 5: Run tests and verify they pass** +- [ ] **Step 6: Commit changes** + +--- + +### Task 5: Frontend Settings UI & Web Build + +**Files:** +- Create: `frontend/src/components/FileSettings.tsx` +- Modify: `frontend/src/Settings.tsx` +- Create: `frontend/src/tests/FileSettings.test.tsx` +- Build output: `www/` + +**Interfaces:** +- Consumes: `/admin/api/settings/files`, `/admin/api/litellm/models` +- Produces: UI inputs for `summary_enabled`, `summary_threshold_kb`, `summary_max_file_size_mb`, `read_file_max_lines`, `summary_chat_model` + +- [ ] **Step 1: Write frontend component test for `FileSettings.tsx`** +- [ ] **Step 2: Implement `FileSettings.tsx` and embed in `Settings.tsx`** +- [ ] **Step 3: Run Vitest frontend test suite** +- [ ] **Step 4: Rebuild frontend bundle (`npm run build`) into `www/`** +- [ ] **Step 5: Commit changes** + +--- + +### Task 6: Comprehensive Verification, Branch Push & PR Creation + +**Files:** +- Test: Entire test suite (`pytest`, `npm test`) +- Remote Git: Branch `feat/file-reading-and-large-file-summarization` -> Origin + +- [ ] **Step 1: Run full backend test suite (`pytest`)** +- [ ] **Step 2: Run full frontend test suite (`npm test -- --run`)** +- [ ] **Step 3: Verify git status and commit any remaining changes** +- [ ] **Step 4: Push branch to origin** +- [ ] **Step 5: Create Pull Request with `gh pr create`** diff --git a/docs/superpowers/specs/2026-09-18-file-reading-and-large-file-summarization-design.md b/docs/superpowers/specs/2026-09-18-file-reading-and-large-file-summarization-design.md new file mode 100644 index 0000000..b6ab1cc --- /dev/null +++ b/docs/superpowers/specs/2026-09-18-file-reading-and-large-file-summarization-design.md @@ -0,0 +1,154 @@ +# Design Specification: File Reading and Large File Summarization + +## 1. Overview & Goals +This feature provides two major capabilities for AI coding agents and human users in ContextCortex: +1. **Full & Sliced File Retrieval (`read_file`)**: An MCP tool and REST API enabling agents to read entire files or bounded line slices (`start_line` / `end_line`) across both monitored local directories (`indexed_paths`) and uploaded local storage files (`/data/storage`), with strict path traversal security. +2. **Large File Summarization Pipeline (`summarize_file`)**: An automated and on-demand LLM summarization system for files that exceed standard chunking thresholds (default: >500 KB). Large files are summarized using the configured LiteLLM chat model, cached in SQLite (`file_summaries.summary_text`), and embedded into the vector store so they remain discoverable via hybrid search rather than being silently omitted. +3. **Configurable Thresholds in UI**: File size thresholds, line retrieval limits, and chat model selections are fully customizable via the Settings UI and stored in SQLite metadata. + +--- + +## 2. Architecture & Components + +### 2.1 File Reader Service (`app/services/file_reader.py`) +- **Responsibilities**: + - Resolves target file paths safely against: + - Registered, enabled local paths from `indexed_paths`. + - Local storage directory (`LOCAL_STORAGE_PATH`, default `/data/storage`). + - Strict security validation: + - Rejects path traversal (`..`, null bytes, symlink breakout). + - Ensures path resolves strictly within an authorized root directory. + - Reads text files with fallback encoding (`utf-8`, `errors='replace'`). + - Detects binary content (e.g. null bytes in head sample) and rejects reading non-text files with an informative error. + - Line-range slicing: + - Supports optional `start_line` (1-based, inclusive) and `end_line` (inclusive). + - Enforces a configurable ceiling `max_lines` (default 2,000 lines). + - Returns structured payload: + ```python + { + "filepath": rel_or_abs_path, + "content": sliced_text, + "start_line": s_line, + "end_line": e_line, + "total_lines": total_lines, + "size_bytes": size_bytes, + "truncated": is_truncated, + "source": "indexed_path" | "local_storage" + } + ``` + +### 2.2 Summarizer Service (`app/services/summarizer.py`) +- **Responsibilities**: + - Interacts with LiteLLM gateway (`/v1/chat/completions`) using the active chat model configured in settings or environment (`LITELLM_URL`, `LITELLM_API_KEY`). + - Summarizes large documents and source code into structured markdown: + - High-level executive overview / purpose. + - Key exports, functions, classes, or sections. + - Architectural dependencies and data flow notes. + - Caches generated markdown summaries in SQLite `file_summaries.summary_text`. + - Embeds the generated summary text into the vector store (Qdrant / Chroma) as a `doc_type="summary"` document, tagged with repo, category, and original file path. + - Provides on-demand summary generation or retrieval via `get_or_create_summary(filepath, repo, force_refresh)`. + +### 2.3 Indexing Processor Integration (`app/services/indexing/processor.py`) +- **Integration**: + - In `process_file_content(...)`: + - Checks file size against `summary_threshold_kb` (default: 500 KB). + - If `summary_enabled` is true and file size exceeds threshold (up to `summary_max_file_size_mb`, default 10 MB): + - Triggers `SummarizerService.generate_file_summary(...)`. + - Adds the resulting summary vector document to `points` so it is indexed immediately alongside other vector points. + - Sets `summary_text` in the `summary_tuple` inserted into `file_summaries`. + - If file exceeds `summary_max_file_size_mb`, it logs a warning and skips embedding to protect memory. + +### 2.4 MCP Tools (`app/mcp/handlers/file_handlers.py` & `app/mcp/tools.py`) +1. **`read_file`**: + - Parameters: + - `path`: (str, required) Target file path (relative to repo/storage, or absolute path matching an indexed root). + - `repo`: (str, optional) Specific repository or storage namespace. + - `start_line`: (int, optional) 1-based start line. + - `end_line`: (int, optional) 1-based end line. + - Output: Formatted markdown block with header, line numbers, and file statistics. +2. **`summarize_file`**: + - Parameters: + - `path`: (str, required) Target file path. + - `repo`: (str, optional) Repository or storage namespace. + - `force_refresh`: (bool, optional, default False) Whether to regenerate the LLM summary even if a cached summary exists. + - Output: Markdown summary of the file. + +### 2.5 REST API Endpoints (`app/api/routers/files.py` & `app/api/routers/settings.py`) +- `GET /admin/api/files/read`: Query params `path`, `repo`, `start_line`, `end_line`. Returns JSON payload from `FileReaderService`. +- `POST /admin/api/files/summarize`: Body `{ "path": str, "repo": Optional[str], "force_refresh": bool }`. Returns JSON summary result. +- `GET /admin/api/settings/files`: Returns current configuration for thresholds and file reading. +- `POST /admin/api/settings/files`: Updates threshold configuration in SQLite metadata. + +### 2.6 Frontend Settings UI (`frontend/src/components/FileSettings.tsx` & `Settings.tsx`) +- New "Files & Summarization" card/tab under Settings: + - **Auto-Summarize Large Files**: Toggle switch (`summary_enabled`). + - **Large File Threshold (KB)**: Numeric input (default `500`). + - **Max File Size for Summarization (MB)**: Numeric input (default `10`). + - **Max Lines Per Read**: Numeric input (default `2000`). + - **Summarization Chat Model**: Dropdown of models discovered from LiteLLM + write-in override. + +--- + +## 3. Database Schema Changes + +### 3.1 Migration in SQLite (`app/services/database/schema.py` & `connection.py`) +Add `summary_text` column to `file_summaries` table: +```sql +ALTER TABLE file_summaries ADD COLUMN summary_text TEXT; +``` +For migration compatibility on startup: +```python +def ensure_file_summaries_columns(conn): + cursor = conn.cursor() + columns = [row[1] for row in cursor.execute("PRAGMA table_info(file_summaries)").fetchall()] + if "summary_text" not in columns: + cursor.execute("ALTER TABLE file_summaries ADD COLUMN summary_text TEXT") + conn.commit() +``` + +### 3.2 Settings Metadata Keys +- `file_summary_enabled`: `"1"` or `"0"` (default `"1"`) +- `file_summary_threshold_kb`: integer as string, e.g. `"500"` +- `file_summary_max_size_mb`: integer as string, e.g. `"10"` +- `file_read_max_lines`: integer as string, e.g. `"2000"` +- `file_summary_model`: model identifier string (defaults to `chat_model` or `gpt-4o-mini`) + +--- + +## 4. Security & Error Handling + +1. **Path Traversal Protection**: + All paths passed to `FileReaderService` are canonicalized (`os.path.realpath`) and verified against authorized roots: + ```python + target = os.path.realpath(resolved_path) + if not any(target.startswith(root) for root in authorized_roots): + raise ForbiddenError("Path traversal or unauthorized directory access attempt.") + ``` +2. **Binary File Protection**: + The service inspects the first 1,024 bytes for null bytes `\x00`. If detected, file reading returns a `400 Bad Request` or an explicit MCP warning. +3. **LiteLLM Failure Resilience**: + If LiteLLM is unreachable or times out during indexing: + - File indexing does not abort or fail the sync job. + - An error is logged, `summary_text` is left null, and indexing completes normally. + - Users or agents can re-request summarization on-demand once LiteLLM is accessible. +4. **Token & Line Bounds**: + If a client requests lines beyond `read_file_max_lines`, output is automatically truncated at the limit with `truncated: true` and an explanatory header. + +--- + +## 5. Testing Strategy +1. **Unit Tests (`tests/test_file_reader.py`)**: + - Safe path resolution within watched paths and local storage. + - Path traversal attempts (`../../etc/passwd`, absolute paths outside roots) are blocked. + - Line slicing (`start_line`, `end_line`, `max_lines` capping, bounds checking). + - Binary file rejection. +2. **Unit Tests (`tests/test_summarizer.py`)**: + - Prompt construction and mock LiteLLM completion calls. + - Summary caching into SQLite and vector store payload formatting. + - `force_refresh` behavior. +3. **Integration Tests (`tests/test_file_mcp_tools.py`)**: + - FastMCP tool registration for `read_file` and `summarize_file`. + - Tool execution with various parameters and permission validation. +4. **Frontend Settings Tests (`frontend/src/tests/FileSettings.test.tsx`)**: + - Loading threshold settings from `/admin/api/settings/files`. + - Updating and submitting threshold values. diff --git a/frontend/dist/assets/index-B-sgo2Eo.js b/frontend/dist/assets/index-B-sgo2Eo.js deleted file mode 100644 index d2d8796..0000000 --- a/frontend/dist/assets/index-B-sgo2Eo.js +++ /dev/null @@ -1,10 +0,0 @@ -var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,o)=>(o=n==null?{}:e(i(n)),s(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function E(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function D(e,t){return E(e.type,t,e.props)}function O(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function k(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ee=/\/+/g;function A(e,t){return typeof e==`object`&&e&&e.key!=null?k(``+e.key):t.toString(36)}function te(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ne(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ne(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+A(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(ee,`$&/`)+`/`),ne(o,r,i,``,function(e){return e})):o!=null&&(O(o)&&(o=D(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ee,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=l()})),d=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m){if(n(c)!==null)m=!0,S||(S=!0,O());else{var t=n(l);t!==null&&A(x,t.startTime-e)}}}var S=!1,C=-1,w=5,T=-1;function E(){return g?!0:!(e.unstable_now()-Tt&&E());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&A(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}}}finally{i?O():S=!1}}}var O;if(typeof y==`function`)O=function(){y(D)};else if(typeof MessageChannel<`u`){var k=new MessageChannel,ee=k.port2;k.port1.onmessage=D,O=function(){ee.postMessage(null)}}else O=function(){_(D,0)};function A(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,A(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,O()))),r},e.unstable_shouldYield=E,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),f=o(((e,t)=>{t.exports=d()})),p=o((e=>{var t=u();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=p()})),h=o((e=>{var t=f(),n=u(),r=m();function i(e){var t=`https://react.dev/errors/`+e;if(1oe||(e.current=ae[oe],ae[oe]=null,oe--)}function F(e,t){oe++,ae[oe]=e.current,e.current=t}var ce=se(null),le=se(null),ue=se(null),de=se(null);function fe(e,t){switch(F(ue,t),F(le,e),F(ce,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}P(ce),F(ce,e)}function pe(){P(ce),P(le),P(ue)}function me(e){e.memoizedState!==null&&F(de,e);var t=ce.current,n=Hd(t,e.type);t!==n&&(F(le,e),F(ce,n))}function he(e){le.current===e&&(P(ce),P(le)),de.current===e&&(P(de),Qf._currentValue=N)}var ge,_e;function ve(e){if(ge===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);ge=t&&t[1]||``,_e=-1)`:-1i||c[r]!==l[i]){var u=` -`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{ye=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?ve(n):``}function xe(e,t){switch(e.tag){case 26:case 27:case 5:return ve(e.type);case 16:return ve(`Lazy`);case 13:return e.child!==t&&t!==null?ve(`Suspense Fallback`):ve(`Suspense`);case 19:return ve(`SuspenseList`);case 0:case 15:return be(e.type,!1);case 11:return be(e.type.render,!1);case 1:return be(e.type,!0);case 31:return ve(`Activity`);default:return``}}function Se(e){try{var t=``,n=null;do t+=xe(e,n),n=e,e=e.return;while(e);return t}catch(e){return` -Error generating stack: `+e.message+` -`+e.stack}}var Ce=Object.prototype.hasOwnProperty,we=t.unstable_scheduleCallback,Te=t.unstable_cancelCallback,Ee=t.unstable_shouldYield,De=t.unstable_requestPaint,Oe=t.unstable_now,ke=t.unstable_getCurrentPriorityLevel,Ae=t.unstable_ImmediatePriority,je=t.unstable_UserBlockingPriority,Me=t.unstable_NormalPriority,Ne=t.unstable_LowPriority,Pe=t.unstable_IdlePriority,Fe=t.log,Ie=t.unstable_setDisableYieldValue,Le=null,Re=null;function ze(e){if(typeof Fe==`function`&&Ie(e),Re&&typeof Re.setStrictMode==`function`)try{Re.setStrictMode(Le,e)}catch{}}var Be=Math.clz32?Math.clz32:Ue,Ve=Math.log,He=Math.LN2;function Ue(e){return e>>>=0,e===0?32:31-(Ve(e)/He|0)|0}var We=256,Ge=262144,Ke=4194304;function qe(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Je(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=qe(n))):i=qe(o):i=qe(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=qe(n))):i=qe(o)):i=qe(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Ye(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Xe(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Ze(){var e=Ke;return Ke<<=1,!(Ke&62914560)&&(Ke=4194304),e}function Qe(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function $e(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function et(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),fn=!1;if(dn)try{var pn={};Object.defineProperty(pn,"passive",{get:function(){fn=!0}}),window.addEventListener(`test`,pn,pn),window.removeEventListener(`test`,pn,pn)}catch{fn=!1}var mn=null,hn=null,gn=null;function _n(){if(gn)return gn;var e,t=hn,n=t.length,r,i=`value`in mn?mn.value:mn.textContent,a=i.length;for(e=0;e=Yn),Qn=` `,$n=!1;function er(e,t){switch(e){case`keyup`:return qn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function tr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var nr=!1;function rr(e,t){switch(e){case`compositionend`:return tr(t);case`keypress`:return t.which===32?($n=!0,Qn):null;case`textInput`:return e=t.data,e===Qn&&$n?null:e;default:return null}}function ir(e,t){if(nr)return e===`compositionend`||!Jn&&er(e,t)?(e=_n(),gn=hn=mn=null,nr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Er(n)}}function Or(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Or(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function kr(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Rt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Rt(e.document)}return t}function Ar(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var jr=dn&&`documentMode`in document&&11>=document.documentMode,Mr=null,Nr=null,Pr=null,Fr=!1;function Ir(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Fr||Mr==null||Mr!==Rt(r)||(r=Mr,`selectionStart`in r&&Ar(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Pr&&Tr(Pr,r)||(Pr=r,r=Ed(Nr,`onSelect`),0>=o,i-=o,Oi=1<<32-Be(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),R&&Ai(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),R&&Ai(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return R&&Ai(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),R&&Ai(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===O&&ka(l)===r.type){n(e,r.sibling),c=a(r,o.props),Ia(c,o),c.return=e,e=c;break a}n(e,r);break}t(e,r),r=r.sibling}o.type===y?(c=hi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=mi(o.type,o.key,o.props,null,e.mode,c),Ia(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l){if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}n(e,r);break}t(e,r),r=r.sibling}c=vi(o,e.mode,c),c.return=e,e=c}return s(e);case O:return o=ka(o),b(e,r,o,c)}if(ie(o))return h(e,r,o,c);if(te(o)){if(l=te(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Fa(o),c);if(o.$$typeof===C)return b(e,r,ra(e,o),c);La(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=gi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Pa=0;var i=b(e,t,n,r);return Na=null,i}catch(t){if(t===Ca||t===Ta)throw t;var a=ui(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var za=Ra(!0),Ba=Ra(!1),Va=!1;function Ha(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ua(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Wa(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Ga(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,G&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=si(e),oi(e,null,n),t}return ri(e,r,t,n),si(e)}function Ka(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,nt(e,n)}}function qa(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var Ja=!1;function Ya(){if(Ja){var e=ma;if(e!==null)throw e}}function Xa(e,t,n,r){Ja=!1;var i=e.updateQueue;Va=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(J&f)===f:(r&f)===f){f!==0&&f===pa&&(Ja=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var m=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(m=g.payload,typeof m==`function`){d=m.call(_,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=g.payload,f=typeof m==`function`?m.call(_,d,f):m,f==null)break a;d=h({},d,f);break a;case 2:Va=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Gl|=o,e.lanes=o,e.memoizedState=d}}function Za(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function Qa(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=j.T,s={};j.T=s,Fs(e,!1,t,n);try{var c=i(),l=j.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Ps(e,t,_a(c,r),pu(e)):Ps(e,t,r,pu(e))}catch(n){Ps(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{M.p=a,o!==null&&s.types!==null&&(o.types=s.types),j.T=o}}function ws(){}function Ts(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Es(e).queue;Cs(e,a,t,N,n===null?ws:function(){return Ds(e),n(r)})}function Es(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:N,baseState:N,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Io,lastRenderedState:N},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Io,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Ds(e){var t=Es(e);t.next===null&&(t=e.alternate.memoizedState),Ps(e,t.next.queue,{},pu())}function Os(){return na(Qf)}function ks(){return jo().memoizedState}function As(){return jo().memoizedState}function js(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Wa(n);var r=Ga(t,e,n);r!==null&&(hu(r,t,n),Ka(r,t,n)),t={cache:la()},e.payload=t;return}t=t.return}}function Ms(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Is(e)?Ls(t,n):(n=ii(e,t,n,r),n!==null&&(hu(n,e,r),Rs(n,t,r)))}function Ns(e,t,n){Ps(e,t,n,pu())}function Ps(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Is(e))Ls(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,wr(s,o))return ri(e,t,i,0),K===null&&ni(),!1}catch{}if(n=ii(e,t,i,r),n!==null)return hu(n,e,r),Rs(n,t,r),!0}return!1}function Fs(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Is(e)){if(t)throw Error(i(479))}else t=ii(e,n,r,2),t!==null&&hu(t,e,2)}function Is(e){var t=e.alternate;return e===B||t!==null&&t===B}function Ls(e,t){go=ho=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Rs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,nt(e,n)}}var zs={readContext:na,use:Po,useCallback:H,useContext:H,useEffect:H,useImperativeHandle:H,useLayoutEffect:H,useInsertionEffect:H,useMemo:H,useReducer:H,useRef:H,useState:H,useDebugValue:H,useDeferredValue:H,useTransition:H,useSyncExternalStore:H,useId:H,useHostTransitionStatus:H,useFormState:H,useActionState:H,useOptimistic:H,useMemoCache:H,useCacheRefresh:H};zs.useEffectEvent=H;var Bs={readContext:na,use:Po,useCallback:function(e,t){return Ao().memoizedState=[e,t===void 0?null:t],e},useContext:na,useEffect:us,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),cs(4194308,4,gs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return cs(4194308,4,e,t)},useInsertionEffect:function(e,t){cs(4,2,e,t)},useMemo:function(e,t){var n=Ao();t=t===void 0?null:t;var r=e();if(_o){ze(!0);try{e()}finally{ze(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Ao();if(n!==void 0){var i=n(t);if(_o){ze(!0);try{n(t)}finally{ze(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ms.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var t=Ao();return e={current:e},t.memoizedState=e},useState:function(e){e=Ko(e);var t=e.queue,n=Ns.bind(null,B,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:vs,useDeferredValue:function(e,t){return xs(Ao(),e,t)},useTransition:function(){var e=Ko(!1);return e=Cs.bind(null,B,e.queue,!0,!1),Ao().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=B,a=Ao();if(R){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),K===null)throw Error(i(349));J&127||Vo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,us(Uo.bind(null,r,o,e),[e]),r.flags|=2048,os(9,{destroy:void 0},Ho.bind(null,r,o,n,t),null),n},useId:function(){var e=Ao(),t=K.identifierPrefix;if(R){var n=ki,r=Oi;n=(r&~(1<<32-Be(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=vo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[ct]=t,o[lt]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Pc(t)}}return U(t),Fc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Pc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ue.current,Hi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Fi,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[ct]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||zi(t,!0)}else e=Bd(e).createTextNode(r),e[ct]=t,t.stateNode=e}return U(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Hi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[ct]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),e=!1}else n=Wi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(uo(t),t):(uo(t),null);if(t.flags&128)throw Error(i(558))}return U(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Hi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[ct]=t}else Ui(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),a=!1}else a=Wi(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(uo(t),t):(uo(t),null)}return uo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Lc(t,t.updateQueue),U(t),null);case 4:return pe(),e===null&&Sd(t.stateNode.containerInfo),U(t),null;case 10:return Xi(t.type),U(t),null;case 19:if(P(z),r=t.memoizedState,r===null)return U(t),null;if(a=!!(t.flags&128),o=r.rendering,o===null){if(a)Rc(r,!1);else{if(X!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=fo(e),o!==null){for(t.flags|=128,Rc(r,!1),e=o.updateQueue,t.updateQueue=e,Lc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)pi(n,e),n=n.sibling;return F(z,z.current&1|2),R&&Ai(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&Oe()>tu&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304)}}else{if(!a){if(e=fo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Lc(t,e),Rc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!R)return U(t),null}else 2*Oe()-r.renderingStartTime>tu&&n!==536870912&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304)}r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(U(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=Oe(),e.sibling=null,n=z.current,F(z,a?n&1|2:n&1),R&&Ai(t,r.treeForkCount),e);case 22:case 23:return uo(t),ro(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(U(t),t.subtreeFlags&6&&(t.flags|=8192)):U(t),n=t.updateQueue,n!==null&&Lc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&P(ya),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Xi(ca),U(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Ni(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Xi(ca),pe(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return he(t),null;case 31:if(t.memoizedState!==null){if(uo(t),t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(uo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Ui()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return P(z),null;case 4:return pe(),null;case 10:return Xi(t.type),null;case 22:case 23:return uo(t),ro(),e!==null&&P(ya),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Xi(ca),null;case 25:return null;default:return null}}function Vc(e,t){switch(Ni(t),t.tag){case 3:Xi(ca),pe();break;case 26:case 27:case 5:he(t);break;case 4:pe();break;case 31:t.memoizedState!==null&&uo(t);break;case 13:uo(t);break;case 19:P(z);break;case 10:Xi(t.type);break;case 22:case 23:uo(t),ro(),e!==null&&P(ya);break;case 24:Xi(ca)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Qa(t,n)}catch(t){Z(e,e.return,t)}}}function Gc(e,t,n){n.props=qs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null){if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[lt]=t}catch(t){Z(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=tn));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[ct]=e,t[lt]=n}catch(t){Z(e,e.return,t)}}var tl=!1,nl=!1,rl=!1,il=typeof WeakSet==`function`?WeakSet:Set,al=null;function ol(e,t){if(e=e.containerInfo,Rd=sp,e=kr(e),Ar(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,al=t;al!==null;)if(t=al,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,al=e;else for(;al!==null;){switch(t=al,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[ct]=e,xt(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Dr(s,h),v=Dr(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,j.T=null,n=lu,lu=null;var o=au,s=su;if(iu=0,ou=au=null,su=0,G&6)throw Error(i(331));var c=G;if(G|=4,Fl(o.current),Dl(o,o.current,s,n),G=c,id(0,!1),Re&&typeof Re.onPostCommitFiberRoot==`function`)try{Re.onPostCommitFiberRoot(Le,o)}catch{}return!0}finally{M.p=a,j.T=r,Vu(e,t)}}function Wu(e,t,n){t=bi(n,t),t=$s(e.stateNode,t,2),e=Ga(e,t,2),e!==null&&($e(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(ru===null||!ru.has(r))){e=bi(n,e),n=ec(2),r=Ga(t,n,2),r!==null&&(tc(n,r,t,e),$e(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new zl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Ul=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,K===e&&(J&n)===n&&(X===4||X===3&&(J&62914560)===J&&300>Oe()-$l?!(G&2)&&Su(e,0):ql|=n,Yl===J&&(Yl=0)),rd(e)}function qu(e,t){t===0&&(t=Ze()),e=ai(e,t),e!==null&&($e(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return we(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t){if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-Be(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=J,a=Je(r,r===K?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Ye(r,a)||(n=!0,ld(r,a))}r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=Oe(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}iu!==0&&iu!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=Bt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),xt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+Bt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+Bt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+Bt(n.imageSizes)+`"]`)):i+=`[href="`+Bt(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=h({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),xt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+Bt(r)+`"][href="`+Bt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=h({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),xt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=bt(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=h({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);xt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=bt(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),xt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=bt(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),xt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=ue.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=bt(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=bt(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=bt(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+Bt(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return h({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),xt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+Bt(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+Bt(n.href)+`"]`);if(r)return t.instance=r,xt(r),r;var a=h({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),xt(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,xt(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),xt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,xt(a),a):(r=n,(a=mf.get(o))&&(r=h({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),xt(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,xt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),xt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=h()})),_=c(u(),1),v=g(),y=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),b=o(((e,t)=>{t.exports=y()}))(),x=(0,_.createContext)(void 0);function S(){let e=(0,_.useContext)(x);if(!e)throw Error(`useToast must be used within a ToastProvider`);return e.toast}var C=0;function w({children:e}){let[t,n]=(0,_.useState)([]),r=(0,_.useState)(()=>new Map)[0];(0,_.useEffect)(()=>()=>{r.forEach(e=>clearTimeout(e)),r.clear()},[r]);let i=(0,_.useCallback)(e=>{let t=r.get(e);t&&(clearTimeout(t),r.delete(e)),n(t=>t.filter(t=>t.id!==e))},[r]),a=(0,_.useCallback)((e,t=`info`)=>{let i=++C;n(n=>[...n,{id:i,message:e,type:t}]);let a=setTimeout(()=>{r.delete(i),n(e=>e.filter(e=>e.id!==i))},4e3);r.set(i,a)},[r]),o=(0,_.useMemo)(()=>({success:e=>a(e,`success`),error:e=>a(e,`error`),info:e=>a(e,`info`),warning:e=>a(e,`warning`),showToast:(e,t)=>a(e,t||`info`),dismiss:i}),[a,i]);return(0,b.jsxs)(x.Provider,{value:{toast:o},children:[e,(0,b.jsx)(`div`,{className:`toast-container`,"aria-live":`polite`,"aria-atomic":`true`,children:t.map(e=>(0,b.jsxs)(`div`,{className:`toast toast-${e.type}`,role:`status`,children:[e.type===`error`&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`,"aria-hidden":`true`}),e.type===`success`&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`,"aria-hidden":`true`}),e.type===`info`&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-info`,"aria-hidden":`true`}),e.type===`warning`&&(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,"aria-hidden":`true`}),(0,b.jsx)(`span`,{className:`toast-message`,children:e.message}),(0,b.jsx)(`button`,{type:`button`,className:`toast-dismiss-btn`,onClick:()=>i(e.id),"aria-label":`Dismiss notification`,title:`Dismiss`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-xmark`,"aria-hidden":`true`})})]},e.id))})]})}function T({stats:e,refreshStats:t}){let n=S();return e?(0,b.jsxs)(`div`,{className:`tab-content active`,children:[(0,b.jsxs)(`div`,{className:`overview-grid`,children:[(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-brands fa-github`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.repos_count??e.git_repos??0).toLocaleString()}),(0,b.jsx)(`span`,{className:`stat-label`,children:`Git Repositories`})]})]}),(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-code`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.symbols_count||0).toLocaleString()}),(0,b.jsx)(`span`,{className:`stat-label`,children:`AST Code Symbols`})]})]}),(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.files_count||0).toLocaleString()}),(0,b.jsx)(`span`,{className:`stat-label`,children:`Indexed Files`})]})]}),(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-network-wired`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.points_count||0).toLocaleString()}),(0,b.jsxs)(`span`,{className:`stat-label`,children:[(e.vector_store_provider||`Qdrant`).toUpperCase(),` (`,(e.vector_store_mode||`embedded`)===`embedded`?`Embedded`:`Remote`,`) Vectors`]})]})]})]}),(0,b.jsxs)(`div`,{className:`two-col-layout`,style:{marginTop:`20px`},children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-server`}),` System & Embedding Specs`]}),(0,b.jsxs)(`div`,{className:`specs-list`,children:[(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Vector Database:`}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,b.jsxs)(`span`,{className:`badge badge-accent`,children:[e.vector_store_provider===`chroma`?`ChromaDB`:`Qdrant`,` (`,(e.vector_store_mode||`embedded`)===`embedded`?`Embedded Disk`:`Remote Server`,`)`]}),e.vector_db_status&&(0,b.jsx)(`span`,{className:`badge ${e.vector_db_status===`Healthy`?`badge-success`:`badge-danger`}`,"data-testid":`overview-vector-db-status`,children:e.vector_db_status})]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Dense Embedding Model:`}),(0,b.jsx)(`code`,{children:e.dense_model||`bge-small-en-v1.5 (384d)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Sparse BM25 Model:`}),(0,b.jsx)(`code`,{children:e.sparse_model?`${e.sparse_model} (FastEmbed)`:`Qdrant/bm25 (FastEmbed)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Retrieval Strategy:`}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.vector_store_provider===`chroma`?`Dense Vector Cosine Similarity`:`Dense + BM25 Normalized Weighted Fusion`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`AST Chunker:`}),(0,b.jsx)(`span`,{children:`Tree-sitter AST (Classes, Functions, Methods)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Last Global Index:`}),(0,b.jsx)(`span`,{className:`code`,children:e.last_indexed||`Never`})]})]}),(0,b.jsx)(`div`,{style:{marginTop:`20px`},children:(0,b.jsx)(`button`,{className:`btn btn-primary`,onClick:async()=>{try{let e=await fetch(`/admin/api/reindex`,{method:`POST`});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error||`Failed to trigger reindex`)}n.success(`Re-indexing triggered successfully`),t()}catch(e){n.error(`Reindex error: `+e.message)}},disabled:e.is_indexing,children:e.is_indexing?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Syncing...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Reindex All Sources`]})})})]}),(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-tags`}),` Top Extracted Topics & Symbols`]}),(0,b.jsx)(`div`,{className:`tag-cloud`,children:!e.top_keywords||e.top_keywords.length===0?(0,b.jsx)(`span`,{className:`text-muted`,children:`No topics extracted yet. Sync repositories to populate.`}):e.top_keywords.map(e=>(0,b.jsx)(`span`,{className:`topic-tag`,children:e},e))})]})]})]}):(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsx)(`p`,{children:`Loading...`})})}function E({isOpen:e,onClose:t,onSave:n,alias:r,setAlias:i,url:a,setUrl:o,branch:s,setBranch:c,provider:l,setProvider:u,authUser:d,setAuthUser:f,token:p,setToken:m,isSaving:h}){return e?(0,b.jsx)(`div`,{className:`modal-backdrop`,onClick:e=>{e.target===e.currentTarget&&t()},children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`}),` Register Git Repository`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:t,children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:n,children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-alias`,children:`Repository Alias / Identifier`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-alias`,required:!0,placeholder:`e.g. backend-api or contextcortex`,value:r,onChange:e=>i(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-provider`,children:`Git Provider`}),(0,b.jsxs)(`select`,{id:`repo-provider`,value:l,onChange:e=>u(e.target.value),children:[(0,b.jsx)(`option`,{value:`auto`,children:`Auto-Detect`}),(0,b.jsx)(`option`,{value:`github`,children:`GitHub / GitHub Enterprise`}),(0,b.jsx)(`option`,{value:`gitlab`,children:`GitLab (Cloud / Self-Hosted)`}),(0,b.jsx)(`option`,{value:`gitea`,children:`Gitea / Forgejo`}),(0,b.jsx)(`option`,{value:`bitbucket`,children:`Bitbucket`}),(0,b.jsx)(`option`,{value:`generic`,children:`Generic Git (HTTP / HTTPS)`})]})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-url`,children:`Git Clone URL (HTTP / HTTPS)`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-url`,required:!0,placeholder:`https://github.com/owner/repo.git or http://git.lan:3000/repo.git`,value:a,onChange:e=>o(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-row form-row-3col`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-branch`,children:`Branch / Tag`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-branch`,placeholder:`main`,value:s,onChange:e=>c(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-user`,children:`Auth User (Optional)`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-user`,placeholder:`e.g. oauth2`,value:d,onChange:e=>f(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-token`,children:`Auth Token (Optional)`}),(0,b.jsx)(`input`,{type:`password`,id:`repo-token`,placeholder:`Token override`,value:p,onChange:e=>m(e.target.value)})]})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:t,children:`Cancel`}),(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:h,children:h?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Adding & Syncing...`]}):`Add & Start Sync`})]})]})]})}):null}function D({repo:e,onClose:t,onCopyUrl:n,copiedUrl:r}){if(!e)return null;let i=`${typeof window<`u`?window.location.origin:``}/api/webhooks/git`;return(0,b.jsx)(`div`,{className:`modal-backdrop`,onClick:e=>{e.target===e.currentTarget&&t()},"data-testid":`webhook-modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`650px`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Webhook Setup: `,e.name]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:t,"aria-label":`Close webhook modal`,children:`×`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`16px`,fontSize:`0.9rem`},children:[(0,b.jsx)(`p`,{className:`text-muted`,children:`Configure a webhook in your Git repository provider to automatically trigger synchronization on every push event.`}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Webhook URL (Payload URL)`}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`input`,{type:`text`,readOnly:!0,value:i,style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`},"aria-label":`Webhook Payload URL`}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>n(i),style:{minWidth:`95px`},"aria-label":`Copy Webhook URL`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${r?`fa-check`:`fa-copy`}`}),` `,r?`Copied!`:`Copy`]})]})]}),e.webhook_secret&&(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Repository Secret Token (HMAC)`}),(0,b.jsx)(`input`,{type:`text`,readOnly:!0,value:e.webhook_secret,style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`},"aria-label":`Repository Secret Token`})]}),(0,b.jsxs)(`div`,{style:{background:`rgba(0, 0, 0, 0.25)`,border:`1px solid var(--border-card)`,borderRadius:`8px`,padding:`14px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`0.95rem`,marginBottom:`10px`,color:`var(--text)`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-list-check`}),` Provider Setup Instructions`]}),(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`10px`,fontSize:`0.85rem`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`strong`,{style:{color:`#fff`},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`,style:{marginRight:`6px`}}),` GitHub:`]}),(0,b.jsxs)(`div`,{style:{color:`var(--text-muted)`,marginTop:`2px`,marginLeft:`18px`},children:[`Navigate to `,(0,b.jsx)(`code`,{children:`Settings > Webhooks > Add webhook`}),` → set `,(0,b.jsx)(`em`,{children:`Payload URL`}),` to the URL above → set `,(0,b.jsx)(`em`,{children:`Content type`}),` to `,(0,b.jsx)(`code`,{children:`application/json`}),` → select `,(0,b.jsx)(`em`,{children:`Push events`}),` → click `,(0,b.jsx)(`strong`,{children:`Add webhook`}),`.`]})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`strong`,{style:{color:`#fff`},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-gitlab`,style:{color:`#fc6d26`,marginRight:`6px`}}),` GitLab:`]}),(0,b.jsxs)(`div`,{style:{color:`var(--text-muted)`,marginTop:`2px`,marginLeft:`18px`},children:[`Navigate to `,(0,b.jsx)(`code`,{children:`Settings > Webhooks`}),` (or `,(0,b.jsx)(`code`,{children:`Settings > Integrations`}),`) → set `,(0,b.jsx)(`em`,{children:`URL`}),` → select `,(0,b.jsx)(`em`,{children:`Push events`}),` → click `,(0,b.jsx)(`strong`,{children:`Add webhook`}),`.`]})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`strong`,{style:{color:`#fff`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-mug-hot`,style:{color:`#609926`,marginRight:`6px`}}),` Gitea / Forgejo:`]}),(0,b.jsxs)(`div`,{style:{color:`var(--text-muted)`,marginTop:`2px`,marginLeft:`18px`},children:[`Navigate to `,(0,b.jsx)(`code`,{children:`Settings > Webhooks > Add Webhook > Gitea`}),` → set `,(0,b.jsx)(`em`,{children:`Target URL`}),` → set `,(0,b.jsx)(`em`,{children:`HTTP Method`}),` to `,(0,b.jsx)(`code`,{children:`POST`}),` → select `,(0,b.jsx)(`em`,{children:`Push Events`}),` → click `,(0,b.jsx)(`strong`,{children:`Add Webhook`}),`.`]})]})]})]}),(0,b.jsx)(`div`,{className:`modal-footer`,style:{marginTop:`8px`,padding:0},children:(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:t,children:`Close`})})]})]})})}function O({repos:e,isLoading:t,syncStates:n,onSync:r,onToggleAutoSync:i,onOpenWebhook:a,onDelete:o,onOpenSyncDrawer:s}){let c=e=>{let t=(e||`github`).toLowerCase();return t===`gitlab`?(0,b.jsx)(`i`,{className:`fa-brands fa-gitlab`,style:{color:`#fc6d26`,marginRight:`6px`},title:`GitLab`}):t===`gitea`||t===`forgejo`?(0,b.jsx)(`i`,{className:`fa-solid fa-mug-hot`,style:{color:`#609926`,marginRight:`6px`},title:`Gitea / Forgejo`}):t===`bitbucket`?(0,b.jsx)(`i`,{className:`fa-brands fa-bitbucket`,style:{color:`#2684ff`,marginRight:`6px`},title:`Bitbucket`}):t===`generic`?(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`,style:{color:`var(--accent)`,marginRight:`6px`},title:`Generic Git`}):(0,b.jsx)(`i`,{className:`fa-brands fa-github`,style:{marginRight:`6px`},title:`GitHub`})},l=(e,t)=>{let n=t?.step||1,r=t?.total_steps||5,i=t?.step_name||`Syncing...`,a=t?.percent??0,o=t?.current_file;return(0,b.jsxs)(`div`,{className:`sync-progress-container`,onClick:()=>s?.(e.id),role:`button`,tabIndex:0,style:{cursor:`pointer`},title:`Click to view live ingestion progress & logs`,onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&s?.(e.id)},children:[(0,b.jsxs)(`div`,{className:`progress-pill badge badge-warning`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),(0,b.jsxs)(`span`,{children:[`Step `,n,`/`,r,`: `,i,` (`,a,`%)`]})]}),(0,b.jsx)(`div`,{className:`sync-progress-bar-wrapper`,children:(0,b.jsx)(`div`,{className:`sync-progress-bar-fill fill-active`,style:{width:`${a}%`}})}),o&&(0,b.jsxs)(`div`,{className:`sync-file-caption`,title:o,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{marginRight:`4px`}}),(0,b.jsx)(`code`,{children:o})]})]})};return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Repo Alias`}),(0,b.jsx)(`th`,{children:`Git URL`}),(0,b.jsx)(`th`,{children:`Branch`}),(0,b.jsx)(`th`,{children:`Commit SHA`}),(0,b.jsx)(`th`,{children:`Status`}),(0,b.jsx)(`th`,{children:`Auto-Sync`}),(0,b.jsx)(`th`,{children:`Files`}),(0,b.jsx)(`th`,{children:`Last Synced`}),(0,b.jsx)(`th`,{children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:t&&e.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsxs)(`td`,{colSpan:9,className:`empty-state`,"data-testid":`repo-loading-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading repositories...`]})}):e.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:9,className:`empty-state`,children:`No Git repositories registered. Click "Add Repository" to index a remote repo.`})}):e.map(e=>{let t=e.auto_sync!==!1&&e.auto_sync!==0,u=n?.[e.id],d=e.status===`syncing`||u?.status===`syncing`;return(0,b.jsxs)(`tr`,{children:[(0,b.jsxs)(`td`,{children:[c(e.provider),(0,b.jsx)(`strong`,{children:e.name})]}),(0,b.jsx)(`td`,{children:(0,b.jsxs)(`a`,{href:e.url,target:`_blank`,rel:`noreferrer`,className:`repo-url-link`,style:{color:`var(--primary)`,textDecoration:`none`,fontSize:`0.85rem`},title:e.url,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrow-up-right-from-square`}),` `,e.url]})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.branch})}),(0,b.jsx)(`td`,{children:e.commit_sha?(0,b.jsx)(`code`,{children:e.commit_sha.substring(0,8)}):(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:d?l(e,u):e.status===`error`||u?.status===`error`?(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`span`,{className:`badge badge-danger`,title:e.last_error||u?.error||`Sync failed`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`}),` Error`]}),(e.last_error||u?.error)&&(0,b.jsx)(`div`,{style:{fontSize:`0.75rem`,color:`var(--danger)`,marginTop:`4px`,maxWidth:`180px`,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},title:e.last_error||u?.error||``,children:e.last_error||u?.error})]}):e.status===`pending`||u?.status===`pending`?(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock`}),` Pending`]}):(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`}),` Synced`]})}),(0,b.jsx)(`td`,{children:(0,b.jsxs)(`button`,{type:`button`,className:`badge ${t?`badge-success`:`badge-danger`}`,style:{cursor:`pointer`,background:t?`rgba(16, 185, 129, 0.2)`:`rgba(239, 68, 68, 0.2)`,border:t?`1px solid rgba(16, 185, 129, 0.4)`:`1px solid rgba(239, 68, 68, 0.4)`,color:t?`#6ee7b7`:`#fca5a5`,padding:`4px 8px`,display:`inline-flex`,alignItems:`center`,gap:`6px`},onClick:()=>i(e.id,t),title:`Auto-Sync: ${t?`ON`:`OFF`} (Click to toggle)`,"aria-label":`Toggle auto-sync for ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${t?`fa-toggle-on`:`fa-toggle-off`}`}),`Auto-Sync: `,t?`ON`:`OFF`]})}),(0,b.jsxs)(`td`,{children:[(e.file_count||0).toLocaleString(),` files`]}),(0,b.jsx)(`td`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`},children:e.last_synced||`Never`}),(0,b.jsx)(`td`,{children:(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`6px`},children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 8px`,fontSize:`0.8rem`},onClick:()=>s?.(e.id),title:`View Ingestion Logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Logs`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 8px`,fontSize:`0.8rem`},onClick:()=>r(e.id),title:`Trigger Sync`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Sync`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 8px`,fontSize:`0.8rem`},onClick:()=>a(e),title:`Webhook Setup`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Webhook`]}),(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>o(e.id,e.name),title:`Delete Repo`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})]})})]},e.id)})})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:t&&e.length===0?(0,b.jsxs)(`div`,{className:`empty-state`,"data-testid":`repo-loading-state-mobile`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading repositories...`]}):e.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No Git repositories registered. Click "Add Repository" to index a remote repo.`}):e.map(e=>{let t=e.auto_sync!==!1&&e.auto_sync!==0,u=n?.[e.id],d=e.status===`syncing`||u?.status===`syncing`;return(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[c(e.provider),(0,b.jsx)(`strong`,{style:{fontSize:`1rem`},children:e.name})]}),!d&&(e.status===`error`||u?.status===`error`?(0,b.jsxs)(`span`,{className:`badge badge-danger`,title:e.last_error||u?.error||`Sync failed`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`}),` Error`]}):e.status===`pending`||u?.status===`pending`?(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock`}),` Pending`]}):(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`}),` Synced`]}))]}),d&&(0,b.jsx)(`div`,{style:{margin:`4px 0 2px 0`},children:l(e,u)}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`URL:`}),(0,b.jsx)(`a`,{href:e.url,target:`_blank`,rel:`noreferrer`,style:{color:`var(--primary)`,textDecoration:`none`},children:e.url})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Branch:`}),(0,b.jsx)(`code`,{children:e.branch})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Commit:`}),e.commit_sha?(0,b.jsx)(`code`,{children:e.commit_sha.substring(0,8)}):`-`]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Auto-Sync:`}),(0,b.jsx)(`button`,{type:`button`,className:`badge ${t?`badge-success`:`badge-danger`}`,style:{cursor:`pointer`,padding:`2px 6px`,fontSize:`0.75rem`},onClick:()=>i(e.id,t),title:`Auto-Sync: ${t?`ON`:`OFF`} (Click to toggle)`,"aria-label":`Toggle auto-sync for ${e.name}`,children:t?`ON`:`OFF`})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Files:`}),(e.file_count||0).toLocaleString(),` files`]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Last Synced:`}),e.last_synced||`Never`]}),!d&&(e.last_error||u?.error)&&(0,b.jsxs)(`div`,{style:{color:`var(--danger)`,fontSize:`0.75rem`},children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Error:`}),e.last_error||u?.error]})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-actions`,children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>s?.(e.id),title:`View Ingestion Logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Logs`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>r(e.id),title:`Trigger Sync`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Sync`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>a(e),title:`Webhook Setup`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Webhook`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>o(e.id,e.name),title:`Delete Repo`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})]})]},`card-${e.id}`)})})]})}var k=[{step:1,title:`1. Connecting & Remote Check`},{step:2,title:`2. Shallow Cloning Repository`},{step:3,title:`3. Computing File Delta & Scanning`},{step:4,title:`4. Parsing AST Symbols & API Routes`},{step:5,title:`5. Upserting Embeddings & Finalizing`}];function ee({isOpen:e,onClose:t,repoId:n,repoName:r,job:i,onCancelSync:a}){let[o,s]=(0,_.useState)(``),[c,l]=(0,_.useState)(!0),[u,d]=(0,_.useState)(!1),[f,p]=(0,_.useState)(0),[m,h]=(0,_.useState)(!1),g=(0,_.useRef)(null),v=(0,_.useRef)(null),y=n??i?.repo_id??null,x=r||i?.repo_name||`Repository`;(0,_.useEffect)(()=>{if(!e||!i?.started_at){p(0);return}let t=()=>{let e=i.started_at>1e11?i.started_at:i.started_at*1e3;return Math.max(0,Math.floor((Date.now()-e)/1e3))};if(p(t()),i.status===`syncing`||i.status===`pending`){let e=setInterval(()=>{p(t())},1e3);return()=>clearInterval(e)}},[e,i?.started_at,i?.status]);let S=e=>{let t=Math.floor(e/60),n=e%60;return`${t.toString().padStart(2,`0`)}:${n.toString().padStart(2,`0`)}`},C=i?.logs,w=(0,_.useMemo)(()=>{let e=C||[];if(!o.trim())return e;let t=o.toLowerCase();return e.filter(e=>e.message.toLowerCase().includes(t)||e.level.toLowerCase().includes(t)||e.timestamp.toLowerCase().includes(t))},[C,o]);(0,_.useEffect)(()=>{c&&g.current&&typeof g.current.scrollIntoView==`function`&&g.current.scrollIntoView({behavior:`smooth`})},[w,c]);let T=async()=>{let e=(i?.logs||[]).map(e=>`[${e.timestamp}] [${e.level.toUpperCase()}] ${e.message}`).join(` -`);try{await navigator.clipboard.writeText(e),d(!0),setTimeout(()=>d(!1),2e3)}catch(e){console.error(`Failed to copy logs:`,e)}},E=async()=>{if(!(!y||!a))try{h(!0),await a(y)}catch(e){console.error(`Failed to cancel sync:`,e)}finally{h(!1)}};if(!e)return null;let D=i?.status||`pending`,O=i?.percent??(D===`synced`?100:0),ee=i?.step??(D===`synced`?5:1);return(0,b.jsx)(`div`,{className:`sync-drawer-backdrop`,onClick:e=>{e.target===e.currentTarget&&t()},"data-testid":`sync-drawer-backdrop`,children:(0,b.jsxs)(`div`,{className:`sync-drawer`,children:[(0,b.jsxs)(`div`,{className:`sync-drawer-header`,children:[(0,b.jsxs)(`div`,{className:`sync-drawer-title-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`10px`,flexWrap:`wrap`},children:[(0,b.jsxs)(`h2`,{style:{fontSize:`1.1rem`,margin:0,fontWeight:700,color:`var(--text)`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`,style:{marginRight:`8px`,color:`var(--primary)`}}),x,` Ingestion Progress & Live Logs`]}),D===`syncing`?(0,b.jsxs)(`span`,{className:`badge badge-warning`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Syncing`]}):D===`synced`?(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`}),` Synced`]}):D===`error`?(0,b.jsxs)(`span`,{className:`badge badge-danger`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`}),` Error`]}):(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock`}),` Pending`]})]}),(0,b.jsxs)(`div`,{className:`sync-drawer-meta`,style:{display:`flex`,alignItems:`center`,gap:`12px`,marginTop:`6px`,fontSize:`0.82rem`,color:`var(--text-muted)`},children:[(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`i`,{className:`fa-regular fa-clock`,style:{marginRight:`4px`}}),`Elapsed: `,(0,b.jsx)(`strong`,{children:S(f)})]}),i?.step_name&&(0,b.jsxs)(`span`,{children:[`• Current: `,(0,b.jsx)(`strong`,{children:i.step_name})]})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[D===`syncing`&&a&&y!=null&&(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary btn-cancel-sync`,onClick:E,disabled:m,style:{fontSize:`0.8rem`,padding:`6px 12px`,color:`var(--danger)`,borderColor:`rgba(239, 68, 68, 0.4)`},children:[(0,b.jsx)(`i`,{className:`fa-solid ${m?`fa-spinner fa-spin`:`fa-stop`}`}),m?`Cancelling...`:`Cancel Sync`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:t,"aria-label":`Close sync drawer`,style:{fontSize:`1.4rem`,lineHeight:1},children:`×`})]})]}),(0,b.jsxs)(`div`,{className:`sync-drawer-body`,children:[(0,b.jsxs)(`div`,{className:`sync-progress-section`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`span`,{style:{fontWeight:600,color:`var(--text)`},children:`Overall Ingestion`}),(0,b.jsxs)(`span`,{style:{fontWeight:700,color:D===`error`?`var(--danger)`:`var(--primary)`},children:[O,`%`]})]}),(0,b.jsx)(`div`,{className:`sync-progress-bar-container`,children:(0,b.jsx)(`div`,{className:`sync-progress-bar-fill ${D===`error`?`fill-error`:D===`synced`?`fill-success`:`fill-active`}`,style:{width:`${O}%`}})})]}),(0,b.jsxs)(`div`,{className:`sync-stepper-container`,children:[(0,b.jsx)(`h4`,{style:{fontSize:`0.82rem`,textTransform:`uppercase`,letterSpacing:`0.05em`,color:`var(--text-muted)`,marginBottom:`10px`},children:`Ingestion Stages`}),(0,b.jsx)(`div`,{className:`sync-stepper-list`,children:k.map(e=>{let t=D===`synced`||D!==`error`&&ee>e.step||D===`error`&&ee>e.step,n=D===`syncing`&&ee===e.step,r=D===`error`&&ee===e.step;return(0,b.jsxs)(`div`,{className:`sync-stepper-item ${t?`item-completed`:n?`item-active`:r?`item-error`:`item-pending`}`,children:[(0,b.jsxs)(`div`,{className:`sync-stepper-icon`,children:[t&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`,style:{color:`#10b981`}}),n&&(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{color:`#f59e0b`}}),r&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-xmark`,style:{color:`#ef4444`}}),!t&&!n&&!r&&(0,b.jsx)(`i`,{className:`fa-regular fa-circle`,style:{color:`var(--text-muted)`}})]}),(0,b.jsxs)(`div`,{className:`sync-stepper-content`,children:[(0,b.jsx)(`div`,{className:`sync-stepper-title`,style:{fontWeight:n?600:500},children:e.title}),n&&(0,b.jsxs)(`div`,{className:`sync-stepper-details`,children:[i?.current_file&&(0,b.jsxs)(`div`,{className:`sync-current-file`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{marginRight:`4px`}}),(0,b.jsx)(`code`,{children:i.current_file})]}),i?.total_files!=null&&i.total_files>0&&(0,b.jsxs)(`div`,{className:`sync-file-count`,style:{marginTop:`2px`,color:`var(--text-muted)`},children:[i.processed_files,` / `,i.total_files,` files (`,O,`%)`]})]}),r&&i?.error&&(0,b.jsxs)(`div`,{className:`sync-stepper-error-msg`,style:{marginTop:`4px`,color:`var(--danger)`,fontSize:`0.82rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,style:{marginRight:`4px`}}),i.error]})]})]},e.step)})})]}),(0,b.jsxs)(`div`,{className:`sync-terminal-section`,children:[(0,b.jsxs)(`div`,{className:`sync-terminal-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`,style:{color:`var(--accent)`}}),(0,b.jsx)(`span`,{style:{fontSize:`0.85rem`,fontWeight:600,color:`var(--text)`},children:`Live Terminal Output`}),(0,b.jsxs)(`span`,{className:`badge badge-secondary`,style:{fontSize:`0.75rem`,padding:`1px 6px`},children:[w.length,` `,w.length===1?`event`:`events`]})]}),(0,b.jsxs)(`div`,{className:`sync-terminal-actions`,children:[(0,b.jsxs)(`label`,{className:`sync-autoscroll-toggle`,children:[(0,b.jsx)(`input`,{type:`checkbox`,checked:c,onChange:e=>l(e.target.checked),"aria-label":`Autoscroll`}),(0,b.jsx)(`span`,{children:`Autoscroll`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:T,"aria-label":`Copy logs`,style:{fontSize:`0.75rem`,padding:`3px 8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid ${u?`fa-check`:`fa-copy`}`}),` `,u?`Copied!`:`Copy Logs`]})]})]}),(0,b.jsxs)(`div`,{className:`sync-terminal-search`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`,style:{color:`var(--text-muted)`,fontSize:`0.8rem`}}),(0,b.jsx)(`input`,{type:`text`,placeholder:`Filter logs by keyword or level...`,value:o,onChange:e=>s(e.target.value),style:{width:`100%`,background:`transparent`,border:`none`,outline:`none`,color:`var(--text)`,fontSize:`0.82rem`,padding:`4px 0`}}),o&&(0,b.jsx)(`button`,{type:`button`,onClick:()=>s(``),style:{background:`transparent`,border:`none`,color:`var(--text-muted)`,cursor:`pointer`,fontSize:`0.8rem`},children:`×`})]}),(0,b.jsx)(`div`,{className:`sync-terminal-body`,ref:v,children:w.length===0?(0,b.jsxs)(`div`,{className:`sync-terminal-empty`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock-rotate-left`,style:{marginBottom:`6px`,fontSize:`1.2rem`,opacity:.5}}),(0,b.jsx)(`div`,{children:(C?.length||0)===0?`Waiting for sync activity...`:`No logs matching filter`})]}):(0,b.jsxs)(`div`,{className:`sync-terminal-lines`,children:[w.map((e,t)=>{let n=(e.level||`INFO`).toUpperCase(),r=`level-info`;return(n===`WARN`||n===`WARNING`)&&(r=`level-warn`),(n===`ERROR`||n===`FATAL`)&&(r=`level-error`),(0,b.jsxs)(`div`,{className:`sync-terminal-line`,children:[(0,b.jsxs)(`span`,{className:`log-time`,children:[`[`,e.timestamp,`]`]}),(0,b.jsx)(`span`,{className:`log-badge ${r}`,children:n}),(0,b.jsx)(`span`,{className:`log-msg`,children:e.message})]},t)}),(0,b.jsx)(`div`,{ref:g})]})})]})]})]})})}function A(){let[e,t]=(0,_.useState)({}),[n,r]=(0,_.useState)(!1),i=(0,_.useRef)(null),a=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/repos/sync-status`);if(e&&e.ok){let n=await e.json();if(n&&typeof n==`object`&&!Array.isArray(n)){let e={};Object.entries(n).forEach(([t,n])=>{let r=n;r&&(r.repo_id!=null||r.step!=null||r.status!=null)&&(e[Number(t)]=r)}),t(t=>({...t,...e}))}else if(Array.isArray(n)){let e={};n.forEach(t=>{t&&t.repo_id!=null&&(t.step!=null||t.status===`syncing`)&&(e[t.repo_id]=t)}),Object.keys(e).length>0&&t(t=>({...t,...e}))}}}catch(e){console.error(`Failed to fetch initial sync status snapshot:`,e)}},[]);return(0,_.useEffect)(()=>{if(a(),typeof EventSource>`u`)return;let e=null;try{e=new EventSource(`/admin/api/repos/sync/stream`),i.current=e,e.onopen=()=>{r(!0)},e.onerror=()=>{r(!1)},e.addEventListener(`init`,e=>{try{let n=JSON.parse(e.data);if(n&&typeof n==`object`){let e={};Object.entries(n).forEach(([t,n])=>{e[Number(t)]=n}),t(e),r(!0)}}catch(e){console.error(`Failed to parse init sync stream event:`,e)}}),e.addEventListener(`progress`,e=>{try{let n=JSON.parse(e.data),i=n.data||n;i&&i.repo_id!=null&&(t(e=>{let t=e[i.repo_id];return{...e,[i.repo_id]:{...t||{},...i,logs:i.logs??t?.logs??[]}}}),r(!0))}catch(e){console.error(`Failed to parse progress event:`,e)}}),e.addEventListener(`log`,e=>{try{let n=JSON.parse(e.data),r=n.repo_id??n.data?.repo_id,i=n.data&&!n.data.repo_id?n.data:n.log||n.data;r!=null&&i&&t(e=>{let t=e[r];if(!t)return e;let n=t.logs||[];return{...e,[r]:{...t,logs:[...n,i]}}})}catch(e){console.error(`Failed to parse log event:`,e)}})}catch(e){console.error(`Failed to initialize EventSource:`,e),r(!1)}return()=>{e&&(e.close(),i.current=null)}},[a]),{syncStates:e,isConnected:n,cancelSync:(0,_.useCallback)(async e=>{try{let t=await fetch(`/admin/api/repos/${e}/cancel-sync`,{method:`POST`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error||`Failed to cancel sync: ${t.statusText}`)}return await t.json()}catch(t){throw console.error(`Error cancelling sync for repo ${e}:`,t),t}},[])}}function te({refreshStats:e}){let[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!0),[a,o]=(0,_.useState)(!1),[s,c]=(0,_.useState)(null),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(null),p=S(),{syncStates:m,cancelSync:h}=A(),[g,v]=(0,_.useState)(``),[y,x]=(0,_.useState)(``),[C,w]=(0,_.useState)(`main`),[T,k]=(0,_.useState)(`auto`),[te,ne]=(0,_.useState)(``),[re,ie]=(0,_.useState)(``),[j,M]=(0,_.useState)(!1),N=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/repos`);if(!e.ok){p.error(`Failed to load repositories`);return}let t=await e.json();n(Array.isArray(t)?t:[])}catch(e){p.error(`Error loading repos: `+e.message),console.error(`Error loading repos:`,e)}finally{i(!1)}},[p]);(0,_.useEffect)(()=>{N();let e=setInterval(N,8e3);return()=>clearInterval(e)},[N]);let ae=async t=>{t.preventDefault(),M(!0);try{let t=await fetch(`/admin/api/repos`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({name:g.trim(),url:y.trim(),branch:C.trim()||`main`,provider:T===`auto`?void 0:T,auth_user:te.trim()||null,auth_token:re.trim()||null})}),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to add repository`);o(!1),v(``),x(``),w(`main`),k(`auto`),ne(``),ie(``),N(),e(),p.success(`Repository '${g.trim()}' added successfully`)}catch(e){p.error(`Error: ${e.message}`)}finally{M(!1)}},oe=async t=>{n(e=>e.map(e=>e.id===t?{...e,status:`syncing`}:e));try{let n=await fetch(`/admin/api/repos/sync/${t}`,{method:`POST`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to trigger sync`)}N(),e(),p.info(`Sync triggered successfully`)}catch(e){N(),p.error(`Failed to trigger sync: `+e.message)}},se=async(e,t)=>{let r=!t;n(t=>t.map(t=>t.id===e?{...t,auto_sync:r}:t));try{let t=await fetch(`/admin/api/repos/${e}/auto-sync`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify({auto_sync:r})});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error||e.detail||`Failed to update auto-sync`)}p.info(`Auto-sync ${r?`enabled`:`disabled`}`),N()}catch(e){N(),p.error(`Failed to update auto-sync: `+e.message)}},P=async e=>{try{navigator?.clipboard?.writeText&&await navigator.clipboard.writeText(e),u(!0),p.info(`Webhook URL copied to clipboard`),setTimeout(()=>u(!1),2e3)}catch(e){p.error(`Failed to copy: `+e.message)}},F=async(t,r)=>{if(window.confirm(`Are you sure you want to delete repository '${r}'? All vectors and indexed symbols for this repo will be permanently purged.`)){n(e=>e.filter(e=>e.id!==t));try{let n=await fetch(`/admin/api/repos/${t}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to delete repo`)}N(),e(),p.success(`Repository '${r}' deleted successfully`)}catch(e){N(),p.error(`Failed to delete repo: `+e.message)}}},ce=d===null?null:m[d],le=t.find(e=>e.id===d)?.name||ce?.repo_name||``;return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`}),` Registered Git Repositories`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Supports GitHub, GitLab, Gitea, Bitbucket, and custom self-hosted Git repositories over HTTP/HTTPS.`})]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>o(!0),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plus`}),` Add Repository`]})]}),(0,b.jsx)(O,{repos:t,isLoading:r,syncStates:m,onSync:oe,onToggleAutoSync:se,onOpenWebhook:e=>c(e),onDelete:F,onOpenSyncDrawer:e=>f(e)}),(0,b.jsx)(E,{isOpen:a,onClose:()=>o(!1),onSave:ae,alias:g,setAlias:v,url:y,setUrl:x,branch:C,setBranch:w,provider:T,setProvider:k,authUser:te,setAuthUser:ne,token:re,setToken:ie,isSaving:j}),(0,b.jsx)(D,{repo:s,onClose:()=>c(null),onCopyUrl:P,copiedUrl:l}),(0,b.jsx)(ee,{isOpen:d!==null,onClose:()=>f(null),repoId:d,repoName:le,job:ce,onCancelSync:h})]})})}function ne({refreshStats:e}){let[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!0),a=S(),[o,s]=(0,_.useState)(!1),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(``),[f,p]=(0,_.useState)(`local`),[m,h]=(0,_.useState)(``),[g,v]=(0,_.useState)(`directory`),[y,x]=(0,_.useState)(1),[C,w]=(0,_.useState)(null),T=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/paths`);if(!e.ok){a.error(`Failed to load local paths`);return}let t=await e.json();n(t)}catch(e){a.error(`Error loading paths: `+e.message),console.error(`Error loading paths:`,e)}finally{i(!1)}},[a]);(0,_.useEffect)(()=>{T();let e=setInterval(T,8e3);return()=>clearInterval(e)},[T]);let E=async t=>{t.preventDefault();try{let t=await fetch(`/admin/api/paths`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:u.trim(),repo:f.trim()||`local`,category:m.trim()||null,type:g,recursive:y,enabled:1})}),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to add path`);s(!1),d(``),p(`local`),h(``),v(`directory`),x(1),T(),e(),a.success(`Path added successfully`)}catch(e){a.error(`Error: ${e.message}`)}},D=async t=>{if(window.confirm(`Are you sure you want to delete this local search path?`)){n(e=>e.filter(e=>e.id!==t));try{let n=await fetch(`/admin/api/paths/${t}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to delete path`)}a.success(`Path deleted successfully`),T(),e()}catch(e){T(),a.error(`Failed to delete path: `+e.message)}}},O=(e=`/`)=>{l(!0),k(e)},k=async e=>{try{let t=await fetch(`/admin/api/browse?path=${encodeURIComponent(e)}`),n=await t.json();if(!t.ok){a.error(n.error||`Failed to browse directory`);return}w(n)}catch(e){a.error(`Browse error: `+e.message),console.error(`Browse error:`,e)}};return(0,b.jsxs)(`div`,{className:`tab-content active`,children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`}),` Monitored Local Paths`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Mounted documentation vaults and local workspaces scanned for changes.`})]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>s(!0),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plus`}),` Add Local Path`]})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Path`}),(0,b.jsx)(`th`,{children:`Repo Alias`}),(0,b.jsx)(`th`,{children:`Type`}),(0,b.jsx)(`th`,{children:`Recursive`}),(0,b.jsx)(`th`,{children:`Category`}),(0,b.jsx)(`th`,{children:`Enabled`}),(0,b.jsx)(`th`,{children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:r&&t.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsxs)(`td`,{colSpan:7,className:`empty-state`,"data-testid":`path-loading-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading local paths...`]})}):t.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:7,className:`empty-state`,children:`No local search paths configured.`})}):t.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.repo||`local`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.type})}),(0,b.jsx)(`td`,{children:e.recursive?`Yes`:`No`}),(0,b.jsx)(`td`,{children:e.category?(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category}):(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:e.enabled?(0,b.jsx)(`span`,{className:`badge badge-success`,children:`Enabled`}):(0,b.jsx)(`span`,{className:`badge badge-danger`,children:`Disabled`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>D(e.id),title:`Delete Path`,"aria-label":`Delete Path`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})})]},e.id))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:r&&t.length===0?(0,b.jsxs)(`div`,{className:`empty-state`,"data-testid":`path-loading-state-mobile`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading local paths...`]}):t.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No local search paths configured.`}):t.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,minWidth:0},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`,style:{color:`var(--accent)`}}),(0,b.jsx)(`strong`,{style:{fontSize:`1rem`},children:e.repo||`local`})]}),e.enabled?(0,b.jsx)(`span`,{className:`badge badge-success`,children:`Enabled`}):(0,b.jsx)(`span`,{className:`badge badge-danger`,children:`Disabled`})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.path})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,flexWrap:`wrap`,alignItems:`center`},children:[(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Type: `}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.type})]}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Recursive: `}),(0,b.jsx)(`span`,{children:e.recursive?`Yes`:`No`})]})]}),e.category&&(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Category: `}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category})]})]}),(0,b.jsx)(`div`,{className:`data-mobile-card-actions`,children:(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>D(e.id),title:`Delete Path`,"aria-label":`Delete Path`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})})]},`card-${e.id}`))})]}),o&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-open`}),` Add Monitored Local Path`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>s(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:E,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Selected Directory / File`}),(0,b.jsxs)(`div`,{className:`path-input-row`,children:[(0,b.jsx)(`input`,{type:`text`,readOnly:!0,required:!0,placeholder:`Browse workspace directories...`,value:u}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>O(C?.current_path||`/`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`}),` Browse`]})]})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-repo-alias`,children:`Repo / Vault Alias`}),(0,b.jsx)(`input`,{type:`text`,id:`path-repo-alias`,placeholder:`local`,value:f,onChange:e=>p(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-category`,children:`Category Override`}),(0,b.jsx)(`input`,{type:`text`,id:`path-category`,placeholder:`Optional category`,value:m,onChange:e=>h(e.target.value)})]})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-type`,children:`Path Type`}),(0,b.jsxs)(`select`,{id:`path-type`,value:g,onChange:e=>v(e.target.value),children:[(0,b.jsx)(`option`,{value:`directory`,children:`Directory`}),(0,b.jsx)(`option`,{value:`file`,children:`Single File`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-recursive`,children:`Scan Subfolders`}),(0,b.jsxs)(`select`,{id:`path-recursive`,value:y,onChange:e=>x(parseInt(e.target.value)),children:[(0,b.jsx)(`option`,{value:1,children:`Yes (Recursive)`}),(0,b.jsx)(`option`,{value:0,children:`No (Top-level only)`})]})]})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>s(!1),children:`Cancel`}),(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,children:`Save Path`})]})]})]})}),c&&C&&(0,b.jsx)(`div`,{className:`modal-backdrop`,style:{zIndex:1100},children:(0,b.jsxs)(`div`,{className:`glass-card modal-card browser-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-search`}),` Browse Workspace Files`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>l(!1),children:`×`})]}),(0,b.jsxs)(`div`,{className:`browser-body`,children:[(0,b.jsxs)(`div`,{className:`browser-breadcrumbs`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Current: `}),(0,b.jsx)(`span`,{className:`code`,style:{wordBreak:`break-all`},children:C.current_path})]}),(0,b.jsx)(`div`,{className:`browser-list-container`,children:(0,b.jsxs)(`ul`,{className:`browser-list`,children:[C.parent_path&&(0,b.jsxs)(`li`,{className:`browser-item`,onClick:()=>k(C.parent_path),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-level-up-alt`,style:{color:`var(--accent)`}}),` `,(0,b.jsx)(`span`,{children:`.. (Parent Directory)`})]}),C.directories.map(e=>(0,b.jsxs)(`li`,{className:`browser-item`,onClick:()=>k(e.path),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder`,style:{color:`#fbbf24`}}),` `,(0,b.jsx)(`span`,{style:{wordBreak:`break-all`},children:e.name})]},e.path)),C.files.map(e=>(0,b.jsxs)(`li`,{className:`browser-item`,onClick:()=>{d(e.path),v(`file`),l(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{color:`var(--text-muted)`}}),` `,(0,b.jsx)(`span`,{style:{wordBreak:`break-all`},children:e.name})]},e.path))]})})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>l(!1),children:`Cancel`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>{C&&(d(C.current_path),v(`directory`),l(!1))},children:`Select Current Folder`})]})]})})]})}function re(){let e=S(),[t,n]=(0,_.useState)(``),[r,i]=(0,_.useState)(`code`),[a,o]=(0,_.useState)(``),[s,c]=(0,_.useState)(!1),[l,u]=(0,_.useState)(null),[d,f]=(0,_.useState)(null);return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`}),` Live Hybrid Search Inspector`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Test hybrid search results across code and documentation directly from the browser.`}),(0,b.jsx)(`form`,{onSubmit:async n=>{n.preventDefault(),c(!0),f(null),u(null);try{let e=await fetch(`/admin/api/search/test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({query:t.trim(),type:r,repo:a.trim()||null})}),n=await e.json();if(!e.ok)throw Error(n.error||`Search failed`);u(n.results||[])}catch(t){f(t.message),e.error(`Search failed: `+t.message)}finally{c(!1)}},style:{marginTop:`16px`},children:(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:2},children:[(0,b.jsx)(`label`,{children:`Search Query`}),(0,b.jsx)(`input`,{type:`text`,required:!0,placeholder:`e.g. JWT token authentication or chunk_markdown`,value:t,onChange:e=>n(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Target Type`}),(0,b.jsxs)(`select`,{value:r,onChange:e=>i(e.target.value),children:[(0,b.jsx)(`option`,{value:`code`,children:`Code Snippets & Symbols`}),(0,b.jsx)(`option`,{value:`doc`,children:`Documentation & Notes`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Repo Filter (Optional)`}),(0,b.jsx)(`input`,{type:`text`,placeholder:`All Repos`,value:a,onChange:e=>o(e.target.value)})]}),(0,b.jsx)(`div`,{className:`form-group search-form-btn-group`,style:{alignSelf:`flex-end`},children:(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:s,children:s?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Searching...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-play`}),` Search`]})})})]})}),(0,b.jsxs)(`div`,{style:{marginTop:`20px`},children:[s&&(0,b.jsx)(`div`,{className:`empty-state`,children:`Running hybrid retrieval with Normalized Weighted Fusion...`}),d&&(0,b.jsxs)(`div`,{className:`empty-state`,style:{color:`var(--danger)`},children:[`Search error: `,d]}),!s&&!d&&l===null&&(0,b.jsx)(`div`,{className:`empty-state`,children:`Enter a query above to test hybrid retrieval.`}),!s&&!d&&l!==null&&l.length===0&&(0,b.jsx)(`div`,{className:`empty-state`,children:`No matching results found in index.`}),!s&&!d&&l!==null&&l.length>0&&l.map((e,t)=>{let n=e.payload;return(0,b.jsxs)(`div`,{className:`search-hit-card`,children:[(0,b.jsxs)(`div`,{className:`search-hit-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,alignItems:`center`,gap:`6px`},children:[(0,b.jsx)(`span`,{className:`badge badge-primary`,children:n.repo}),(0,b.jsx)(`strong`,{children:n.rel_path}),n.symbol&&(0,b.jsx)(`span`,{className:`badge badge-accent`,children:n.symbol}),(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:[`(Lines `,n.start_line,`-`,n.end_line,`)`]}),n.github_url&&(()=>{let e=n.github_url.toLowerCase(),t=`View Source`,r=`fa-solid fa-code-branch`;return e.includes(`gitlab`)||e.includes(`/-/blob/`)?(t=`View on GitLab`,r=`fa-brands fa-gitlab`):e.includes(`gitea`)||e.includes(`forgejo`)?(t=`View on Gitea`,r=`fa-solid fa-mug-hot`):e.includes(`bitbucket`)?(t=`View on Bitbucket`,r=`fa-brands fa-bitbucket`):e.includes(`github.com`)&&(t=`View on GitHub`,r=`fa-brands fa-github`),(0,b.jsxs)(`a`,{href:n.github_url,target:`_blank`,rel:`noreferrer`,style:{color:`var(--primary)`,fontSize:`0.8rem`},children:[(0,b.jsx)(`i`,{className:r,style:{marginRight:`4px`}}),t]})})()]}),(0,b.jsx)(`div`,{children:(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[`Score: `,(e.score*100).toFixed(1),`% (`,e.score.toFixed(4),`)`]})})]}),(0,b.jsx)(`pre`,{className:`search-hit-code`,children:n.content})]},t)})]})]})})}function ie({vectorStore:e,isLoadingVs:t,testFeedback:n,vsProvider:r,vsMode:i,vsStoragePath:a,setVsStoragePath:o,vsUrl:s,setVsUrl:c,vsCollection:l,setVsCollection:u,isTestingVs:d,isSwitchingVs:f,onProviderChange:p,onModeChange:m,onTestConnection:h,onSwitchBackend:g}){return(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-database`}),` Vector Database Engine`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure and switch between vector database backends (Qdrant & ChromaDB). Switching backends updates system metadata and triggers full re-indexing.`}),(0,b.jsxs)(`div`,{className:`vs-config-layout`,children:[(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-nodes`}),` Active Vector Backend`]}),t&&!e?(0,b.jsx)(`p`,{className:`text-muted`,children:`Loading vector store configuration...`}):e?(0,b.jsxs)(`div`,{className:`specs-list`,style:{marginTop:0},children:[(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Provider:`}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider===`chroma`?`ChromaDB`:`Qdrant`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Operating Mode:`}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.mode===`embedded`?`Embedded Disk`:`Remote Server`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:e.mode===`embedded`?`Storage Path:`:`Server URL:`}),(0,b.jsx)(`code`,{children:e.mode===`embedded`?e.storage_path||`data/qdrant_db`:e.url||`http://localhost:6333`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Collection Name:`}),(0,b.jsx)(`code`,{children:e.collection||`knowledge_rag_v1`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Points Count:`}),(0,b.jsx)(`span`,{style:{fontSize:`0.9rem`,fontWeight:600},children:(e.points_count||0).toLocaleString()})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Health Status:`}),e.healthy?(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`}),` Healthy`]}):(0,b.jsxs)(`span`,{className:`badge badge-danger`,title:e.health_message||`Unhealthy`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`}),` `,e.health_message?e.health_message.length>35?e.health_message.slice(0,35)+`...`:e.health_message:`Unhealthy`]})]})]}):(0,b.jsx)(`p`,{className:`text-muted`,children:`No vector store configuration found.`})]}),(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-sliders`}),` Configure & Switch Backend`]}),n&&(0,b.jsxs)(`div`,{className:`vs-feedback-banner ${n.success?`feedback-success`:`feedback-error`}`,children:[(0,b.jsx)(`i`,{className:n.success?`fa-solid fa-circle-check`:`fa-solid fa-circle-exclamation`}),(0,b.jsx)(`span`,{children:n.message})]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),g()},children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-provider`,children:`Vector Store Provider`}),(0,b.jsxs)(`select`,{id:`vs-provider`,value:r,onChange:e=>p(e.target.value),children:[(0,b.jsx)(`option`,{value:`qdrant`,children:`Qdrant (Hybrid Dense + BM25)`}),(0,b.jsx)(`option`,{value:`chroma`,children:`ChromaDB (Dense Vectors)`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-mode`,children:`Operating Mode`}),(0,b.jsxs)(`select`,{id:`vs-mode`,value:i,onChange:e=>m(e.target.value),children:[(0,b.jsx)(`option`,{value:`embedded`,children:`Embedded Disk Storage`}),(0,b.jsx)(`option`,{value:`remote`,children:`Remote Server URL`})]})]})]}),i===`embedded`?(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-storage-path`,children:`Storage Directory Path`}),(0,b.jsx)(`input`,{id:`vs-storage-path`,type:`text`,value:a,onChange:e=>o(e.target.value),placeholder:r===`chroma`?`data/chroma_db`:`data/qdrant_db`})]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-url`,children:`Remote Server URL`}),(0,b.jsx)(`input`,{id:`vs-url`,type:`text`,value:s,onChange:e=>c(e.target.value),placeholder:r===`chroma`?`http://localhost:8000`:`http://localhost:6333`})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-collection`,children:`Collection Name`}),(0,b.jsx)(`input`,{id:`vs-collection`,type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`knowledge_rag_v1`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`10px`,marginTop:`16px`,flexWrap:`wrap`},children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:h,disabled:d||f,children:d?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Testing Connection...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plug`}),` Test Connection`]})}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:g,disabled:d||f,children:f?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Switching Backend...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Save & Switch Backend`]})})]})]})]})]})]})}function j({embeddingConfig:e,isLoadingEmb:t,isSavingEmb:n,embProvider:r,setEmbProvider:i,embThreads:a,setEmbThreads:o,embBatchSize:s,setEmbBatchSize:c,embDenseModel:l,setEmbDenseModel:u,embSparseModel:d,setEmbSparseModel:f,embLitellmUrl:p,setEmbLitellmUrl:m,embLitellmApiKey:h=``,setEmbLitellmApiKey:g,embVisionOcrModel:v=`gemini-2.5-flash`,setEmbVisionOcrModel:y,embChatModel:x=`gemini-2.5-flash`,setEmbChatModel:S,discoveryResult:C=null,isDiscovering:w=!1,onDiscoverModels:T,onSaveEmbeddingSettings:E}){let D=e?.system_cpus||2,O=e?.system_memory_gb||4,[k,ee]=(0,_.useState)(!1),[A,te]=(0,_.useState)(!1),[ne,re]=(0,_.useState)(!1),ie=C?.embedding_models||[],j=C?.vision_models||[],M=C?.chat_models||[];return(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-microchip`}),` Embedding Engine & Resource Limits`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure local FastEmbed (ONNX) resource limits, CPU thread concurrency, or remote LiteLLM endpoints with dynamic model discovery for embeddings, Vision AI OCR, and chat synthesis.`}),(0,b.jsxs)(`div`,{className:`vs-config-layout`,children:[(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-gauge-high`}),` Active Embedding Engine`]}),t&&!e?(0,b.jsx)(`p`,{className:`text-muted`,children:`Loading embedding configuration...`}):e?(0,b.jsxs)(`div`,{className:`specs-list`,style:{marginTop:0},children:[(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Execution Provider:`}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider===`api`?`Remote API (LiteLLM)`:`Local FastEmbed (ONNX)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`CPU Threads Allocation:`}),(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[e.threads,` `,e.threads===1?`Core`:`Cores`,` (of `,D,` detected)`]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Batch Processing Size:`}),(0,b.jsxs)(`span`,{style:{fontSize:`0.9rem`,fontWeight:600},children:[e.batch_size,` chunks/batch`]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`System RAM Capacity:`}),(0,b.jsxs)(`span`,{style:{fontSize:`0.9rem`,fontWeight:600},children:[O,` GB`]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Dense Model:`}),(0,b.jsx)(`code`,{children:e.dense_model||`BAAI/bge-small-en-v1.5`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Sparse Model (BM25):`}),(0,b.jsx)(`code`,{children:e.sparse_model||`Qdrant/bm25`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Vision AI OCR Model:`}),(0,b.jsx)(`code`,{children:e.vision_ocr_model||`gemini-2.5-flash`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Chat Completion Model:`}),(0,b.jsx)(`code`,{children:e.chat_model||`gemini-2.5-flash`})]}),e.provider===`api`&&(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`API Endpoint URL:`}),(0,b.jsx)(`code`,{children:e.litellm_url||`http://litellm:4000/v1`})]})]}):(0,b.jsx)(`p`,{className:`text-muted`,children:`No embedding configuration found.`})]}),(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-sliders`}),` Configure Models & Resources`]}),(0,b.jsxs)(`form`,{onSubmit:E,children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-provider`,children:`Embedding Provider`}),(0,b.jsxs)(`select`,{id:`emb-provider`,value:r,onChange:e=>i(e.target.value),children:[(0,b.jsx)(`option`,{value:`local`,children:`Local Model (FastEmbed / ONNX Runtime)`}),(0,b.jsx)(`option`,{value:`api`,children:`API Endpoint (LiteLLM / OpenAI Compatible)`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-threads`,children:`CPU Thread Cap`}),(0,b.jsx)(`input`,{id:`emb-threads`,type:`number`,min:`1`,max:Math.max(D,128),value:a,onChange:e=>o(Math.max(1,parseInt(e.target.value)||1)),placeholder:`2`}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`,marginTop:`2px`,display:`block`},children:`Recommended: 2 cores. Prevents container CPU spikes.`})]})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-batch-size`,children:`Embedding Batch Size`}),(0,b.jsxs)(`select`,{id:`emb-batch-size`,value:s,onChange:e=>c(parseInt(e.target.value)||32),children:[(0,b.jsx)(`option`,{value:`16`,children:`16 chunks (Lowest RAM footprint)`}),(0,b.jsx)(`option`,{value:`32`,children:`32 chunks (Balanced Default)`}),(0,b.jsx)(`option`,{value:`64`,children:`64 chunks (High throughput)`}),(0,b.jsx)(`option`,{value:`128`,children:`128 chunks (Large RAM environments)`}),(0,b.jsx)(`option`,{value:`256`,children:`256 chunks (FastEmbed default)`})]})]}),r===`api`?(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-litellm-url`,children:`API Endpoint URL (LiteLLM)`}),(0,b.jsx)(`input`,{id:`emb-litellm-url`,type:`text`,value:p,onChange:e=>m(e.target.value),placeholder:`http://litellm:4000/v1`})]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-dense-model`,children:`Dense Model Name`}),(0,b.jsx)(`input`,{id:`emb-dense-model`,type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`BAAI/bge-small-en-v1.5`})]})]}),r===`api`&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-litellm-api-key`,children:`LiteLLM API Key (Optional / Bearer)`}),(0,b.jsx)(`input`,{id:`emb-litellm-api-key`,type:`password`,value:h,onChange:e=>g?.(e.target.value),placeholder:`sk-...`,autoComplete:`off`})]}),(0,b.jsx)(`div`,{className:`form-group`,style:{display:`flex`,flexDirection:`column`,justifyContent:`flex-end`},children:(0,b.jsx)(`button`,{type:`button`,id:`btn-discover-models`,className:`btn btn-secondary`,onClick:T,disabled:w,style:{height:`38px`,whiteSpace:`nowrap`},children:w?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Discovering...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Discover Models`]})})})]}),C&&(0,b.jsx)(`div`,{style:{marginBottom:`16px`},children:C.status===`success`?(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`8px 12px`,background:`rgba(16, 185, 129, 0.1)`,border:`1px solid rgba(16, 185, 129, 0.3)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`,style:{color:`#10b981`}}),(0,b.jsxs)(`span`,{children:[`Connected to LiteLLM — `,(0,b.jsxs)(`strong`,{children:[C.total_models,` models available`]}),` (`,ie.length,` embedding, `,j.length,` vision, `,M.length,` chat)`]})]}):(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`8px 12px`,background:`rgba(239, 68, 68, 0.1)`,border:`1px solid rgba(239, 68, 68, 0.3)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,style:{color:`#ef4444`}}),(0,b.jsx)(`span`,{children:C.message||`Could not connect to LiteLLM endpoint`})]})}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[(0,b.jsx)(`label`,{htmlFor:`emb-dense-model`,style:{marginBottom:0},children:`Dense Embedding Model`}),ie.length>0&&(0,b.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:()=>ee(!k),style:{fontSize:`0.75rem`,background:`none`,border:`none`,color:`#38bdf8`,cursor:`pointer`,padding:0},children:k?`← Select from discovered`:`Enter custom model →`})]}),!k&&ie.length>0?(0,b.jsxs)(`select`,{id:`emb-dense-model`,value:l,onChange:e=>{e.target.value===`__custom__`?ee(!0):u(e.target.value)},children:[ie.map(e=>(0,b.jsx)(`option`,{value:e,children:e},e)),(0,b.jsx)(`option`,{value:`__custom__`,children:`Custom / Enter manually...`})]}):(0,b.jsx)(`input`,{id:`emb-dense-model`,type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`gemini-embedding-2`})]})]}),r===`local`&&(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-sparse-model`,children:`Sparse BM25 Model`}),(0,b.jsx)(`input`,{id:`emb-sparse-model`,type:`text`,value:d,onChange:e=>f(e.target.value),placeholder:`Qdrant/bm25`})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[(0,b.jsxs)(`label`,{htmlFor:`emb-vision-ocr-model`,style:{marginBottom:0},children:[`Vision AI OCR Model `,(0,b.jsx)(`span`,{className:`text-muted`,style:{fontWeight:400,fontSize:`0.8rem`},children:`(PDF Ingestion Fallback)`})]}),j.length>0&&(0,b.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:()=>te(!A),style:{fontSize:`0.75rem`,background:`none`,border:`none`,color:`#38bdf8`,cursor:`pointer`,padding:0},children:A?`← Select from discovered`:`Enter custom model →`})]}),!A&&j.length>0?(0,b.jsxs)(`select`,{id:`emb-vision-ocr-model`,value:v,onChange:e=>{e.target.value===`__custom__`?te(!0):y?.(e.target.value)},children:[j.map(e=>(0,b.jsx)(`option`,{value:e,children:e},e)),(0,b.jsx)(`option`,{value:`__custom__`,children:`Custom / Enter manually...`})]}):(0,b.jsx)(`input`,{id:`emb-vision-ocr-model`,type:`text`,value:v,onChange:e=>y?.(e.target.value),placeholder:`gemini-2.5-flash`})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[(0,b.jsx)(`label`,{htmlFor:`emb-chat-model`,style:{marginBottom:0},children:`General Chat & Synthesis Model`}),M.length>0&&(0,b.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:()=>re(!ne),style:{fontSize:`0.75rem`,background:`none`,border:`none`,color:`#38bdf8`,cursor:`pointer`,padding:0},children:ne?`← Select from discovered`:`Enter custom model →`})]}),!ne&&M.length>0?(0,b.jsxs)(`select`,{id:`emb-chat-model`,value:x,onChange:e=>{e.target.value===`__custom__`?re(!0):S?.(e.target.value)},children:[M.map(e=>(0,b.jsx)(`option`,{value:e,children:e},e)),(0,b.jsx)(`option`,{value:`__custom__`,children:`Custom / Enter manually...`})]}):(0,b.jsx)(`input`,{id:`emb-chat-model`,type:`text`,value:x,onChange:e=>S?.(e.target.value),placeholder:`gemini-2.5-flash`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,gap:`10px`,marginTop:`16px`},children:(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:n||t,children:n?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving & Applying...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-floppy-disk`}),` Save & Apply Embedding Limits & Model Settings`]})})})]})]})]})]})}function M({isLoadingAutoSync:e,intervalMins:t,setIntervalMins:n,hasGlobalSecret:r,showWebhookSecret:i,setShowWebhookSecret:a,webhookSecret:o,setWebhookSecret:s,fullWebhookUrl:c,copiedWebhookUrl:l,isSavingAutoSync:u,onSaveAutoSync:d,onClearWebhookSecret:f,onCopyWebhookUrl:p}){return(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Auto-Sync & Webhooks`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure scheduled background repository polling interval and global incoming webhook triggers.`}),e&&!t?(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`12px`},children:`Loading auto-sync settings...`}):(0,b.jsxs)(`form`,{onSubmit:d,style:{marginTop:`16px`},children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,b.jsx)(`label`,{htmlFor:`auto-sync-interval`,children:`Repository Polling Interval`}),(0,b.jsxs)(`select`,{id:`auto-sync-interval`,value:t,onChange:e=>n(Number(e.target.value)),style:{width:`100%`},children:[(0,b.jsx)(`option`,{value:0,children:`Disabled (0m)`}),(0,b.jsx)(`option`,{value:5,children:`5 minutes`}),(0,b.jsx)(`option`,{value:15,children:`15 minutes (Default)`}),(0,b.jsx)(`option`,{value:30,children:`30 minutes`}),(0,b.jsx)(`option`,{value:60,children:`1 hour`}),(0,b.jsx)(`option`,{value:360,children:`6 hours`}),![0,5,15,30,60,360].includes(t)&&(0,b.jsxs)(`option`,{value:t,children:[t,` minutes (Custom)`]})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`6px`},children:[(0,b.jsx)(`label`,{htmlFor:`auto-sync-secret`,style:{marginBottom:0},children:`Global Webhook Secret (HMAC / Token)`}),r?(0,b.jsx)(`span`,{className:`badge badge-accent`,children:`Secret Active`}):(0,b.jsx)(`span`,{className:`badge badge-secondary`,style:{color:`var(--text-muted)`},children:`None`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`input`,{id:`auto-sync-secret`,type:i?`text`:`password`,value:o,onChange:e=>s(e.target.value),placeholder:r?`Secret configured (enter new to change)`:`Enter webhook secret (optional)`,style:{flex:1}}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>a(!i),title:i?`Hide secret`:`Reveal secret`,"aria-label":i?`Hide secret`:`Reveal secret`,style:{minWidth:`42px`,padding:`0 12px`},children:(0,b.jsx)(`i`,{className:`fa-solid ${i?`fa-eye-slash`:`fa-eye`}`})}),(r||o)&&(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:f,title:`Clear secret`,"aria-label":`Clear secret`,disabled:u,style:{padding:`0 12px`},children:`Clear`})]})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{marginTop:`14px`,minWidth:0,width:`100%`},children:[(0,b.jsx)(`label`,{htmlFor:`auto-sync-webhook-url`,children:`Incoming Webhook Payload URL`}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,minWidth:0,width:`100%`},children:[(0,b.jsx)(`input`,{id:`auto-sync-webhook-url`,type:`text`,readOnly:!0,value:c,style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`,flex:1,minWidth:0,width:`100%`},"aria-label":`Webhook Payload URL`}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:p,style:{minWidth:`95px`},"aria-label":`Copy Webhook URL`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${l?`fa-check`:`fa-copy`}`}),` `,l?`Copied!`:`Copy`]})]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{fontSize:`0.8rem`,marginTop:`6px`},children:`Payload URL for repository push webhooks. Webhooks trigger immediate background synchronization for registered repositories.`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,gap:`10px`,marginTop:`18px`},children:(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:u,children:u?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-floppy-disk`}),` Save Auto-Sync Settings`]})})})]})]})}function N({stats:e,ghAuth:t,glAuth:n,gtAuth:r,ghToken:i,setGhToken:a,glToken:o,setGlToken:s,gtToken:c,setGtToken:l,hostCredentials:u,isHostModalOpen:d,setIsHostModalOpen:f,newHost:p,setNewHost:m,newHostProvider:h,setNewHostProvider:g,newHostUser:_,setNewHostUser:v,newHostToken:y,setNewHostToken:x,isSavingHost:S,onSaveToken:C,onClearToken:w,onSaveHostCredential:T,onDeleteHostCredential:E}){return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-key`}),` Global Git Provider Authentication`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Default tokens are automatically applied to repositories matching these providers when no per-repo or host-specific override exists.`}),(0,b.jsxs)(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(min(100%, 300px), 1fr))`,gap:`20px`,marginTop:`20px`},children:[(0,b.jsxs)(`div`,{className:`settings-provider-box`,style:{background:`rgba(255,255,255,0.02)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,fontWeight:600},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github fa-lg`}),` GitHub`]}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:t.token_source})]}),(0,b.jsxs)(`div`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`,marginBottom:`8px`,wordBreak:`break-all`},children:[`Active Token: `,(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:t.masked_token})]}),e?.rate_limit&&(0,b.jsxs)(`div`,{style:{fontSize:`0.78rem`,color:`var(--text-muted)`,marginBottom:`12px`},children:[`Rate Limit: `,e.rate_limit.remaining,` / `,e.rate_limit.limit,` requests`]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(`github_token`,i,`GitHub`)},children:[(0,b.jsx)(`div`,{className:`form-group`,style:{marginBottom:`10px`},children:(0,b.jsx)(`input`,{type:`password`,placeholder:`ghp_xxxxxxxxxxxx`,value:i,onChange:e=>a(e.target.value)})}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},children:`Save`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},onClick:()=>w(`github_token`,`GitHub`),children:`Clear`})]})]})]}),(0,b.jsxs)(`div`,{className:`settings-provider-box`,style:{background:`rgba(255,255,255,0.02)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,fontWeight:600},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-gitlab fa-lg`,style:{color:`#fc6d26`}}),` GitLab (Global)`]}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:n.token_source})]}),(0,b.jsxs)(`div`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`,marginBottom:`16px`,wordBreak:`break-all`},children:[`Active Token: `,(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:n.masked_token})]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(`gitlab_token`,o,`GitLab`)},children:[(0,b.jsx)(`div`,{className:`form-group`,style:{marginBottom:`10px`},children:(0,b.jsx)(`input`,{type:`password`,placeholder:`glpat-xxxxxxxxxxxx`,value:o,onChange:e=>s(e.target.value)})}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},children:`Save`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},onClick:()=>w(`gitlab_token`,`GitLab`),children:`Clear`})]})]})]}),(0,b.jsxs)(`div`,{className:`settings-provider-box`,style:{background:`rgba(255,255,255,0.02)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,fontWeight:600},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-mug-hot fa-lg`,style:{color:`#609926`}}),` Gitea / Forgejo`]}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:r.token_source})]}),(0,b.jsxs)(`div`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`,marginBottom:`16px`,wordBreak:`break-all`},children:[`Active Token: `,(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:r.masked_token})]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(`gitea_token`,c,`Gitea`)},children:[(0,b.jsx)(`div`,{className:`form-group`,style:{marginBottom:`10px`},children:(0,b.jsx)(`input`,{type:`password`,placeholder:`Token / Personal Token`,value:c,onChange:e=>l(e.target.value)})}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},children:`Save`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},onClick:()=>w(`gitea_token`,`Gitea`),children:`Clear`})]})]})]})]})]}),(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-shield-halved`}),` Custom & Self-Hosted Git Host Vault`]}),(0,b.jsxs)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:[`Define credentials for self-hosted GitLab Enterprise, Gitea, or custom servers (e.g. `,(0,b.jsx)(`code`,{children:`gitlab.mycorp.com`}),` or `,(0,b.jsx)(`code`,{children:`git.lan:3000`}),`).`]})]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>f(!0),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plus`}),` Add Host Credential`]})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,style:{marginTop:`16px`},children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Host Domain / Address`}),(0,b.jsx)(`th`,{children:`Provider Type`}),(0,b.jsx)(`th`,{children:`Auth User`}),(0,b.jsx)(`th`,{children:`Masked Token`}),(0,b.jsx)(`th`,{children:`Added At`}),(0,b.jsx)(`th`,{children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:u.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:6,className:`empty-state`,children:`No custom host credentials configured. Add a host domain to authenticate self-hosted instances.`})}):u.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.host})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider.toUpperCase()})}),(0,b.jsx)(`td`,{children:e.auth_user?(0,b.jsx)(`code`,{children:e.auth_user}):(0,b.jsx)(`span`,{className:`text-muted`,children:`Default`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.masked_token})}),(0,b.jsx)(`td`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`},children:e.added_at}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>E(e.id,e.host),title:`Delete Credential`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})})]},e.id))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:u.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No custom host credentials configured. Add a host domain to authenticate self-hosted instances.`}):u.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:(0,b.jsx)(`code`,{style:{fontSize:`0.95rem`},children:e.host})}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider.toUpperCase()})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Auth User: `}),e.auth_user?(0,b.jsx)(`code`,{children:e.auth_user}):(0,b.jsx)(`span`,{className:`text-muted`,children:`Default`})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Masked Token: `}),(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.masked_token})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Added At: `}),(0,b.jsx)(`span`,{style:{color:`var(--text-muted)`},children:e.added_at})]})]}),(0,b.jsx)(`div`,{className:`data-mobile-card-actions`,children:(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>E(e.id,e.host),title:`Delete Credential`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})})]},`card-${e.id}`))})]}),d&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-shield-halved`}),` Add Host Credential`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>f(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:T,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-domain`,children:`Host Domain / IP`}),(0,b.jsx)(`input`,{type:`text`,id:`host-domain`,required:!0,placeholder:`e.g. gitlab.mycorp.internal or git.lan:3000`,value:p,onChange:e=>m(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-provider`,children:`Provider Type`}),(0,b.jsxs)(`select`,{id:`host-provider`,value:h,onChange:e=>g(e.target.value),children:[(0,b.jsx)(`option`,{value:`gitlab`,children:`GitLab Enterprise / Self-Hosted`}),(0,b.jsx)(`option`,{value:`gitea`,children:`Gitea / Forgejo`}),(0,b.jsx)(`option`,{value:`github`,children:`GitHub Enterprise`}),(0,b.jsx)(`option`,{value:`bitbucket`,children:`Bitbucket Server / Cloud`}),(0,b.jsx)(`option`,{value:`generic`,children:`Generic Git (HTTP / HTTPS)`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-user`,children:`Auth User (Optional)`}),(0,b.jsx)(`input`,{type:`text`,id:`host-user`,placeholder:`e.g. oauth2 or gitlab-ci-token`,value:_,onChange:e=>v(e.target.value)})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-token`,children:`Personal Access Token / Password`}),(0,b.jsx)(`input`,{type:`password`,id:`host-token`,required:!0,placeholder:`Token or password`,value:y,onChange:e=>x(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>f(!1),children:`Cancel`}),(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:S,children:S?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving...`]}):`Save Host Credential`})]})]})]})})]})}var ae=`contextcortex_theme`,oe=`deep-ocean`,se=[{id:`deep-ocean`,name:`Deep Ocean`,mode:`dark`,description:`Monochromatic petrol slate with vibrant cyan and mint accents.`,swatches:[`#07181b`,`#0d2c2f`,`#0891b2`,`#2dd4bf`]},{id:`midnight-blue`,name:`Midnight Blue`,mode:`dark`,description:`Classic deep space navy with cobalt blue and teal highlights.`,swatches:[`#0a0f1d`,`#121a2f`,`#3b82f6`,`#14b8a6`]},{id:`lavender-haze`,name:`Lavender Haze`,mode:`light`,description:`Elegant soft violet canvas with vibrant purple, fuchsia accents, and plum text.`,swatches:[`#f5f3ff`,`#faf8ff`,`#7c3aed`,`#ec4899`]},{id:`amber-warmth`,name:`Amber Warmth`,mode:`light`,description:`Warm sandstone canvas with terracotta orange, amber accents, and espresso text.`,swatches:[`#fdf8f4`,`#ffffff`,`#ea580c`,`#d97706`]}];function P(){if(typeof window>`u`)return oe;try{let e=localStorage.getItem(ae);if(e===`arctic-frost`||e===`aqua-breeze`)return`lavender-haze`;if(e===`solar-daybreak`||e===`azure-daylight`)return`amber-warmth`;if(e&&se.some(t=>t.id===e))return e}catch{}return oe}function F(e){if(!(typeof document>`u`)){document.documentElement.setAttribute(`data-theme`,e);try{localStorage.setItem(ae,e)}catch{}}}function ce(){let[e,t]=(0,_.useState)(`deep-ocean`),n=S();(0,_.useEffect)(()=>{t(P())},[]);let r=(e,r)=>{F(e),t(e),n.success(`Switched theme to ${r}`)};return(0,b.jsxs)(`section`,{className:`settings-section glass-card`,"aria-labelledby":`theme-settings-heading`,children:[(0,b.jsxs)(`div`,{className:`section-header`,children:[(0,b.jsx)(`div`,{className:`header-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-palette`})}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h2`,{id:`theme-settings-heading`,style:{fontSize:`1.1rem`,fontWeight:600},children:`Appearance & Theme`}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Choose your preferred color scheme. The selected theme will persist across browser sessions.`})]})]}),(0,b.jsx)(`div`,{className:`theme-options-grid`,role:`radiogroup`,"aria-label":`Appearance Themes`,children:se.map(t=>{let n=e===t.id;return(0,b.jsxs)(`button`,{type:`button`,className:`theme-card ${n?`active`:``}`,onClick:()=>r(t.id,t.name),role:`radio`,"aria-checked":n,"aria-label":`Select ${t.name} theme`,children:[(0,b.jsxs)(`div`,{className:`theme-card-header`,children:[(0,b.jsxs)(`div`,{className:`theme-card-title`,children:[(0,b.jsx)(`span`,{children:t.name}),(0,b.jsxs)(`span`,{className:`badge`,style:{fontSize:`0.68rem`,fontWeight:500,opacity:.85,padding:`2px 6px`},children:[(0,b.jsx)(`i`,{className:`fa-solid ${t.mode===`dark`?`fa-moon`:`fa-sun`}`,style:{marginRight:`3px`}}),t.mode===`dark`?`Dark`:`Light`]})]}),n?(0,b.jsxs)(`span`,{className:`badge badge-accent`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`,style:{marginRight:`4px`}}),` Active`]}):(0,b.jsx)(`span`,{className:`badge badge-primary`,children:`Select`})]}),(0,b.jsx)(`div`,{className:`theme-card-desc`,children:t.description}),(0,b.jsx)(`div`,{className:`theme-swatches`,"aria-hidden":`true`,children:t.swatches.map((e,t)=>(0,b.jsx)(`span`,{className:`theme-swatch`,style:{backgroundColor:e},title:e},t))})]},t.id)})})]})}function le({stats:e,refreshStats:t}){let[n,r]=(0,_.useState)(``),[i,a]=(0,_.useState)(``),[o,s]=(0,_.useState)(``),[c,l]=(0,_.useState)([]),[u,d]=(0,_.useState)(15),[f,p]=(0,_.useState)(``),[m,h]=(0,_.useState)(!1),[g,v]=(0,_.useState)(`/api/webhooks/git`),[y,x]=(0,_.useState)(!1),[C,w]=(0,_.useState)(!1),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(!1),[k,ee]=(0,_.useState)(!1),[A,te]=(0,_.useState)(``),[ne,re]=(0,_.useState)(`gitlab`),[ae,oe]=(0,_.useState)(``),[se,P]=(0,_.useState)(``),[F,le]=(0,_.useState)(!1),[ue,de]=(0,_.useState)(null),[fe,pe]=(0,_.useState)(!1),[me,he]=(0,_.useState)(`qdrant`),[ge,_e]=(0,_.useState)(`embedded`),[ve,ye]=(0,_.useState)(`data/qdrant_db`),[be,xe]=(0,_.useState)(`http://localhost:6333`),[Se,Ce]=(0,_.useState)(`knowledge_rag_v1`),[we,Te]=(0,_.useState)(!1),[Ee,De]=(0,_.useState)(null),[Oe,ke]=(0,_.useState)(!1),[Ae,je]=(0,_.useState)(null),[Me,Ne]=(0,_.useState)(!1),[Pe,Fe]=(0,_.useState)(!1),[Ie,Le]=(0,_.useState)(`local`),[Re,ze]=(0,_.useState)(2),[Be,Ve]=(0,_.useState)(32),[He,Ue]=(0,_.useState)(`BAAI/bge-small-en-v1.5`),[We,Ge]=(0,_.useState)(`Qdrant/bm25`),[Ke,qe]=(0,_.useState)(`http://litellm:4000/v1`),[Je,Ye]=(0,_.useState)(``),[Xe,Ze]=(0,_.useState)(`gemini-2.5-flash`),[Qe,$e]=(0,_.useState)(`gemini-2.5-flash`),[et,tt]=(0,_.useState)(null),[nt,rt]=(0,_.useState)(!1),I=S(),it=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/settings/hosts`);if(e.ok){let t=await e.json();l(Array.isArray(t)?t:[])}}catch(e){console.error(`Failed to load host credentials:`,e),l([])}},[]),at=(0,_.useCallback)(async()=>{pe(!0);try{let e=await fetch(`/admin/api/vector-store`);if(e.ok){let t=await e.json();de(t),t.provider&&he(t.provider),t.mode&&_e(t.mode),t.storage_path&&ye(t.storage_path),t.url&&xe(t.url),t.collection&&Ce(t.collection)}}catch(e){console.error(`Failed to load vector store config:`,e)}finally{pe(!1)}},[]),ot=(0,_.useCallback)(async()=>{x(!0);try{let e=await fetch(`/admin/api/settings/auto-sync`);if(e.ok){let t=await e.json();typeof t.interval_mins==`number`&&d(t.interval_mins),typeof t.webhook_url==`string`&&v(t.webhook_url),typeof t.has_global_secret==`boolean`&&h(t.has_global_secret)}}catch(e){console.error(`Failed to load auto-sync settings:`,e)}finally{x(!1)}},[]),st=(0,_.useCallback)(async()=>{Ne(!0);try{let e=await fetch(`/admin/api/settings/embedding`);if(e.ok){let t=await e.json();je(t),t.provider&&Le(t.provider),typeof t.threads==`number`&&ze(t.threads),typeof t.batch_size==`number`&&Ve(t.batch_size),t.dense_model&&Ue(t.dense_model),t.sparse_model&&Ge(t.sparse_model),t.litellm_url&&qe(t.litellm_url),t.litellm_api_key&&Ye(t.litellm_api_key),t.vision_ocr_model&&Ze(t.vision_ocr_model),t.chat_model&&$e(t.chat_model)}}catch(e){console.error(`Failed to load embedding config:`,e)}finally{Ne(!1)}},[]);(0,_.useEffect)(()=>{it(),at(),ot(),st()},[it,at,ot,st]),(0,_.useEffect)(()=>{e?.vector_store?(de(e.vector_store),e.vector_store.provider&&he(e.vector_store.provider),e.vector_store.mode&&_e(e.vector_store.mode),e.vector_store.storage_path&&ye(e.vector_store.storage_path),e.vector_store.url&&xe(e.vector_store.url),e.vector_store.collection&&Ce(e.vector_store.collection)):e?.vector_store_provider&&de(t=>t?{...t,provider:e.vector_store_provider||t.provider,mode:e.vector_store_mode||t.mode,collection:e.vector_store_collection||t.collection,points_count:e.points_count??t.points_count,healthy:e.vector_db_status?e.vector_db_status===`Healthy`:t.healthy}:null)},[e]);let ct=async()=>{rt(!0);try{let e=new URLSearchParams;Ke&&e.set(`url`,Ke.trim()),Je&&e.set(`api_key`,Je.trim());let t=await(await fetch(`/admin/api/models/discover?${e.toString()}`)).json();tt(t),t.status===`success`?I.success(`Discovered ${t.total_models} models from LiteLLM`):I.error(t.message||`Failed to discover models from LiteLLM`)}catch(e){tt({status:`error`,total_models:0,models:[],embedding_models:[],vision_models:[],chat_models:[],message:e.message||`Network error discovering models`}),I.error(`Error discovering models: ${e.message}`)}finally{rt(!1)}},lt=async e=>{e.preventDefault(),Fe(!0);try{let e={provider:Ie,threads:Number(Re),batch_size:Number(Be),dense_model:He.trim()||void 0,sparse_model:We.trim()||void 0,litellm_url:Ie===`api`&&Ke.trim()||void 0,litellm_api_key:Ie===`api`&&Je.trim()||void 0,vision_ocr_model:Xe.trim()||void 0,chat_model:Qe.trim()||void 0},n=await fetch(`/admin/api/settings/embedding`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}),r=await n.json();if(!n.ok)throw Error(r.error||r.message||`Failed to save embedding settings`);r.config&&je(r.config),I.success(`Embedding resource limits updated successfully`),t()}catch(e){I.error(`Error saving embedding settings: `+e.message)}finally{Fe(!1)}},ut=`${typeof window<`u`?window.location.origin:``}${g||`/api/webhooks/git`}`,dt=async()=>{try{navigator?.clipboard?.writeText&&await navigator.clipboard.writeText(ut),O(!0),I.info(`Webhook URL copied to clipboard`),setTimeout(()=>O(!1),2e3)}catch(e){I.error(`Failed to copy: `+e.message)}},ft=async e=>{e.preventDefault(),w(!0);try{let e={interval_mins:Number(u)};f.trim()&&(e.global_webhook_secret=f.trim());let t=await fetch(`/admin/api/settings/auto-sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to save auto-sync settings`);typeof n.has_global_secret==`boolean`?h(n.has_global_secret):f.trim()&&h(!0),typeof n.interval_mins==`number`&&d(n.interval_mins),p(``),I.success(`Auto-sync settings saved successfully`)}catch(e){I.error(`Error saving auto-sync settings: `+e.message)}finally{w(!1)}},pt=async()=>{if(f&&!m){p(``);return}if(window.confirm(`Clear the global webhook secret? Incoming webhook payloads will no longer require secret verification unless configured per-repository.`)){w(!0);try{let e=await fetch(`/admin/api/settings/auto-sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({interval_mins:Number(u),global_webhook_secret:``})}),t=await e.json();if(!e.ok)throw Error(t.error||`Failed to clear global webhook secret`);h(!1),p(``),I.success(`Global webhook secret cleared`)}catch(e){I.error(`Failed to clear webhook secret: `+e.message)}finally{w(!1)}}},mt=e=>{he(e),e===`qdrant`?((!ve||ve===`data/chroma_db`)&&ye(`data/qdrant_db`),(!be||be===`http://localhost:8000`)&&xe(`http://localhost:6333`)):((!ve||ve===`data/qdrant_db`)&&ye(`data/chroma_db`),(!be||be===`http://localhost:6333`)&&xe(`http://localhost:8000`))},ht=e=>{_e(e),e===`embedded`&&!ve&&ye(me===`chroma`?`data/chroma_db`:`data/qdrant_db`),e===`remote`&&!be&&xe(me===`chroma`?`http://localhost:8000`:`http://localhost:6333`)},gt=async()=>{Te(!0),De(null);try{let e={provider:me,mode:ge,storage_path:ge===`embedded`?ve.trim():null,url:ge===`remote`?be.trim():null,collection:Se.trim()||`knowledge_rag_v1`},t=await fetch(`/admin/api/vector-store/test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}),n=await t.json();if(!t.ok||!n.success){let e=n.message||n.error||`Vector store connection test failed`;De({success:!1,message:e}),I.error(`Vector store test: `+e)}else{let e=n.message||`Vector store connection test successful`;De({success:!0,message:e}),I.success(e)}}catch(e){let t=e.message||`Connection error`;De({success:!1,message:t}),I.error(`Vector store test error: `+t)}finally{Te(!1)}},_t=async()=>{let e=me===`chroma`?`ChromaDB`:`Qdrant`,n=ge===`embedded`?`Embedded Disk`:`Remote Server`;if(window.confirm(`Switch active vector database backend to ${e} (${n})? This will update settings and trigger a full re-indexing of all sources.`)){ke(!0);try{let n={provider:me,mode:ge,storage_path:ge===`embedded`?ve.trim():null,url:ge===`remote`?be.trim():null,collection:Se.trim()||`knowledge_rag_v1`},r=await fetch(`/admin/api/vector-store/switch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(n)}),i=await r.json();if(!r.ok||i.status===`error`){let e=i.error||i.message||`Failed to switch vector database backend`;De({success:!1,message:e}),I.error(`Switch error: `+e)}else{let n=i.message||`Switched vector backend to ${e}`;De({success:!0,message:n}),I.success(n),await at(),t()}}catch(e){De({success:!1,message:e.message}),I.error(`Switch error: `+e.message)}finally{ke(!1)}}},vt=async(e,n,i)=>{if(n.trim())try{let o=await fetch(`/admin/api/settings/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({[e]:n.trim()})}),c=await o.json();if(!o.ok)throw Error(c.error||`Failed to save token`);I.success(`${i} token saved successfully.`),e===`github_token`&&r(``),e===`gitlab_token`&&a(``),e===`gitea_token`&&s(``),t()}catch(e){I.error(`Error saving ${i} token: `+e.message)}},yt=async(e,n)=>{if(window.confirm(`Clear the stored ${n} token from database?`))try{let r=await fetch(`/admin/api/settings/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({[e]:``})});if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error||`Failed to clear token`)}I.success(`${n} token cleared`),t()}catch(e){I.error(`Failed to clear ${n} token: `+e.message)}},bt=async e=>{if(e.preventDefault(),!(!A.trim()||!se.trim())){le(!0);try{let e=await fetch(`/admin/api/settings/hosts`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({host:A.trim(),provider:ne,auth_user:ae.trim()||null,auth_token:se.trim()})}),t=await e.json();if(!e.ok)throw Error(t.error||`Failed to save host credential`);I.success(`Host credential for '${A.trim()}' saved`),ee(!1),te(``),re(`gitlab`),oe(``),P(``),it()}catch(e){I.error(`Error: `+e.message)}finally{le(!1)}}},xt=async(e,t)=>{if(window.confirm(`Remove stored credentials for host '${t}'?`))try{let n=await fetch(`/admin/api/settings/hosts/${e}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to delete`)}I.success(`Removed credentials for '${t}'`),it()}catch(e){I.error(`Failed to remove: `+e.message)}},St=e?.providers_auth?.github||{token_source:e?.token_source||`None`,masked_token:e?.masked_token||`None`},Ct=e?.providers_auth?.gitlab||{token_source:`None`,masked_token:`None`},wt=e?.providers_auth?.gitea||{token_source:`None`,masked_token:`None`};return(0,b.jsxs)(`div`,{className:`tab-content active`,style:{display:`flex`,flexDirection:`column`,gap:`24px`},children:[(0,b.jsx)(ce,{}),(0,b.jsx)(ie,{vectorStore:ue,isLoadingVs:fe,testFeedback:Ee,vsProvider:me,vsMode:ge,vsStoragePath:ve,setVsStoragePath:ye,vsUrl:be,setVsUrl:xe,vsCollection:Se,setVsCollection:Ce,isTestingVs:we,isSwitchingVs:Oe,onProviderChange:mt,onModeChange:ht,onTestConnection:gt,onSwitchBackend:_t}),(0,b.jsx)(j,{embeddingConfig:Ae,isLoadingEmb:Me,isSavingEmb:Pe,embProvider:Ie,setEmbProvider:Le,embThreads:Re,setEmbThreads:ze,embBatchSize:Be,setEmbBatchSize:Ve,embDenseModel:He,setEmbDenseModel:Ue,embSparseModel:We,setEmbSparseModel:Ge,embLitellmUrl:Ke,setEmbLitellmUrl:qe,embLitellmApiKey:Je,setEmbLitellmApiKey:Ye,embVisionOcrModel:Xe,setEmbVisionOcrModel:Ze,embChatModel:Qe,setEmbChatModel:$e,discoveryResult:et,isDiscovering:nt,onDiscoverModels:ct,onSaveEmbeddingSettings:lt}),(0,b.jsx)(M,{isLoadingAutoSync:y,intervalMins:u,setIntervalMins:d,hasGlobalSecret:m,showWebhookSecret:T,setShowWebhookSecret:E,webhookSecret:f,setWebhookSecret:p,fullWebhookUrl:ut,copiedWebhookUrl:D,isSavingAutoSync:C,onSaveAutoSync:ft,onClearWebhookSecret:pt,onCopyWebhookUrl:dt}),(0,b.jsx)(N,{stats:e,ghAuth:St,glAuth:Ct,gtAuth:wt,ghToken:n,setGhToken:r,glToken:i,setGlToken:a,gtToken:o,setGtToken:s,hostCredentials:c,isHostModalOpen:k,setIsHostModalOpen:ee,newHost:A,setNewHost:te,newHostProvider:ne,setNewHostProvider:re,newHostUser:ae,setNewHostUser:oe,newHostToken:se,setNewHostToken:P,isSavingHost:F,onSaveToken:vt,onClearToken:yt,onSaveHostCredential:bt,onDeleteHostCredential:xt})]})}function ue(){let e=S(),[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(`ALL`),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(!0),[d,f]=(0,_.useState)(new Set),p=(0,_.useRef)(null),m=(0,_.useRef)(null),h=(0,_.useCallback)(async()=>{i(!0);try{let e=await fetch(`/admin/api/logs`);if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();n(Array.isArray(t)?t:[])}catch(t){e.error(`Failed to load diagnostics logs: ${t.message}`)}finally{i(!1)}},[e]);(0,_.useEffect)(()=>{h();let e=setInterval(h,8e3);return()=>clearInterval(e)},[h]),(0,_.useEffect)(()=>{l&&m.current&&(m.current.scrollTop=m.current.scrollHeight)},[t,l]);let g=async()=>{if(window.confirm(`Are you sure you want to clear all server diagnostics logs?`))try{let t=await fetch(`/admin/api/logs`,{method:`DELETE`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error||`HTTP ${t.status}`)}n([]),f(new Set),e.success(`Diagnostics logs cleared.`)}catch(t){e.error(`Failed to clear logs: ${t.message}`)}},v=e=>{f(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},y=e=>{switch(e.toUpperCase()){case`ERROR`:return`badge badge-danger`;case`WARNING`:return`badge badge-warning`;case`INFO`:return`badge badge-primary`;case`DEBUG`:return`badge badge-secondary`;default:return`badge badge-secondary`}},x=t.filter(e=>{if(a!==`ALL`&&e.level.toUpperCase()!==a)return!1;if(s.trim()){let t=s.toLowerCase(),n=e.message?.toLowerCase().includes(t),r=e.logger?.toLowerCase().includes(t),i=e.traceback?.toLowerCase().includes(t),a=e.level?.toLowerCase().includes(t);if(!n&&!r&&!i&&!a)return!1}return!0}),C={ALL:t.length,INFO:t.filter(e=>e.level===`INFO`).length,WARNING:t.filter(e=>e.level===`WARNING`).length,ERROR:t.filter(e=>e.level===`ERROR`).length,DEBUG:t.filter(e=>e.level===`DEBUG`).length};return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card log-viewer-container`,children:[(0,b.jsxs)(`div`,{className:`log-viewer-header`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Diagnostics & Server Logs`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Inspect real-time server runtime events, tree-sitter AST parsing, background indexing, and MCP tool traces.`})]}),(0,b.jsxs)(`div`,{className:`log-viewer-actions`,children:[(0,b.jsxs)(`label`,{className:`log-autoscroll-label`,children:[(0,b.jsx)(`input`,{type:`checkbox`,checked:l,onChange:e=>u(e.target.checked)}),`Auto-scroll`]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:h,disabled:r,title:`Refresh logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-rotate ${r?`fa-spin`:``}`}),` Refresh`]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-danger`,onClick:g,title:`Clear all logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Clear Logs`]})]})]}),(0,b.jsxs)(`div`,{className:`log-toolbar`,children:[(0,b.jsx)(`div`,{className:`log-filter-pills`,children:[`ALL`,`INFO`,`WARNING`,`ERROR`,`DEBUG`].map(e=>(0,b.jsxs)(`button`,{type:`button`,className:`log-filter-btn ${a===e?`active`:``} ${e.toLowerCase()}`,onClick:()=>o(e),children:[e,` `,(0,b.jsx)(`span`,{className:`pill-count`,children:C[e]})]},e))}),(0,b.jsxs)(`div`,{className:`log-search-wrapper`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass search-icon`}),(0,b.jsx)(`input`,{type:`text`,className:`log-search-input`,placeholder:`Search logs by message, logger, or traceback...`,value:s,onChange:e=>c(e.target.value)}),s&&(0,b.jsx)(`button`,{type:`button`,className:`clear-search-btn`,onClick:()=>c(``),title:`Clear search`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-xmark`})})]})]}),(0,b.jsx)(`div`,{className:`log-stream-container`,ref:m,children:x.length===0?(0,b.jsxs)(`div`,{className:`empty-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-info`,style:{fontSize:`2rem`,marginBottom:`12px`,opacity:.5}}),(0,b.jsxs)(`p`,{children:[`No logs available `,s||a!==`ALL`?`matching current filter`:``,`.`]})]}):(0,b.jsxs)(`div`,{className:`log-stream-list`,children:[x.map((e,t)=>{let n=!!e.traceback,r=d.has(t);return(0,b.jsxs)(`div`,{className:`log-entry log-level-${e.level.toLowerCase()} ${n?`has-traceback`:``}`,children:[(0,b.jsxs)(`div`,{className:`log-entry-main`,children:[(0,b.jsx)(`span`,{className:`log-timestamp`,children:e.timestamp}),(0,b.jsx)(`span`,{className:y(e.level),children:e.level}),(0,b.jsx)(`span`,{className:`log-logger code`,children:e.logger}),(0,b.jsx)(`span`,{className:`log-message`,children:e.message}),n&&(0,b.jsxs)(`button`,{type:`button`,className:`btn-traceback-toggle`,onClick:()=>v(t),title:`Toggle traceback details`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${r?`fa-chevron-down`:`fa-chevron-right`}`}),(0,b.jsx)(`span`,{children:r?`Hide Stack Trace`:`View Stack Trace`})]})]}),n&&r&&(0,b.jsx)(`div`,{className:`log-traceback-wrapper`,children:(0,b.jsx)(`pre`,{className:`traceback-box`,children:e.traceback})})]},`${e.timestamp}-${t}`)}),(0,b.jsx)(`div`,{ref:p})]})})]})})}var de=({repos:e,selectedRepo:t,onSelectRepo:n,density:r,onChangeDensity:i,searchQuery:a=``,onSearchChange:o,totalFiles:s=0,totalSymbols:c=0,onRefresh:l,loading:u=!1})=>(0,b.jsxs)(`div`,{className:`nav-toolbar`,"data-testid":`navigator-toolbar`,children:[(0,b.jsxs)(`div`,{className:`nav-toolbar-left`,children:[(0,b.jsxs)(`div`,{className:`nav-repo-selector-wrapper`,children:[(0,b.jsx)(`label`,{htmlFor:`nav-repo-select`,className:`nav-repo-label`,children:`Repository:`}),(0,b.jsxs)(`select`,{id:`nav-repo-select`,"aria-label":`Repository`,className:`nav-repo-select`,value:t,onChange:e=>n(e.target.value),disabled:u,children:[(0,b.jsx)(`option`,{value:`__all__`,children:`All Repositories (__all__)`}),e.filter(e=>e.name!==`__all__`).map(e=>(0,b.jsx)(`option`,{value:e.name,children:e.name},e.id??e.name))]})]}),(0,b.jsxs)(`div`,{className:`nav-stats-badges`,children:[(0,b.jsxs)(`span`,{className:`nav-stat-badge`,title:`Total Indexed Files`,children:[(0,b.jsx)(`span`,{className:`stat-num`,children:s}),` files`]}),(0,b.jsxs)(`span`,{className:`nav-stat-badge`,title:`Total Extracted AST Symbols`,children:[(0,b.jsx)(`span`,{className:`stat-num`,children:c}),` symbols`]})]})]}),(0,b.jsx)(`div`,{className:`nav-toolbar-center`,children:o&&(0,b.jsxs)(`div`,{className:`nav-global-search`,children:[(0,b.jsxs)(`svg`,{className:`search-icon`,width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,b.jsx)(`circle`,{cx:`11`,cy:`11`,r:`8`}),(0,b.jsx)(`line`,{x1:`21`,y1:`21`,x2:`16.65`,y2:`16.65`})]}),(0,b.jsx)(`input`,{type:`text`,className:`nav-search-input`,placeholder:`Search files (Ctrl+P / /)...`,value:a,onChange:e=>o(e.target.value),"aria-label":`Quick search files`}),a&&(0,b.jsx)(`button`,{type:`button`,className:`nav-search-clear-btn`,onClick:()=>o(``),"aria-label":`Clear search`,children:`✕`})]})}),(0,b.jsxs)(`div`,{className:`nav-toolbar-right`,children:[(0,b.jsxs)(`div`,{className:`nav-density-switcher`,role:`group`,"aria-label":`Density mode`,children:[(0,b.jsx)(`span`,{className:`density-label`,children:`Density:`}),(0,b.jsx)(`button`,{type:`button`,className:`density-btn ${r===`compact`?`active`:``}`,onClick:()=>i(`compact`),title:`Compact (20px rows - IDE mode)`,"aria-pressed":r===`compact`,children:`Compact`}),(0,b.jsx)(`button`,{type:`button`,className:`density-btn ${r===`balanced`?`active`:``}`,onClick:()=>i(`balanced`),title:`Balanced (28px rows - Default)`,"aria-pressed":r===`balanced`,children:`Balanced`}),(0,b.jsx)(`button`,{type:`button`,className:`density-btn ${r===`spacious`?`active`:``}`,onClick:()=>i(`spacious`),title:`Spacious (36px rows - Cards)`,"aria-pressed":r===`spacious`,children:`Spacious`})]}),l&&(0,b.jsx)(`button`,{type:`button`,className:`nav-refresh-btn ${u?`spinning`:``}`,onClick:l,title:`Refresh codebase tree`,disabled:u,"aria-label":`Refresh codebase tree`,children:(0,b.jsx)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,b.jsx)(`path`,{d:`M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67`})})})]})]});function fe(e,t){let n=e.toLowerCase();return n.endsWith(`.py`)||t===`python`?{icon:`🐍`,className:`icon-py`}:n.endsWith(`.tsx`)||n.endsWith(`.ts`)||t===`typescript`?{icon:`⚡`,className:`icon-ts`}:n.endsWith(`.jsx`)||n.endsWith(`.js`)||n.endsWith(`.mjs`)||t===`javascript`?{icon:`📜`,className:`icon-js`}:n.endsWith(`.go`)||t===`go`?{icon:`🔷`,className:`icon-go`}:n.endsWith(`.rs`)||t===`rust`?{icon:`🦀`,className:`icon-rs`}:n.endsWith(`.json`)?{icon:`📄`,className:`icon-json`}:n.endsWith(`.md`)||n.endsWith(`.markdown`)?{icon:`📝`,className:`icon-md`}:n.endsWith(`.css`)||n.endsWith(`.scss`)?{icon:`🎨`,className:`icon-css`}:n.endsWith(`.sql`)?{icon:`🗄️`,className:`icon-sql`}:n.endsWith(`.yaml`)||n.endsWith(`.yml`)||n.endsWith(`.toml`)?{icon:`⚙️`,className:`icon-yaml`}:{icon:`📄`,className:`icon-file`}}var pe=({nodes:e,selectedPath:t,onSelectFile:n,filterText:r,onFilterChange:i,density:a=`balanced`,loading:o=!1})=>{let[s,c]=(0,_.useState)(``),l=r===void 0?s:r,u=i||c,[d,f]=(0,_.useState)(new Set),[p,m]=(0,_.useState)(-1),h=(0,_.useRef)(null),g=(0,_.useCallback)(e=>{let t=[],n=e=>{if(!(!e||!Array.isArray(e)))for(let r of e)r&&r.is_dir&&(t.push(r.id),Array.isArray(r.children)&&n(r.children))};return n(e),t},[]),v=(0,_.useCallback)((e,t)=>{if(!e||!Array.isArray(e))return{filteredNodes:[],matchedDirIds:new Set};let n=t.toLowerCase().trim(),r=new Set,i=e=>{if(!e)return null;let t=(e.name||``).toLowerCase().includes(n)||(e.path||``).toLowerCase().includes(n);if(e.is_dir){let n=Array.isArray(e.children)?e.children:[],a=n.map(i).filter(e=>e!==null);return a.length>0||t?(r.add(e.id),{...e,children:a.length>0?a:n}):null}return t?e:null};return{filteredNodes:e.map(i).filter(e=>e!==null),matchedDirIds:r}},[]),{filteredNodes:y,matchedDirIds:x}=(0,_.useMemo)(()=>l.trim()?v(e,l):{filteredNodes:Array.isArray(e)?e:[],matchedDirIds:new Set},[e,l,v]);(0,_.useEffect)(()=>{l.trim()&&f(e=>{let t=new Set(e);return x.forEach(e=>t.add(e)),t})},[l,x]),(0,_.useEffect)(()=>{if(t){let e=t.split(`/`),n=[];for(let t=1;t0&&f(e=>{let t=new Set(e);return n.forEach(e=>t.add(e)),t})}},[t]);let S=(0,_.useCallback)(e=>{f(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),C=(0,_.useCallback)(()=>{let t=g(e);f(new Set(t))},[e,g]),w=(0,_.useCallback)(()=>{f(new Set)},[]),T=(0,_.useMemo)(()=>{let e=[],t=!!l.trim(),n=(r,i)=>{if(!(!r||!Array.isArray(r)))for(let a of r){if(!a)continue;let r=!!(a.is_dir&&Array.isArray(a.children)&&a.children.length>0),o=d.has(a.id)||t&&x.has(a.id);e.push({node:a,depth:i,isExpanded:o,hasChildren:r}),a.is_dir&&o&&Array.isArray(a.children)&&n(a.children,i+1)}};return n(y,0),e},[y,d,l,x]);return(0,b.jsxs)(`div`,{className:`nav-tree-pane density-${a}`,"data-testid":`navigator-tree-container`,tabIndex:0,ref:h,onKeyDown:e=>{if(T.length!==0){if(e.key===`ArrowDown`)e.preventDefault(),m(e=>ee>0?e-1:T.length-1);else if(e.key===`ArrowRight`){if(e.preventDefault(),p>=0&&p=0&&p=0&&pu(e.target.value)}),l&&(0,b.jsx)(`button`,{type:`button`,className:`nav-tree-clear-btn`,onClick:()=>u(``),"aria-label":`Clear filter`,children:`✕`})]})]}),(0,b.jsx)(`div`,{className:`nav-tree-content`,children:o?(0,b.jsxs)(`div`,{className:`nav-loading-wrapper`,"data-testid":`tree-loading-spinner`,children:[(0,b.jsx)(`div`,{className:`nav-spinner`}),(0,b.jsx)(`span`,{children:`Loading codebase tree...`})]}):T.length===0?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`p`,{children:`No matching files found`}),l&&(0,b.jsx)(`button`,{type:`button`,className:`nav-clear-filter-btn`,onClick:()=>u(``),children:`Clear filter`})]}):(0,b.jsx)(`div`,{className:`nav-tree-list`,role:`tree`,children:T.map((e,r)=>{let{node:i,depth:a,isExpanded:o}=e,s=!i.is_dir&&i.path===t,c=r===p,{icon:l,className:u}=i.is_dir?{icon:o?`📂`:`📁`,className:`icon-dir`}:fe(i.name,i.language);return(0,b.jsxs)(`div`,{role:`treeitem`,"aria-expanded":i.is_dir?o:void 0,"aria-selected":s,className:`nav-tree-item ${i.is_dir?`dir-item`:`file-item`} ${s?`selected`:``} ${c?`focused`:``}`,style:{paddingLeft:`${a*14+10}px`},onClick:()=>{m(r),i.is_dir?S(i.id):n(i)},children:[(0,b.jsx)(`span`,{className:`tree-chevron`,children:i.is_dir?(0,b.jsx)(`span`,{className:`chevron-arrow ${o?`open`:``}`,children:`▶`}):(0,b.jsx)(`span`,{className:`chevron-spacer`})}),(0,b.jsx)(`span`,{className:`tree-icon ${u}`,"aria-hidden":`true`,children:l}),(0,b.jsx)(`span`,{className:`tree-label`,title:i.path,children:i.name}),(0,b.jsxs)(`div`,{className:`tree-badges`,children:[i.symbol_count>0&&(0,b.jsxs)(`span`,{className:`badge-symbols`,title:`${i.symbol_count} AST Symbols`,children:[i.symbol_count,` sym`]}),i.route_count>0&&(0,b.jsxs)(`span`,{className:`badge-routes`,title:`${i.route_count} API Routes`,children:[i.route_count,` rts`]})]})]},i.id)})})})]})};function me(e){switch(e.toUpperCase()){case`GET`:return`method-get`;case`POST`:return`method-post`;case`PUT`:return`method-put`;case`DELETE`:return`method-delete`;case`PATCH`:return`method-patch`;default:return`method-other`}}function he(e){switch(e.toLowerCase()){case`class`:return`kind-class`;case`function`:case`method`:case`async function`:return`kind-function`;case`variable`:case`constant`:return`kind-variable`;case`interface`:case`type`:return`kind-type`;default:return`kind-default`}}var ge=({outline:e,selectedSymbolId:t,onSelectSymbol:n,density:r=`balanced`,loading:i=!1})=>{let[a,o]=(0,_.useState)(`all`),[s,c]=(0,_.useState)(``),l=e?.symbols||[],u=(0,_.useMemo)(()=>{let e=0,t=0,n=0;for(let r of l){r.route&&e++;let i=r.kind.toLowerCase();i===`class`||i===`interface`?t++:(i.includes(`func`)||i===`method`)&&(r.route||n++)}return{all:l.length,routes:e,classes:t,functions:n}},[l]),d=(0,_.useMemo)(()=>l.filter(e=>{if(a===`routes`){if(!e.route)return!1}else if(a===`classes`){let t=e.kind.toLowerCase();if(t!==`class`&&t!==`interface`)return!1}else if(a===`functions`){let t=e.kind.toLowerCase();if(!t.includes(`func`)&&t!==`method`||e.route)return!1}if(s.trim()){let t=s.toLowerCase(),n=e.name.toLowerCase().includes(t),r=(e.signature||``).toLowerCase().includes(t),i=e.route?e.route.path_pattern.toLowerCase().includes(t)||e.route.http_method.toLowerCase().includes(t):!1;if(!n&&!r&&!i)return!1}return!0}),[l,a,s]),f=e?.filepath?e.filepath.split(`/`).pop():``;return(0,b.jsxs)(`div`,{className:`nav-outline-pane density-${r}`,"data-testid":`navigator-outline-container`,children:[(0,b.jsxs)(`div`,{className:`nav-outline-header`,children:[(0,b.jsxs)(`div`,{className:`nav-outline-title-row`,children:[(0,b.jsxs)(`div`,{className:`nav-outline-title`,children:[(0,b.jsxs)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,b.jsx)(`line`,{x1:`8`,y1:`6`,x2:`21`,y2:`6`}),(0,b.jsx)(`line`,{x1:`8`,y1:`12`,x2:`21`,y2:`12`}),(0,b.jsx)(`line`,{x1:`8`,y1:`18`,x2:`21`,y2:`18`}),(0,b.jsx)(`line`,{x1:`3`,y1:`6`,x2:`3.01`,y2:`6`}),(0,b.jsx)(`line`,{x1:`3`,y1:`12`,x2:`3.01`,y2:`12`}),(0,b.jsx)(`line`,{x1:`3`,y1:`18`,x2:`3.01`,y2:`18`})]}),(0,b.jsx)(`span`,{children:`Symbols & Routes`})]}),e&&(0,b.jsx)(`div`,{className:`nav-file-badge`,title:e.filepath,children:(0,b.jsx)(`span`,{className:`file-name`,children:f})})]}),e&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`nav-outline-search-bar`,children:[(0,b.jsxs)(`svg`,{className:`search-icon`,width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`circle`,{cx:`11`,cy:`11`,r:`8`}),(0,b.jsx)(`line`,{x1:`21`,y1:`21`,x2:`16.65`,y2:`16.65`})]}),(0,b.jsx)(`input`,{type:`text`,className:`nav-outline-search-input`,placeholder:`Filter symbols...`,value:s,onChange:e=>c(e.target.value)}),s&&(0,b.jsx)(`button`,{type:`button`,className:`nav-outline-clear-btn`,onClick:()=>c(``),"aria-label":`Clear symbol search`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`nav-category-chips`,role:`tablist`,"aria-label":`Symbol Category Filter`,children:[(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`all`?`active`:``}`,onClick:()=>o(`all`),children:[`All `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.all})]}),(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`routes`?`active`:``}`,onClick:()=>o(`routes`),children:[`Routes `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.routes})]}),(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`classes`?`active`:``}`,onClick:()=>o(`classes`),children:[`Classes `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.classes})]}),(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`functions`?`active`:``}`,onClick:()=>o(`functions`),children:[`Functions `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.functions})]})]})]})]}),(0,b.jsx)(`div`,{className:`nav-outline-content`,children:i?(0,b.jsxs)(`div`,{className:`nav-outline-skeleton`,"data-testid":`outline-loading-skeleton`,children:[(0,b.jsx)(`div`,{className:`skeleton-item shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-item shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-item shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-item shimmer`})]}):e?l.length===0?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`div`,{className:`empty-icon`,children:`⚡`}),(0,b.jsx)(`h4`,{children:`No Symbols Found`}),(0,b.jsx)(`p`,{children:`No symbols found in this file.`})]}):d.length===0?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`h4`,{children:`No Matching Symbols`}),(0,b.jsx)(`p`,{children:`No symbols match the current category and search filters.`}),(0,b.jsx)(`button`,{type:`button`,className:`nav-clear-filter-btn`,onClick:()=>{o(`all`),c(``)},children:`Reset Filters`})]}):(0,b.jsx)(`div`,{className:`nav-symbol-list`,role:`list`,children:d.map(e=>{let r=e.id===t,i=he(e.kind);return(0,b.jsxs)(`div`,{"data-testid":`symbol-item-${e.id}`,className:`nav-symbol-item ${r?`active`:``}`,onClick:()=>n(e),role:`listitem`,tabIndex:0,onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),n(e))},children:[(0,b.jsxs)(`div`,{className:`symbol-header-row`,children:[(0,b.jsxs)(`div`,{className:`symbol-name-col`,children:[(0,b.jsx)(`span`,{className:`symbol-kind-badge ${i}`,children:e.kind}),(0,b.jsx)(`span`,{className:`symbol-name-text`,title:e.full_symbol||e.name,children:e.name})]}),(0,b.jsx)(`div`,{className:`symbol-meta-col`,children:(0,b.jsxs)(`span`,{className:`symbol-line-badge`,children:[`L`,e.start_line,e.end_line&&e.end_line!==e.start_line?` - L${e.end_line}`:``]})})]}),e.route&&(0,b.jsxs)(`div`,{className:`symbol-route-row`,children:[(0,b.jsx)(`span`,{className:`route-method-badge ${me(e.route.http_method)}`,children:e.route.http_method}),(0,b.jsx)(`span`,{className:`route-path-text`,title:e.route.path_pattern,children:e.route.path_pattern}),e.route.framework&&(0,b.jsx)(`span`,{className:`route-framework-tag`,children:e.route.framework})]}),e.signature&&(0,b.jsx)(`div`,{className:`symbol-signature-snippet`,children:(0,b.jsx)(`code`,{children:e.signature})})]},e.id)})}):(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`div`,{className:`empty-icon`,children:`📂`}),(0,b.jsx)(`h4`,{children:`No File Selected`}),(0,b.jsx)(`p`,{children:`Select a file from the tree to inspect its symbols and routes.`})]})})]})},_e=({impact:e,onSelectCaller:t,onSelectCallee:n,density:r=`balanced`,loading:i=!1})=>{let[a,o]=(0,_.useState)(!1),s=async()=>{if(!e?.symbol)return;let{filepath:t,start_line:n,end_line:r}=e.symbol,i=`${t}#L${n}${r&&r!==n?`-L${r}`:``}`;try{navigator?.clipboard?.writeText&&await navigator.clipboard.writeText(i),o(!0),setTimeout(()=>o(!1),2e3)}catch{}},c=e?.symbol,l=e?.route,u=e?.callers||[],d=e?.callees||[],f=e?.imports||[];return(0,b.jsxs)(`div`,{className:`nav-inspector-pane density-${r}`,"data-testid":`navigator-inspector-container`,children:[(0,b.jsxs)(`div`,{className:`nav-inspector-header`,children:[(0,b.jsxs)(`div`,{className:`nav-inspector-title`,children:[(0,b.jsxs)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,b.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,b.jsx)(`path`,{d:`M12 16v-4M12 8h.01`})]}),(0,b.jsx)(`span`,{children:`Code Intelligence & Impact`})]}),c&&(0,b.jsx)(`button`,{type:`button`,className:`nav-copy-permalink-btn`,onClick:s,title:`Copy file path & line range permalink`,"aria-label":`Copy Permalink`,children:a?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:(0,b.jsx)(`polyline`,{points:`20 6 9 17 4 12`})}),(0,b.jsx)(`span`,{children:`Copied!`})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`path`,{d:`M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71`}),(0,b.jsx)(`path`,{d:`M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71`})]}),(0,b.jsx)(`span`,{children:`Copy Permalink`})]})})]}),(0,b.jsx)(`div`,{className:`nav-inspector-content`,children:i?(0,b.jsxs)(`div`,{className:`nav-inspector-skeleton`,"data-testid":`inspector-loading-skeleton`,children:[(0,b.jsx)(`div`,{className:`skeleton-header shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-metrics shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-block shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-block shimmer`})]}):!e||!c?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`div`,{className:`empty-icon`,children:`🔍`}),(0,b.jsx)(`h4`,{children:`No Symbol Selected`}),(0,b.jsx)(`p`,{children:`Select a symbol from the outline to inspect its callers, dependencies, and impact.`})]}):(0,b.jsxs)(`div`,{className:`nav-inspector-body`,children:[(0,b.jsxs)(`div`,{className:`inspector-card symbol-summary-card`,children:[(0,b.jsxs)(`div`,{className:`summary-title-row`,children:[(0,b.jsx)(`span`,{className:`symbol-kind-badge ${he(c.kind)}`,children:c.kind}),(0,b.jsx)(`h3`,{className:`summary-name`,title:c.full_symbol||c.name,children:c.name})]}),(0,b.jsxs)(`div`,{className:`summary-location-row`,children:[(0,b.jsxs)(`span`,{className:`summary-file-path`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`path`,{d:`M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z`}),(0,b.jsx)(`polyline`,{points:`13 2 13 9 20 9`})]}),c.filepath]}),(0,b.jsxs)(`span`,{className:`summary-line-range`,children:[`L`,c.start_line,` - L`,c.end_line]})]})]}),(0,b.jsxs)(`div`,{className:`inspector-metrics-grid`,children:[(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Incoming Callers`}),(0,b.jsx)(`span`,{className:`metric-value`,"data-testid":`metric-callers`,children:u.length})]}),(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Outgoing Callees`}),(0,b.jsx)(`span`,{className:`metric-value`,"data-testid":`metric-callees`,children:d.length})]}),(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Total Imports`}),(0,b.jsx)(`span`,{className:`metric-value`,"data-testid":`metric-imports`,children:f.length})]}),(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Language`}),(0,b.jsx)(`span`,{className:`metric-value metric-lang`,"data-testid":`metric-scope`,children:c.language||`code`})]})]}),l&&(0,b.jsxs)(`div`,{className:`inspector-card route-card`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,b.jsx)(`line`,{x1:`2`,y1:`12`,x2:`22`,y2:`12`}),(0,b.jsx)(`path`,{d:`M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z`})]}),(0,b.jsx)(`span`,{children:`API Route Mapping`})]}),(0,b.jsxs)(`div`,{className:`route-detail-row`,children:[(0,b.jsx)(`span`,{className:`route-method-badge ${me(l.http_method)}`,children:l.http_method}),(0,b.jsx)(`span`,{className:`route-path-code`,children:l.path_pattern}),l.framework&&(0,b.jsx)(`span`,{className:`route-framework-tag`,children:l.framework})]})]}),c.signature&&(0,b.jsxs)(`div`,{className:`inspector-card code-preview-card`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`polyline`,{points:`16 18 22 12 16 6`}),(0,b.jsx)(`polyline`,{points:`8 6 2 12 8 18`})]}),(0,b.jsx)(`span`,{children:`Signature`})]}),(0,b.jsx)(`pre`,{className:`signature-code-block`,children:(0,b.jsx)(`code`,{children:c.signature})})]}),c.docstring&&(0,b.jsxs)(`div`,{className:`inspector-card docstring-card`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),(0,b.jsx)(`polyline`,{points:`14 2 14 8 20 8`}),(0,b.jsx)(`line`,{x1:`16`,y1:`13`,x2:`8`,y2:`13`}),(0,b.jsx)(`line`,{x1:`16`,y1:`17`,x2:`8`,y2:`17`}),(0,b.jsx)(`polyline`,{points:`10 9 9 9 8 9`})]}),(0,b.jsx)(`span`,{children:`Documentation`})]}),(0,b.jsx)(`p`,{className:`docstring-text`,children:c.docstring})]}),(0,b.jsxs)(`div`,{className:`inspector-card relations-card callers-section`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:(0,b.jsx)(`path`,{d:`M12 19V5M5 12l7-7 7 7`})}),(0,b.jsxs)(`span`,{children:[`Incoming Callers (`,u.length,`)`]})]}),u.length===0?(0,b.jsx)(`div`,{className:`nav-no-items-text`,children:`No incoming callers found in this repository.`}):(0,b.jsx)(`div`,{className:`relation-list`,children:u.map((e,n)=>(0,b.jsxs)(`div`,{"data-testid":`caller-item-${e.id??n}`,className:`relation-item caller-item`,onClick:()=>{e.source_filepath&&t&&t(e.source_filepath,e.source_symbol,e.source_symbol_id??void 0)},role:`button`,tabIndex:0,title:`Jump to ${e.source_symbol||`caller`} in ${e.source_filepath||``}`,children:[(0,b.jsxs)(`div`,{className:`relation-top`,children:[(0,b.jsx)(`span`,{className:`rel-symbol-name`,children:e.source_symbol||`Unknown Caller`}),(0,b.jsx)(`span`,{className:`rel-jump-hint`,"aria-hidden":`true`,children:`Jump ↗`})]}),(0,b.jsxs)(`div`,{className:`relation-bottom`,children:[e.source_filepath&&(0,b.jsx)(`span`,{className:`rel-filepath`,children:e.source_filepath}),e.all_lines?(0,b.jsxs)(`span`,{className:`rel-line`,title:`Lines: ${e.all_lines}`,children:[`L`,e.all_lines.includes(`,`)?e.all_lines.split(`,`).slice(0,3).join(`, L`)+(e.all_lines.split(`,`).length>3?`...`:``):e.all_lines]}):e.line_number?(0,b.jsxs)(`span`,{className:`rel-line`,children:[`L`,e.line_number]}):null,e.call_count&&e.call_count>1?(0,b.jsxs)(`span`,{className:`rel-count-badge`,children:[e.call_count,` calls`]}):null,e.relationship_type&&(0,b.jsx)(`span`,{className:`rel-type-tag`,children:e.relationship_type})]})]},e.id??n))})]}),(0,b.jsxs)(`div`,{className:`inspector-card relations-card dependencies-section`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:(0,b.jsx)(`path`,{d:`M12 5v14M5 12l7 7 7-7`})}),(0,b.jsxs)(`span`,{children:[`Outgoing Dependencies (`,d.length+f.length,`)`]})]}),d.length===0&&f.length===0?(0,b.jsx)(`div`,{className:`nav-no-items-text`,children:`No outgoing calls or imports.`}):(0,b.jsxs)(`div`,{className:`relation-list`,children:[d.map((e,t)=>(0,b.jsxs)(`div`,{"data-testid":`callee-item-${e.id??t}`,className:`relation-item callee-item ${e.target_filepath?`is-clickable`:``}`,onClick:()=>{e.target_filepath&&n&&n(e.target_filepath,e.target_symbol)},role:e.target_filepath?`button`:void 0,tabIndex:e.target_filepath?0:void 0,title:e.target_filepath?`Jump to ${e.target_symbol} in ${e.target_filepath}`:void 0,onKeyDown:t=>{e.target_filepath&&n&&(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),n(e.target_filepath,e.target_symbol))},children:[(0,b.jsxs)(`div`,{className:`relation-top`,children:[(0,b.jsx)(`span`,{className:`rel-symbol-name`,children:e.target_symbol}),(0,b.jsxs)(`div`,{className:`rel-top-right`,children:[(0,b.jsx)(`span`,{className:`rel-type-badge`,children:e.relationship_type||`CALLS`}),e.target_filepath&&(0,b.jsx)(`span`,{className:`rel-jump-hint`,"aria-hidden":`true`,children:`Jump ↗`})]})]}),(0,b.jsxs)(`div`,{className:`relation-bottom`,children:[e.target_filepath&&(0,b.jsx)(`span`,{className:`rel-filepath`,children:e.target_filepath}),e.all_lines?(0,b.jsxs)(`span`,{className:`rel-line`,title:`Lines: ${e.all_lines}`,children:[`L`,e.all_lines.includes(`,`)?e.all_lines.split(`,`).slice(0,3).join(`, L`)+(e.all_lines.split(`,`).length>3?`...`:``):e.all_lines]}):e.line_number?(0,b.jsxs)(`span`,{className:`rel-line`,children:[`L`,e.line_number]}):null,e.call_count&&e.call_count>1?(0,b.jsxs)(`span`,{className:`rel-count-badge`,children:[e.call_count,` calls`]}):null]})]},e.id??`callee-${t}`)),f.map((e,t)=>(0,b.jsxs)(`div`,{className:`relation-item import-item`,children:[(0,b.jsxs)(`div`,{className:`relation-top`,children:[(0,b.jsx)(`span`,{className:`rel-symbol-name`,children:e.target_symbol}),(0,b.jsx)(`span`,{className:`rel-type-badge import-badge`,children:`IMPORTS`})]}),(0,b.jsxs)(`div`,{className:`relation-bottom`,children:[e.all_lines?(0,b.jsxs)(`span`,{className:`rel-line`,title:`Lines: ${e.all_lines}`,children:[`L`,e.all_lines.includes(`,`)?e.all_lines.split(`,`).slice(0,3).join(`, L`)+(e.all_lines.split(`,`).length>3?`...`:``):e.all_lines]}):e.line_number?(0,b.jsxs)(`span`,{className:`rel-line`,children:[`L`,e.line_number]}):null,e.import_count&&e.import_count>1?(0,b.jsxs)(`span`,{className:`rel-count-badge`,children:[e.import_count,` imports`]}):null]})]},e.id??`import-${t}`))]})]})]})})]})},ve=`contextcortex_navigator_density`,ye=({initialRepo:e=`__all__`,initialPath:t,initialSymbolId:n})=>{let[r,i]=(0,_.useState)(()=>{let e=localStorage.getItem(ve);return e===`compact`||e===`balanced`||e===`spacious`?e:`balanced`}),a=e=>{i(e),localStorage.setItem(ve,e)},[o,s]=(0,_.useState)([]),[c,l]=(0,_.useState)(e),[u,d]=(0,_.useState)(null),[f,p]=(0,_.useState)(!1),[m,h]=(0,_.useState)(``),[g,v]=(0,_.useState)(t||null),[y,x]=(0,_.useState)(null),[S,C]=(0,_.useState)(!1),[w,T]=(0,_.useState)(n||null),[E,D]=(0,_.useState)(null),[O,k]=(0,_.useState)(!1),[ee,A]=(0,_.useState)(null);(0,_.useEffect)(()=>{(async()=>{try{let e=await fetch(`/admin/api/repositories`);if(e.ok){let t=await e.json();s(Array.isArray(t)?t:[])}else{let e=await fetch(`/admin/api/repos`);if(e.ok){let t=await e.json();s(Array.isArray(t)?t:[])}}}catch(e){console.error(`Error fetching repositories:`,e)}})()},[]);let te=(0,_.useCallback)(async e=>{p(!0),A(null);try{let t=await fetch(`/admin/api/navigator/tree?repo=${encodeURIComponent(e)}`);if(!t.ok)throw Error(`Failed to load tree: ${t.status} ${t.statusText}`);let n=await t.json();d(n)}catch(e){console.error(`Error fetching codebase tree:`,e),A(e.message||`Failed to load codebase tree`)}finally{p(!1)}},[]);(0,_.useEffect)(()=>{te(c)},[c,te]);let ne=(0,_.useCallback)(async(e,t)=>{k(!0);try{let n=await fetch(`/admin/api/navigator/symbol-impact?repo=${encodeURIComponent(e)}&symbol_id=${t}`);if(!n.ok)throw Error(`Failed to load symbol impact: ${n.status}`);let r=await n.json();D(r)}catch(e){console.error(`Error fetching symbol impact:`,e),D(null)}finally{k(!1)}},[]),re=(0,_.useCallback)(async(e,t,n)=>{C(!0);try{let r=await fetch(`/admin/api/navigator/file-outline?repo=${encodeURIComponent(e)}&filepath=${encodeURIComponent(t)}`);if(!r.ok)throw Error(`Failed to load file outline: ${r.status}`);let i=await r.json();if(x(i),i.symbols&&i.symbols.length>0){let t;typeof n==`number`?t=i.symbols.find(e=>e.id===n):typeof n==`string`&&(t=i.symbols.find(e=>e.name===n||e.full_symbol===n));let r=t||i.symbols[0];T(r.id),await ne(e,r.id)}else T(null),D(null)}catch(e){console.error(`Error fetching outline:`,e),x(null),T(null),D(null)}finally{C(!1)}},[ne]);return(0,b.jsxs)(`div`,{className:`code-navigator-container density-${r}`,"data-testid":`code-navigator-container`,children:[(0,b.jsx)(de,{repos:o,selectedRepo:c,onSelectRepo:e=>{l(e),v(null),x(null),T(null),D(null)},density:r,onChangeDensity:a,searchQuery:m,onSearchChange:h,totalFiles:u?.total_files??0,totalSymbols:u?.total_symbols??0,onRefresh:()=>te(c),loading:f}),ee&&(0,b.jsxs)(`div`,{className:`nav-error-banner`,role:`alert`,children:[(0,b.jsxs)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,b.jsx)(`line`,{x1:`12`,y1:`8`,x2:`12`,y2:`12`}),(0,b.jsx)(`line`,{x1:`12`,y1:`16`,x2:`12.01`,y2:`16`})]}),(0,b.jsx)(`span`,{children:ee}),(0,b.jsx)(`button`,{type:`button`,onClick:()=>A(null),className:`error-close-btn`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`nav-panes-layout`,children:[(0,b.jsx)(`section`,{className:`nav-pane-column nav-pane-tree`,"aria-label":`File Tree`,children:(0,b.jsx)(pe,{nodes:u?.tree??[],selectedPath:g,onSelectFile:e=>{e.is_dir||(v(e.path),re(c,e.path))},filterText:m,onFilterChange:h,density:r,loading:f})}),(0,b.jsx)(`section`,{className:`nav-pane-column nav-pane-outline`,"aria-label":`Symbol and Route Outline`,children:(0,b.jsx)(ge,{outline:y,selectedSymbolId:w,onSelectSymbol:e=>{T(e.id),ne(c,e.id)},density:r,loading:S})}),(0,b.jsx)(`section`,{className:`nav-pane-column nav-pane-inspector`,"aria-label":`Code Intelligence and Impact`,children:(0,b.jsx)(_e,{impact:E,onSelectCaller:(e,t,n)=>{v(e),re(c,e,n??t)},onSelectCallee:(e,t)=>{e&&(v(e),re(c,e,t))},density:r,loading:O})})]})]})};function be({data:e,onConfirm:t,onCancel:n,isIngesting:r=!1}){let[i,a]=(0,_.useState)(`pages`),[o,s]=(0,_.useState)(0),c=e.total_pages||e.pages.length||1,l=e.pages[o]||{page_number:1,text:``,char_count:0,ocr_applied:!1};return(0,b.jsx)(`div`,{className:`modal-backdrop`,"data-testid":`pdf-preview-modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`850px`,width:`95%`,maxHeight:`90vh`,display:`flex`,flexDirection:`column`},"data-testid":`pdf-preview-modal`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,style:{marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,margin:0,fontSize:`1.25rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf text-red-500 mr-2`,style:{color:`#ef4444`}}),(0,b.jsx)(`span`,{children:`PDF Extraction Preview`})]}),(0,b.jsx)(`div`,{style:{fontSize:`0.85rem`,color:`var(--text-muted)`,marginTop:`4px`},children:(0,b.jsx)(`code`,{children:e.filename})})]}),(0,b.jsx)(`button`,{type:`button`,className:`btn-close`,onClick:n,"aria-label":`Close modal`,children:`×`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,flexWrap:`wrap`,gap:`10px`,padding:`10px 14px`,background:`rgba(255, 255, 255, 0.04)`,borderRadius:`6px`,marginBottom:`14px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`14px`,flexWrap:`wrap`,alignItems:`center`,fontSize:`0.85rem`},children:[(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`strong`,{children:`Total Pages:`}),` `,(0,b.jsx)(`span`,{className:`badge badge-primary`,"data-testid":`total-pages-badge`,children:e.total_pages})]}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`strong`,{children:`Total Characters:`}),` `,(0,b.jsx)(`span`,{className:`badge badge-primary`,"data-testid":`total-chars-badge`,children:e.total_characters.toLocaleString()})]}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`strong`,{children:`OCR Applied:`}),` `,(0,b.jsxs)(`span`,{className:`badge ${e.ocr_pages_count>0?`badge-warning`:`badge-secondary`}`,"data-testid":`ocr-count-badge`,children:[e.ocr_pages_count,` `,e.ocr_pages_count===1?`page`:`pages`]})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`6px`},children:[(0,b.jsxs)(`button`,{type:`button`,className:`btn ${i===`pages`?`btn-primary`:`btn-secondary`}`,style:{padding:`4px 10px`,fontSize:`0.82rem`},onClick:()=>a(`pages`),"data-testid":`tab-pages-btn`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`,style:{marginRight:`5px`}}),` Page Text`]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn ${i===`chunks`?`btn-primary`:`btn-secondary`}`,style:{padding:`4px 10px`,fontSize:`0.82rem`},onClick:()=>a(`chunks`),"data-testid":`tab-chunks-btn`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-layer-group`,style:{marginRight:`5px`}}),` Sample Chunks (`,e.sample_chunks?.length||0,`)`]})]})]}),(0,b.jsx)(`div`,{style:{flex:1,overflowY:`auto`,minHeight:`320px`,display:`flex`,flexDirection:`column`},children:i===`pages`?(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,flexWrap:`wrap`,gap:`8px`,marginBottom:`10px`,padding:`6px 10px`,background:`rgba(0, 0, 0, 0.2)`,borderRadius:`6px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`3px 8px`,fontSize:`0.8rem`},onClick:()=>{o>0&&s(e=>e-1)},disabled:o<=0,"aria-label":`Previous Page`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-chevron-left`}),` Prev`]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`span`,{children:`Page`}),(0,b.jsx)(`select`,{value:o,onChange:t=>{let n=parseInt(t.target.value,10);!isNaN(n)&&n>=0&&n(0,b.jsxs)(`option`,{value:t,children:[e.page_number,` `,e.ocr_applied?`(OCR)`:``]},e.page_number))}),(0,b.jsxs)(`span`,{children:[`of `,c]})]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`3px 8px`,fontSize:`0.8rem`},onClick:()=>{oe+1)},disabled:o>=e.pages.length-1,"aria-label":`Next Page`,children:[`Next `,(0,b.jsx)(`i`,{className:`fa-solid fa-chevron-right`})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[l.ocr_applied?(0,b.jsxs)(`span`,{className:`badge badge-warning`,style:{display:`inline-flex`,alignItems:`center`,gap:`4px`},"data-testid":`page-ocr-applied-badge`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-eye`}),` OCR Fallback`]}):(0,b.jsxs)(`span`,{className:`badge badge-secondary`,style:{display:`inline-flex`,alignItems:`center`,gap:`4px`},"data-testid":`page-digital-badge`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-font`}),` Digital`]}),(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:[l.char_count.toLocaleString(),` chars`]})]})]}),(0,b.jsx)(`div`,{style:{flex:1,minHeight:`260px`,position:`relative`},children:l.text?(0,b.jsx)(`pre`,{className:`search-hit-code`,style:{maxHeight:`400px`,overflowY:`auto`,margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,fontSize:`0.85rem`,lineHeight:`1.5`,padding:`12px`,background:`rgba(0, 0, 0, 0.3)`,borderRadius:`6px`},"data-testid":`page-text-content`,children:l.text}):(0,b.jsxs)(`div`,{className:`empty-state`,style:{padding:`30px`,textAlign:`center`,color:`var(--text-muted)`},"data-testid":`page-empty-text`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-circle-question`,style:{fontSize:`1.5rem`,marginBottom:`8px`,display:`block`}}),`No text extracted from Page `,l.page_number,`.`]})})]}):(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`10px`},"data-testid":`chunks-container`,children:[(0,b.jsx)(`div`,{style:{fontSize:`0.82rem`,color:`var(--text-muted)`,marginBottom:`4px`},children:`Simulated chunking for vector ingestion (approx. 1000 chars / chunk with 200 char overlap):`}),!e.sample_chunks||e.sample_chunks.length===0?(0,b.jsx)(`div`,{className:`empty-state`,style:{padding:`24px`},children:`No vector chunks generated for this document.`}):e.sample_chunks.map(e=>(0,b.jsxs)(`div`,{style:{border:`1px solid var(--border-card)`,borderRadius:`6px`,background:`rgba(0, 0, 0, 0.25)`,padding:`10px 12px`},"data-testid":`chunk-card-${e.chunk_index}`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,fontSize:`0.8rem`,marginBottom:`6px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,alignItems:`center`},children:[(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[`Chunk #`,e.chunk_index+1]}),(0,b.jsxs)(`span`,{className:`text-muted`,children:[e.heading,` (Page `,e.page_number,`)`]})]}),(0,b.jsxs)(`span`,{className:`badge badge-secondary`,children:[e.char_count,` chars`]})]}),(0,b.jsx)(`pre`,{style:{margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,fontFamily:`var(--font-family-mono)`,fontSize:`0.8rem`,color:`var(--text)`,lineHeight:`1.4`,background:`rgba(0, 0, 0, 0.2)`,padding:`8px`,borderRadius:`4px`},children:e.preview})]},e.chunk_index))]})}),(0,b.jsxs)(`div`,{className:`modal-footer`,style:{marginTop:`16px`,paddingTop:`12px`,borderTop:`1px solid var(--border-card)`,display:`flex`,justifyContent:`flex-end`,gap:`10px`},children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:n,disabled:r,children:`Cancel`}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-primary`,onClick:t,disabled:r,"data-testid":`confirm-ingest-btn`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${r?`fa-spinner fa-spin`:`fa-database`}`,style:{marginRight:`6px`}}),r?`Ingesting...`:`Confirm & Ingest to Vector DB`]})]})]})})}function xe({refreshStats:e}){let t=S(),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)(``),[o,s]=(0,_.useState)(!1),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(``),[f,p]=(0,_.useState)(``),[m,h]=(0,_.useState)(`local_storage`),[g,v]=(0,_.useState)(``),[y,x]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(!1),[k,ee]=(0,_.useState)(null),[A,te]=(0,_.useState)(!1),[ne,re]=(0,_.useState)(!1),[ie,j]=(0,_.useState)(null),[M,N]=(0,_.useState)(``),[ae,oe]=(0,_.useState)(``),[se,P]=(0,_.useState)(!1),[F,ce]=(0,_.useState)(!1),[le,ue]=(0,_.useState)(!1),[de,fe]=(0,_.useState)(null),[pe,me]=(0,_.useState)(null),[he,ge]=(0,_.useState)(``),[_e,ve]=(0,_.useState)(`local_storage`),[ye,xe]=(0,_.useState)(``),[Se,Ce]=(0,_.useState)(!1),we=e=>{if(!e||e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/t**r).toFixed(1))+` `+n[r]},Te=e=>{if(!e)return`-`;let t=e<1e11?e*1e3:e;return new Date(t).toLocaleString()},Ee=(0,_.useCallback)(async(e=i)=>{s(!0);try{let t=e?`/admin/api/storage/tree?folder=${encodeURIComponent(e)}`:`/admin/api/storage/tree`,n=await fetch(t);if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to load storage tree`)}let i=await n.json();r(i),a(i.current_folder||``)}catch(e){t.error(`Error loading storage: `+e.message),console.error(`Error loading storage tree:`,e)}finally{s(!1)}},[i,t]);(0,_.useEffect)(()=>{Ee(``)},[]);let De=e=>{Ee(e)},Oe=()=>{if(!i)return;let e=i.split(`/`).filter(Boolean);e.pop(),De(e.join(`/`))},ke=e=>{let t=e===void 0?i:e;d(t?`${t}/`:``),p(``),h(`local_storage`),v(``),x(null),l(!0)},Ae=e=>{if(e.preventDefault(),w(!1),e.dataTransfer.files&&e.dataTransfer.files.length>0){let t=e.dataTransfer.files[0];Fe(t)}},je=e=>{e.target.files&&e.target.files.length>0&&Fe(e.target.files[0])},Me=async(e,n,r,a)=>{ue(!0);try{let t=new FormData;t.append(`file`,e),t.append(`ocr_fallback`,`true`);let o=await fetch(`/admin/api/storage/pdf/preview`,{method:`POST`,body:t}),s=await o.json();if(!o.ok)throw Error(s.error||`Failed to generate PDF preview`);me(e),ge(n||(i?`${i}/${e.name}`:e.name)),ve(r||m||`local_storage`),xe(a||f||``),fe(s),l(!1),ce(!0)}catch(e){t.error(`PDF preview error: ${e.message}`)}finally{ue(!1)}},Ne=async()=>{if(pe){Ce(!0);try{let n=new FormData;n.append(`file`,pe),n.append(`path`,he||pe.name),n.append(`repo`,_e||`local_storage`),ye&&n.append(`category`,ye);let r=await fetch(`/admin/api/storage/upload`,{method:`POST`,body:n}),a=await r.json();if(!r.ok)throw Error(a.error||`Failed to ingest PDF`);ce(!1),me(null),fe(null);let o=a.chunks_indexed??0;t.success(`PDF uploaded and indexed (${o} chunks)`),Ee(i),e&&e()}catch(e){t.error(`PDF ingestion error: ${e.message}`)}finally{Ce(!1)}}},Pe=()=>{ce(!1),me(null),fe(null)},Fe=e=>{x(e);let t=i?`${i}/${e.name}`:e.name;if(d(t),e.name.toLowerCase().endsWith(`.pdf`)||e.type===`application/pdf`){v(``),Me(e,t,m,f);return}let n=new FileReader;n.onload=e=>{typeof e.target?.result==`string`&&v(e.target.result)},n.readAsText(e)},Ie=async n=>{if(n.preventDefault(),!u.trim()){t.error(`File path is required`);return}if(y&&y.name.toLowerCase().endsWith(`.pdf`)){await Me(y,u.trim(),m.trim(),f.trim());return}E(!0);try{let n;if(y&&!g){let e=new FormData;e.append(`file`,y),e.append(`path`,u.trim()),e.append(`repo`,m.trim()||`local_storage`),f.trim()&&e.append(`category`,f.trim()),n=await fetch(`/admin/api/storage/upload`,{method:`POST`,body:e})}else n=await fetch(`/admin/api/storage/upload`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:u.trim(),content:g,repo:m.trim()||`local_storage`,category:f.trim()||null})});let r=await n.json();if(!n.ok)throw Error(r.error||`Failed to upload file`);l(!1);let a=r.chunks_indexed??0;t.success(`File uploaded and indexed (${a} chunks)`),Ee(i),e&&e()}catch(e){t.error(`Upload error: ${e.message}`)}finally{E(!1)}},Le=async e=>{te(!0),O(!0);try{let t=await fetch(`/admin/api/storage/file?path=${encodeURIComponent(e.rel_path)}`),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to read file`);ee(n)}catch(e){t.error(`Preview error: ${e.message}`),O(!1)}finally{te(!1)}},Re=async e=>{if(j(e),oe(``),re(!0),e.rel_path.toLowerCase().endsWith(`.pdf`)){N(``);return}try{let t=await fetch(`/admin/api/storage/file?path=${encodeURIComponent(e.rel_path)}`),n=await t.json();t.ok&&n.content!==void 0?N(n.content):N(``)}catch{N(``)}},ze=async n=>{if(n.preventDefault(),ie){if(ie.rel_path.toLowerCase().endsWith(`.pdf`)){t.error(`PDF files cannot be edited directly via text editor. Upload a new PDF file instead.`);return}P(!0);try{let n=await fetch(`/admin/api/storage/file`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:ie.rel_path,content:M,repo:`local_storage`,category:ae.trim()||``})}),r=await n.json();if(!n.ok)throw Error(r.error||`Failed to update file`);re(!1);let a=r.chunks_indexed??0;t.success(`File updated and indexed (${a} chunks)`),Ee(i),e&&e()}catch(e){t.error(`Replace error: ${e.message}`)}finally{P(!1)}}},Be=async n=>{if(window.confirm(`Are you sure you want to delete '${n.name}' from local storage and purge its vector embeddings?`))try{let r=await fetch(`/admin/api/storage/file?path=${encodeURIComponent(n.rel_path)}`,{method:`DELETE`}),a=await r.json();if(!r.ok)throw Error(a.error||`Failed to delete file`);t.success(`File deleted successfully: ${n.name}`),Ee(i),e&&e()}catch(e){t.error(`Delete error: ${e.message}`)}},Ve=i?i.split(`/`).filter(Boolean):[];return(0,b.jsxs)(`div`,{className:`tab-content active`,children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`}),` Local Storage Explorer`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Upload, browse, inspect, replace, and delete managed documents in ContextCortex local storage with real-time vector indexing.`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`10px`},children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>Ee(i),title:`Refresh directory`,disabled:o,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate ${o?`fa-spin`:``}`}),` Refresh`]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>ke(),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-upload`}),` Upload File`]})]})]}),(0,b.jsxs)(`div`,{className:`browser-breadcrumbs`,style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,flexWrap:`wrap`,gap:`10px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,flexWrap:`wrap`},children:[(0,b.jsx)(`span`,{className:`label`,style:{fontWeight:600},children:`Location:`}),(0,b.jsxs)(`button`,{className:`btn-icon`,style:{padding:`2px 6px`,fontSize:`0.85rem`,color:i===``?`var(--primary)`:`var(--text)`},onClick:()=>De(``),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-house`}),` root`]}),Ve.map((e,t)=>{let n=Ve.slice(0,t+1).join(`/`),r=t===Ve.length-1;return(0,b.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:`6px`},children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`/`}),(0,b.jsx)(`button`,{className:`btn-icon`,style:{padding:`2px 6px`,fontSize:`0.85rem`,fontWeight:r?`bold`:`normal`,color:r?`var(--primary)`:`var(--text)`},onClick:()=>De(n),children:e})]},n)})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,fontSize:`0.8rem`,color:`var(--text-muted)`},children:[(0,b.jsxs)(`span`,{children:[`Directories: `,(0,b.jsx)(`strong`,{children:n?.directories.length||0})]}),(0,b.jsx)(`span`,{children:`•`}),(0,b.jsxs)(`span`,{children:[`Files: `,(0,b.jsx)(`strong`,{children:n?.files.length||0})]})]})]}),i!==``&&(0,b.jsx)(`div`,{style:{marginTop:`8px`,marginBottom:`8px`},children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.82rem`},onClick:Oe,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-level-up-alt`}),` .. (Parent Directory)`]})}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{style:{width:`40%`},children:`Name`}),(0,b.jsx)(`th`,{children:`Path`}),(0,b.jsx)(`th`,{children:`Size`}),(0,b.jsx)(`th`,{children:`Modified`}),(0,b.jsx)(`th`,{style:{textAlign:`right`},children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:!n||n.directories.length===0&&n.files.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:5,className:`empty-state`,children:`No files or subdirectories found in this storage directory. Click "Upload File" to add documents.`})}):(0,b.jsxs)(b.Fragment,{children:[n.directories.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsxs)(`button`,{className:`btn-icon`,style:{display:`inline-flex`,alignItems:`center`,gap:`8px`,textAlign:`left`,color:`var(--text)`},onClick:()=>De(e.rel_path),"aria-label":`open ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder`,style:{color:`#fbbf24`,fontSize:`1.05rem`}}),(0,b.jsx)(`strong`,{children:e.name})]})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.rel_path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{style:{textAlign:`right`},children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`3px 8px`,fontSize:`0.8rem`},onClick:()=>De(e.rel_path),title:`Open ${e.name}`,"aria-label":`open ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-open`}),` Open`]})})]},e.rel_path)),n.files.map(e=>{let t=e.name.toLowerCase().endsWith(`.pdf`);return(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[t?(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf text-red-500 mr-2`,style:{color:`#ef4444`,fontSize:`1.05rem`}}):(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`,style:{color:`var(--primary)`,fontSize:`1.05rem`}}),(0,b.jsx)(`span`,{children:e.name})]})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.rel_path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:we(e.size_bytes)})}),(0,b.jsx)(`td`,{style:{fontSize:`0.85rem`},children:Te(e.mtime)}),(0,b.jsx)(`td`,{style:{textAlign:`right`},children:(0,b.jsxs)(`div`,{style:{display:`inline-flex`,gap:`6px`},children:[(0,b.jsx)(`button`,{className:`btn-icon`,onClick:()=>Le(e),title:`Preview File`,"aria-label":`Preview File`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-eye`})}),(0,b.jsx)(`button`,{className:`btn-icon`,onClick:()=>Re(e),title:`Replace File`,"aria-label":`Replace File`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-file-pen`})}),(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>Be(e),title:`Delete File`,"aria-label":`Delete File`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})]})})]},e.rel_path)})]})})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:!n||n.directories.length===0&&n.files.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No files or subdirectories found.`}):(0,b.jsxs)(b.Fragment,{children:[n.directories.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder`,style:{color:`#fbbf24`}}),(0,b.jsx)(`strong`,{children:e.name})]}),(0,b.jsx)(`span`,{className:`badge badge-warning`,children:`Directory`})]}),(0,b.jsx)(`div`,{className:`data-mobile-card-body`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{children:e.rel_path})]})}),(0,b.jsx)(`div`,{className:`data-mobile-card-actions`,children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>De(e.rel_path),"aria-label":`open ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-open`}),` Open Folder`]})})]},`m-${e.rel_path}`)),n.files.map(e=>{let t=e.name.toLowerCase().endsWith(`.pdf`);return(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[t?(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf text-red-500 mr-2`,style:{color:`#ef4444`}}):(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`,style:{color:`var(--primary)`}}),(0,b.jsx)(`strong`,{children:e.name})]}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:we(e.size_bytes)})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{children:e.rel_path})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Modified: `}),(0,b.jsx)(`span`,{children:Te(e.mtime)})]})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-actions`,children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>Le(e),title:`Preview File`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-eye`}),` Preview`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>Re(e),title:`Replace File`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pen`}),` Replace`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>Be(e),title:`Delete File`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})]})]},`m-${e.rel_path}`)})]})})]}),c&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`640px`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-cloud-arrow-up`}),` Upload to Local Storage`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>l(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:Ie,children:[(0,b.jsxs)(`div`,{style:{border:C?`2px dashed var(--primary)`:`2px dashed rgba(255, 255, 255, 0.15)`,borderRadius:`8px`,padding:`20px`,textAlign:`center`,background:C?`rgba(59, 130, 246, 0.08)`:`rgba(0, 0, 0, 0.15)`,marginBottom:`16px`,cursor:`pointer`,transition:`all 0.2s ease`},onDragOver:e=>{e.preventDefault(),w(!0)},onDragLeave:()=>w(!1),onDrop:Ae,onClick:()=>document.getElementById(`storage-file-input`)?.click(),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-arrow-up`,style:{fontSize:`2rem`,color:`var(--primary)`,marginBottom:`8px`}}),(0,b.jsx)(`p`,{style:{margin:`4px 0`,fontSize:`0.9rem`},children:y?`Selected: ${y.name} (${we(y.size)})`:`Drag & drop a file here, or click to browse`}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`},children:`Supports Markdown, code, JSON, YAML, plain text, PDF (up to 50MB)`}),le&&(0,b.jsxs)(`div`,{style:{marginTop:`8px`,fontSize:`0.85rem`,color:`var(--primary)`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`6px`}}),`Extracting and analyzing PDF preview...`]}),(0,b.jsx)(`input`,{id:`storage-file-input`,type:`file`,accept:`.md,.markdown,.txt,.json,.yaml,.yml,.sql,.html,.css,.pdf`,style:{display:`none`},onChange:je})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:2},children:[(0,b.jsx)(`label`,{htmlFor:`upload-path`,children:`Relative File Path (e.g. docs/guide.md)`}),(0,b.jsx)(`input`,{id:`upload-path`,type:`text`,required:!0,placeholder:`folder/document.md`,value:u,onChange:e=>d(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,b.jsx)(`label`,{htmlFor:`upload-category`,children:`Category Override`}),(0,b.jsx)(`input`,{id:`upload-category`,type:`text`,placeholder:`Optional category`,value:f,onChange:e=>p(e.target.value)})]})]}),y?.name.toLowerCase().endsWith(`.pdf`)||y?.type===`application/pdf`||u.trim().toLowerCase().endsWith(`.pdf`)?(0,b.jsxs)(`div`,{className:`alert alert-info`,style:{margin:`12px 0`,padding:`12px`,background:`rgba(59, 130, 246, 0.1)`,border:`1px solid var(--primary)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf`,style:{color:`#ef4444`,marginRight:`8px`}}),(0,b.jsx)(`strong`,{children:`PDF Document Selected:`}),` Binary PDF content cannot be edited manually as text. Extracted text, page segmentation, and vector chunks will be previewed in the extraction modal before ingestion.`]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`upload-content`,children:`File Content (Optional if file uploaded directly)`}),(0,b.jsx)(`textarea`,{id:`upload-content`,rows:8,placeholder:`# Enter or paste text content here...`,value:g,onChange:e=>v(e.target.value),style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`}})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>l(!1),children:`Cancel`}),(0,b.jsxs)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:T,children:[(0,b.jsx)(`i`,{className:`fa-solid ${T?`fa-spinner fa-spin`:`fa-upload`}`}),` Upload & Index`]})]})]})]})}),D&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`750px`,maxHeight:`90vh`,display:`flex`,flexDirection:`column`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`}),` File Preview: `,k?.rel_path||`Loading...`]}),k&&(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:[`Size: `,we(k.size_bytes),` • Modified: `,Te(k.mtime)]})]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>O(!1),children:`×`})]}),(0,b.jsx)(`div`,{style:{flex:1,overflowY:`auto`,margin:`10px 0`},children:A?(0,b.jsxs)(`div`,{className:`empty-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Loading content...`]}):(0,b.jsx)(`pre`,{className:`search-hit-code`,style:{maxHeight:`420px`,overflowY:`auto`,margin:0,whiteSpace:`pre-wrap`},children:k?.content||`Empty file.`})}),(0,b.jsx)(`div`,{className:`modal-footer`,children:(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>O(!1),children:`Close`})})]})}),ne&&ie&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`680px`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pen`}),` Replace File: `,ie.name]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>re(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:ze,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Target File Path`}),(0,b.jsx)(`input`,{type:`text`,readOnly:!0,value:ie.rel_path})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`replace-category`,children:`Category Override`}),(0,b.jsx)(`input`,{id:`replace-category`,type:`text`,placeholder:`Optional category`,value:ae,onChange:e=>oe(e.target.value)})]}),ie.rel_path.toLowerCase().endsWith(`.pdf`)?(0,b.jsxs)(`div`,{className:`alert alert-warning`,style:{margin:`14px 0`,padding:`12px`,background:`rgba(245, 158, 11, 0.1)`,border:`1px solid rgba(245, 158, 11, 0.3)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,style:{marginRight:`8px`,color:`#f59e0b`}}),(0,b.jsx)(`strong`,{children:`PDF Replacement:`}),` PDF documents contain binary page streams and cannot be edited as plain text. To replace this document, please upload a new `,(0,b.jsx)(`code`,{children:`.pdf`}),` file using the "Upload File" tool.`]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`replace-content`,children:`File Content`}),(0,b.jsx)(`textarea`,{id:`replace-content`,rows:10,required:!0,placeholder:`Updated file text...`,value:M,onChange:e=>N(e.target.value),style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`}})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>re(!1),children:`Cancel`}),(0,b.jsxs)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:se||ie.rel_path.toLowerCase().endsWith(`.pdf`),children:[(0,b.jsx)(`i`,{className:`fa-solid ${se?`fa-spinner fa-spin`:`fa-save`}`}),` Save & Re-Index`]})]})]})]})}),F&&de&&(0,b.jsx)(be,{data:de,onConfirm:Ne,onCancel:Pe,isIngesting:Se})]})}function Se(){let e=S(),[t,n]=(0,_.useState)(null),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(`all`),[s,c]=(0,_.useState)(`summary`),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(``),[h,g]=(0,_.useState)(``),v=(0,_.useCallback)(async(t=a,r=s,o=l,c=d,u=p)=>{i(!0);try{let e=new URLSearchParams;e.set(`source_type`,t),e.set(`detail_level`,r),o.trim()&&e.set(`repo_name`,o.trim()),c.trim()&&e.set(`path_prefix`,c.trim()),u.trim()&&e.set(`file_extension`,u.trim());let i=await fetch(`/admin/api/ingestion/catalog?${e.toString()}`);if(!i.ok){let e=await i.json().catch(()=>({}));throw Error(e.error||`Failed to load ingestion catalog`)}let a=await i.json();n(a)}catch(t){e.error(`Error loading catalog: `+t.message),console.error(`Error loading ingestion catalog:`,t)}finally{i(!1)}},[a,s,l,d,p,e]);(0,_.useEffect)(()=>{v(a,s,l,d,p)},[a,s]);let y=e=>{e&&e.preventDefault(),v(a,s,l,d,p)},x=()=>{u(``),f(``),m(``),g(``),v(a,s,``,``,``)},C=e=>{o(e)},w=e=>{c(e)},T=e=>{if(!e)return`-`;if(typeof e==`string`)try{return new Date(e).toLocaleString()}catch{return e}let t=e<1e11?e*1e3:e;return new Date(t).toLocaleString()},E=t?.git_repositories||[],D=t?.monitored_paths||[],O=t?.local_storage,k=(t?.files||[]).filter(e=>{if(!h.trim())return!0;let t=h.toLowerCase();return e.filepath.toLowerCase().includes(t)||e.repo.toLowerCase().includes(t)||e.language&&e.language.toLowerCase().includes(t)}),ee=E.reduce((e,t)=>e+(t.file_count||0),0),A=D.reduce((e,t)=>e+(t.file_count||0),0),te=O?.file_count||0,ne=ee+A+te;return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-book-bookmark`}),` Unified Ingestion Catalog`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Inspect all indexed Git repositories, monitored local workspaces, and uploaded local storage documents.`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,gap:`10px`},children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>y(),disabled:r,title:`Refresh catalog`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate ${r?`fa-spin`:``}`}),` Refresh`]})})]}),(0,b.jsxs)(`div`,{className:`stats-grid`,style:{marginBottom:`20px`},children:[(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-brands fa-github`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Git Repositories`}),(0,b.jsxs)(`span`,{className:`stat-value`,children:[E.length,` `,(0,b.jsxs)(`small`,{style:{fontSize:`0.75rem`,fontWeight:`normal`,color:`var(--text-muted)`},children:[`(`,ee,` files)`]})]})]})]}),(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Monitored Paths`}),(0,b.jsxs)(`span`,{className:`stat-value`,children:[D.length,` `,(0,b.jsxs)(`small`,{style:{fontSize:`0.75rem`,fontWeight:`normal`,color:`var(--text-muted)`},children:[`(`,A,` files)`]})]})]})]}),(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Local Storage`}),(0,b.jsxs)(`span`,{className:`stat-value`,children:[te,` `,(0,b.jsx)(`small`,{style:{fontSize:`0.75rem`,fontWeight:`normal`,color:`var(--text-muted)`},children:`files`})]})]})]}),(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-database`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Total Cataloged Files`}),(0,b.jsx)(`span`,{className:`stat-value`,children:ne})]})]})]}),(0,b.jsxs)(`div`,{style:{background:`rgba(0, 0, 0, 0.2)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`,marginBottom:`20px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,flexWrap:`wrap`,gap:`12px`,marginBottom:`14px`},children:[(0,b.jsxs)(`div`,{className:`log-filter-pills`,role:`group`,"aria-label":`Source Type Filters`,children:[(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`all`?`active`:``}`,onClick:()=>C(`all`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-layer-group`}),` All Sources`]}),(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`git`?`active`:``}`,onClick:()=>C(`git`),children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`}),` Git Repositories`]}),(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`monitored_path`?`active`:``}`,onClick:()=>C(`monitored_path`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`}),` Monitored Paths`]}),(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`local_storage`?`active`:``}`,onClick:()=>C(`local_storage`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`}),` Local Storage`]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`6px`},role:`group`,"aria-label":`Detail Level Switch`,children:[(0,b.jsxs)(`button`,{className:`btn ${s===`summary`?`btn-primary`:`btn-secondary`}`,style:{padding:`5px 12px`,fontSize:`0.8rem`},onClick:()=>w(`summary`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-list`}),` Summary`]}),(0,b.jsxs)(`button`,{className:`btn ${s===`detailed`?`btn-primary`:`btn-secondary`}`,style:{padding:`5px 12px`,fontSize:`0.8rem`},onClick:()=>w(`detailed`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-network-wired`}),` Detailed File Tree`]})]})]}),(0,b.jsxs)(`form`,{onSubmit:y,children:[(0,b.jsxs)(`div`,{className:`form-row-3col`,style:{alignItems:`flex-end`},children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{margin:0},children:[(0,b.jsx)(`label`,{htmlFor:`catalog-repo-filter`,style:{fontSize:`0.8rem`},children:`Repository / Alias`}),(0,b.jsx)(`input`,{id:`catalog-repo-filter`,type:`text`,placeholder:`Filter by repo name...`,value:l,onChange:e=>u(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{margin:0},children:[(0,b.jsx)(`label`,{htmlFor:`catalog-prefix-filter`,style:{fontSize:`0.8rem`},children:`Path Prefix`}),(0,b.jsx)(`input`,{id:`catalog-prefix-filter`,type:`text`,placeholder:`e.g. app/api or docs/`,value:d,onChange:e=>f(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{margin:0},children:[(0,b.jsx)(`label`,{htmlFor:`catalog-ext-filter`,style:{fontSize:`0.8rem`},children:`File Extension`}),(0,b.jsx)(`input`,{id:`catalog-ext-filter`,type:`text`,placeholder:`e.g. .md, .py, .ts`,value:p,onChange:e=>m(e.target.value)})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`flex-end`,gap:`8px`,marginTop:`12px`},children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`6px 12px`,fontSize:`0.85rem`},onClick:x,children:`Clear`}),(0,b.jsxs)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`6px 14px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-filter`}),` Apply`]})]})]})]}),(a===`all`||a===`git`)&&(0,b.jsxs)(`div`,{style:{marginBottom:`28px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,marginBottom:`10px`,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`,style:{color:`var(--primary)`}}),` Git Repositories`,(0,b.jsx)(`span`,{className:`badge badge-primary`,children:E.length})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Name`}),(0,b.jsx)(`th`,{children:`Branch / Commit`}),(0,b.jsx)(`th`,{children:`Status`}),(0,b.jsx)(`th`,{children:`Files`}),(0,b.jsx)(`th`,{children:`Provider`}),(0,b.jsx)(`th`,{children:`URL`})]})}),(0,b.jsx)(`tbody`,{children:E.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:6,className:`empty-state`,children:`No Git repositories match criteria.`})}):E.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.name})}),(0,b.jsxs)(`td`,{children:[(0,b.jsx)(`code`,{children:e.branch}),e.commit_sha&&(0,b.jsxs)(`span`,{className:`text-muted`,style:{marginLeft:`6px`,fontSize:`0.8rem`},children:[`@`,e.commit_sha.substring(0,7)]})]}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge ${e.status===`synced`?`badge-success`:e.status===`syncing`?`badge-warning`:`badge-danger`}`,children:e.status})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.file_count??0})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.provider||`git`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.82rem`,wordBreak:`break-all`},children:e.url})})]},e.id))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:E.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No Git repositories match criteria.`}):E.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`strong`,{children:e.name}),(0,b.jsx)(`span`,{className:`badge ${e.status===`synced`?`badge-success`:`badge-warning`}`,children:e.status})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Branch: `}),(0,b.jsx)(`code`,{children:e.branch})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Files: `}),(0,b.jsx)(`strong`,{children:e.file_count??0})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`URL: `}),(0,b.jsx)(`span`,{style:{wordBreak:`break-all`},children:e.url})]})]})]},`gm-${e.id}`))})]}),(a===`all`||a===`monitored_path`)&&(0,b.jsxs)(`div`,{style:{marginBottom:`28px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,marginBottom:`10px`,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`,style:{color:`#fbbf24`}}),` Monitored Local Paths`,(0,b.jsx)(`span`,{className:`badge badge-primary`,children:D.length})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Path`}),(0,b.jsx)(`th`,{children:`Repo Alias`}),(0,b.jsx)(`th`,{children:`Category`}),(0,b.jsx)(`th`,{children:`Files Indexed`})]})}),(0,b.jsx)(`tbody`,{children:D.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:4,className:`empty-state`,children:`No monitored paths match criteria.`})}):D.map((e,t)=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.repo})}),(0,b.jsx)(`td`,{children:e.category?(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category}):(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.file_count??0})})]},`${e.path}-${t}`))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:D.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No monitored paths match criteria.`}):D.map((e,t)=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`strong`,{children:e.repo}),(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[e.file_count??0,` files`]})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{children:e.path})]}),e.category&&(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Category: `}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category})]})]})]},`mpm-${t}`))})]}),(a===`all`||a===`local_storage`)&&O&&(0,b.jsxs)(`div`,{style:{marginBottom:`28px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,marginBottom:`10px`,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`,style:{color:`var(--accent)`}}),` Local Storage`,(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[O.file_count,` files`]})]}),(0,b.jsxs)(`div`,{style:{background:`rgba(255, 255, 255, 0.02)`,padding:`16px`,borderRadius:`8px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`20px`,flexWrap:`wrap`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.85rem`},children:`Storage Root: `}),(0,b.jsx)(`code`,{children:O.root_path})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.85rem`},children:`Total Files: `}),(0,b.jsx)(`strong`,{children:O.file_count})]})]}),O.tree&&(0,b.jsxs)(`div`,{style:{fontSize:`0.85rem`,color:`var(--text-muted)`},children:[`Top-level Subfolders: `,(0,b.jsx)(`strong`,{children:O.tree.directories?.length||0}),` • Top-level Files: `,(0,b.jsx)(`strong`,{children:O.tree.files?.length||0})]})]})]}),s===`detailed`&&(0,b.jsxs)(`div`,{style:{marginTop:`20px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,flexWrap:`wrap`,gap:`10px`,marginBottom:`12px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,margin:0,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{color:`var(--primary)`}}),` Ingested Files Details`,(0,b.jsx)(`span`,{className:`badge badge-primary`,children:k.length})]}),(0,b.jsxs)(`div`,{className:`log-search-wrapper`,style:{maxWidth:`320px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass search-icon`}),(0,b.jsx)(`input`,{type:`text`,className:`log-search-input`,placeholder:`Search in loaded files...`,value:h,onChange:e=>g(e.target.value)}),h&&(0,b.jsx)(`button`,{className:`clear-search-btn`,onClick:()=>g(``),children:`×`})]})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Filepath`}),(0,b.jsx)(`th`,{children:`Repository`}),(0,b.jsx)(`th`,{children:`Type`}),(0,b.jsx)(`th`,{children:`Language`}),(0,b.jsx)(`th`,{children:`Last Modified`})]})}),(0,b.jsx)(`tbody`,{children:k.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:5,className:`empty-state`,children:`No detailed files match current search or filters.`})}):k.map((e,t)=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.filepath})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.repo})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.doc_type})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.language||`text`})}),(0,b.jsx)(`td`,{style:{fontSize:`0.85rem`},children:T(e.mtime)})]},`${e.filepath}-${t}`))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:k.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No detailed files match current search or filters.`}):k.map((e,t)=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`strong`,{children:e.repo}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.language||`text`})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.filepath})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Type: `}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.doc_type})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Modified: `}),(0,b.jsx)(`span`,{children:T(e.mtime)})]})]})]},`dfm-${t}`))})]})]})})}function Ce(){let[e,t]=(0,_.useState)(`overview`),[n,r]=(0,_.useState)(!1),[i,a]=(0,_.useState)(null),o=async()=>{try{let e=await fetch(`/admin/api/stats`);if(!e.ok)return;let t=await e.json();a(t)}catch(e){console.error(`Error loading stats:`,e)}};return(0,_.useEffect)(()=>{o();let e=setInterval(o,8e3);return()=>clearInterval(e)},[]),(0,b.jsx)(b.Fragment,{children:(0,b.jsxs)(`div`,{className:`dashboard-container`,children:[(0,b.jsxs)(`header`,{className:`dashboard-header`,children:[(0,b.jsxs)(`div`,{className:`header-top-row`,children:[(0,b.jsxs)(`div`,{className:`header-logo`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-layer-group logo-icon`}),(0,b.jsxs)(`div`,{className:`header-title`,children:[(0,b.jsx)(`h1`,{children:`ContextCortex`}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:`v2.14.0`})]})]}),(0,b.jsx)(`button`,{className:`menu-toggle-btn`,"aria-label":`Toggle navigation`,onClick:()=>r(!n),children:(0,b.jsx)(`i`,{className:`fa-solid ${n?`fa-xmark`:`fa-bars`}`})})]}),(0,b.jsxs)(`div`,{className:`header-status`,children:[(0,b.jsxs)(`div`,{className:`status-item`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Engine State`}),(0,b.jsx)(`span`,{className:`value`,children:i?.is_indexing?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`span`,{className:`indicator indexing`}),` Syncing...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`span`,{className:`indicator online`}),` Idle`]})})]}),(0,b.jsxs)(`div`,{className:`status-item`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Vector Backend`}),(0,b.jsxs)(`span`,{className:`value`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-database`,style:{marginRight:`5px`}}),(0,b.jsxs)(`span`,{children:[i?.vector_store_provider===`chroma`?`ChromaDB`:`Qdrant`,` (`,(i?.vector_store_mode||`embedded`)===`embedded`?`Embedded`:`Remote`,`)`]}),i?.vector_db_status&&(0,b.jsx)(`span`,{className:`badge ${i.vector_db_status===`Healthy`?`badge-success`:`badge-danger`}`,style:{marginLeft:`6px`,fontSize:`0.75rem`,padding:`2px 6px`},"data-testid":`vector-db-status-badge`,children:i.vector_db_status})]})]}),(0,b.jsxs)(`div`,{className:`status-item`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Collection`}),(0,b.jsx)(`span`,{className:`value code`,children:i?.vector_store_collection||`knowledge_rag_v1`})]})]})]}),(0,b.jsxs)(`nav`,{className:`dashboard-nav ${n?`drawer-open`:``}`,children:[(0,b.jsxs)(`button`,{className:`nav-tab ${e===`overview`?`active`:``}`,onClick:()=>{t(`overview`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-chart-pie`}),` Overview`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`navigator`||e===`topology`?`active`:``}`,onClick:()=>{t(`navigator`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-fork`}),` Navigator`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`git-repos`?`active`:``}`,onClick:()=>{t(`git-repos`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`}),` Git Repositories`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`local-paths`?`active`:``}`,onClick:()=>{t(`local-paths`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`}),` Local Paths`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`local-storage`?`active`:``}`,onClick:()=>{t(`local-storage`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`}),` Local Storage`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`ingestion-catalog`?`active`:``}`,onClick:()=>{t(`ingestion-catalog`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-book-bookmark`}),` Ingestion Catalog`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`search-inspector`?`active`:``}`,onClick:()=>{t(`search-inspector`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`}),` Search & Inspector`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`settings`?`active`:``}`,onClick:()=>{t(`settings`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-gear`}),` Settings`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`diagnostics`?`active`:``}`,onClick:()=>{t(`diagnostics`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Diagnostics & Logs`]})]}),(0,b.jsxs)(`main`,{className:`dashboard-main`,children:[e===`overview`&&(0,b.jsx)(T,{stats:i,refreshStats:o}),(e===`navigator`||e===`topology`)&&(0,b.jsx)(ye,{}),e===`git-repos`&&(0,b.jsx)(te,{refreshStats:o}),e===`local-paths`&&(0,b.jsx)(ne,{refreshStats:o}),e===`local-storage`&&(0,b.jsx)(xe,{refreshStats:o}),e===`ingestion-catalog`&&(0,b.jsx)(Se,{}),e===`search-inspector`&&(0,b.jsx)(re,{}),e===`settings`&&(0,b.jsx)(le,{stats:i,refreshStats:o}),e===`diagnostics`&&(0,b.jsx)(ue,{})]}),(0,b.jsx)(`footer`,{className:`dashboard-footer`,children:(0,b.jsx)(`p`,{children:`ContextCortex MCP • Universal Code & Knowledge RAG • 2026`})})]})})}(0,v.createRoot)(document.getElementById(`root`)).render((0,b.jsx)(_.StrictMode,{children:(0,b.jsx)(w,{children:(0,b.jsx)(Ce,{})})})); \ No newline at end of file diff --git a/frontend/dist/assets/index-Bk22mWpi.js b/frontend/dist/assets/index-Bk22mWpi.js new file mode 100644 index 0000000..c5b822f --- /dev/null +++ b/frontend/dist/assets/index-Bk22mWpi.js @@ -0,0 +1,10 @@ +var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,o)=>(o=n==null?{}:e(i(n)),s(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n));(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var l=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.consumer`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.for(`react.activity`),p=Symbol.iterator;function m(e){return typeof e!=`object`||!e?null:(e=p&&e[p]||e[`@@iterator`],typeof e==`function`?e:null)}var h={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},g=Object.assign,_={};function v(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function y(){}y.prototype=v.prototype;function b(e,t,n){this.props=e,this.context=t,this.refs=_,this.updater=n||h}var x=b.prototype=new y;x.constructor=b,g(x,v.prototype),x.isPureReactComponent=!0;var S=Array.isArray;function C(){}var w={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function E(e,n,r){var i=r.ref;return{$$typeof:t,type:e,key:n,ref:i===void 0?null:i,props:r}}function D(e,t){return E(e.type,t,e.props)}function O(e){return typeof e==`object`&&!!e&&e.$$typeof===t}function k(e){var t={"=":`=0`,":":`=2`};return`$`+e.replace(/[=:]/g,function(e){return t[e]})}var ee=/\/+/g;function A(e,t){return typeof e==`object`&&e&&e.key!=null?k(``+e.key):t.toString(36)}function te(e){switch(e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason;default:switch(typeof e.status==`string`?e.then(C,C):(e.status=`pending`,e.then(function(t){e.status===`pending`&&(e.status=`fulfilled`,e.value=t)},function(t){e.status===`pending`&&(e.status=`rejected`,e.reason=t)})),e.status){case`fulfilled`:return e.value;case`rejected`:throw e.reason}}throw e}function ne(e,r,i,a,o){var s=typeof e;(s===`undefined`||s===`boolean`)&&(e=null);var c=!1;if(e===null)c=!0;else switch(s){case`bigint`:case`string`:case`number`:c=!0;break;case`object`:switch(e.$$typeof){case t:case n:c=!0;break;case d:return c=e._init,ne(c(e._payload),r,i,a,o)}}if(c)return o=o(e),c=a===``?`.`+A(e,0):a,S(o)?(i=``,c!=null&&(i=c.replace(ee,`$&/`)+`/`),ne(o,r,i,``,function(e){return e})):o!=null&&(O(o)&&(o=D(o,i+(o.key==null||e&&e.key===o.key?``:(``+o.key).replace(ee,`$&/`)+`/`)+c)),r.push(o)),1;c=0;var l=a===``?`.`:a+`:`;if(S(e))for(var u=0;u{t.exports=l()})),d=o((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(e.unstable_now=void 0,typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=!1,_=typeof setTimeout==`function`?setTimeout:null,v=typeof clearTimeout==`function`?clearTimeout:null,y=typeof setImmediate<`u`?setImmediate:null;function b(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function x(e){if(h=!1,b(e),!m){if(n(c)!==null)m=!0,S||(S=!0,O());else{var t=n(l);t!==null&&A(x,t.startTime-e)}}}var S=!1,C=-1,w=5,T=-1;function E(){return g?!0:!(e.unstable_now()-Tt&&E());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=t);if(t=e.unstable_now(),typeof s==`function`){d.callback=s,b(t),i=!0;break b}d===n(c)&&r(c),b(t)}else r(c);d=n(c)}if(d!==null)i=!0;else{var u=n(l);u!==null&&A(x,u.startTime-t),i=!1}}break a}finally{d=null,f=a,p=!1}}}finally{i?O():S=!1}}}var O;if(typeof y==`function`)O=function(){y(D)};else if(typeof MessageChannel<`u`){var k=new MessageChannel,ee=k.port2;k.port1.onmessage=D,O=function(){ee.postMessage(null)}}else O=function(){_(D,0)};function A(t,n){C=_(function(){t(e.unstable_now())},n)}e.unstable_IdlePriority=5,e.unstable_ImmediatePriority=1,e.unstable_LowPriority=4,e.unstable_NormalPriority=3,e.unstable_Profiling=null,e.unstable_UserBlockingPriority=2,e.unstable_cancelCallback=function(e){e.callback=null},e.unstable_forceFrameRate=function(e){0>e||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(v(C),C=-1):h=!0,A(x,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,S||(S=!0,O()))),r},e.unstable_shouldYield=E,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),f=o(((e,t)=>{t.exports=d()})),p=o((e=>{var t=u();function n(e){var t=`https://react.dev/errors/`+e;if(1{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=p()})),h=o((e=>{var t=f(),n=u(),r=m();function i(e){var t=`https://react.dev/errors/`+e;if(1oe||(e.current=ae[oe],ae[oe]=null,oe--)}function F(e,t){oe++,ae[oe]=e.current,e.current=t}var ce=se(null),le=se(null),ue=se(null),de=se(null);function fe(e,t){switch(F(ue,t),F(le,e),F(ce,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?Vd(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=Vd(t),e=Hd(t,e);else switch(e){case`svg`:e=1;break;case`math`:e=2;break;default:e=0}}P(ce),F(ce,e)}function pe(){P(ce),P(le),P(ue)}function me(e){e.memoizedState!==null&&F(de,e);var t=ce.current,n=Hd(t,e.type);t!==n&&(F(le,e),F(ce,n))}function he(e){le.current===e&&(P(ce),P(le)),de.current===e&&(P(de),Qf._currentValue=N)}var ge,_e;function ve(e){if(ge===void 0)try{throw Error()}catch(e){var t=e.stack.trim().match(/\n( *(at )?)/);ge=t&&t[1]||``,_e=-1)`:-1i||c[r]!==l[i]){var u=` +`+c[r].replace(` at new `,` at `);return e.displayName&&u.includes(``)&&(u=u.replace(``,e.displayName)),u}while(1<=r&&0<=i);break}}}finally{ye=!1,Error.prepareStackTrace=n}return(n=e?e.displayName||e.name:``)?ve(n):``}function xe(e,t){switch(e.tag){case 26:case 27:case 5:return ve(e.type);case 16:return ve(`Lazy`);case 13:return e.child!==t&&t!==null?ve(`Suspense Fallback`):ve(`Suspense`);case 19:return ve(`SuspenseList`);case 0:case 15:return be(e.type,!1);case 11:return be(e.type.render,!1);case 1:return be(e.type,!0);case 31:return ve(`Activity`);default:return``}}function Se(e){try{var t=``,n=null;do t+=xe(e,n),n=e,e=e.return;while(e);return t}catch(e){return` +Error generating stack: `+e.message+` +`+e.stack}}var Ce=Object.prototype.hasOwnProperty,we=t.unstable_scheduleCallback,Te=t.unstable_cancelCallback,Ee=t.unstable_shouldYield,De=t.unstable_requestPaint,I=t.unstable_now,Oe=t.unstable_getCurrentPriorityLevel,ke=t.unstable_ImmediatePriority,Ae=t.unstable_UserBlockingPriority,je=t.unstable_NormalPriority,Me=t.unstable_LowPriority,Ne=t.unstable_IdlePriority,Pe=t.log,Fe=t.unstable_setDisableYieldValue,Ie=null,Le=null;function Re(e){if(typeof Pe==`function`&&Fe(e),Le&&typeof Le.setStrictMode==`function`)try{Le.setStrictMode(Ie,e)}catch{}}var ze=Math.clz32?Math.clz32:He,Be=Math.log,Ve=Math.LN2;function He(e){return e>>>=0,e===0?32:31-(Be(e)/Ve|0)|0}var Ue=256,We=262144,Ge=4194304;function Ke(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function qe(e,t,n){var r=e.pendingLanes;if(r===0)return 0;var i=0,a=e.suspendedLanes,o=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s===0?(s=r&~a,s===0?o===0?n||(n=r&~e,n!==0&&(i=Ke(n))):i=Ke(o):i=Ke(s)):(r=s&~a,r===0?(o&=s,o===0?n||(n=s&~e,n!==0&&(i=Ke(n))):i=Ke(o)):i=Ke(r)),i===0?0:t!==0&&t!==i&&(t&a)===0&&(a=i&-i,n=t&-t,a>=n||a===32&&n&4194048)?t:i}function Je(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Ye(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Xe(){var e=Ge;return Ge<<=1,!(Ge&62914560)&&(Ge=4194304),e}function Ze(e){for(var t=[],n=0;31>n;n++)t.push(e);return t}function Qe(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function $e(e,t,n,r,i,a){var o=e.pendingLanes;e.pendingLanes=n,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=n,e.entangledLanes&=n,e.errorRecoveryDisabledLanes&=n,e.shellSuspendCounter=0;var s=e.entanglements,c=e.expirationTimes,l=e.hiddenUpdates;for(n=o&~n;0`u`||window.document===void 0||window.document.createElement===void 0),dn=!1;if(un)try{var fn={};Object.defineProperty(fn,"passive",{get:function(){dn=!0}}),window.addEventListener(`test`,fn,fn),window.removeEventListener(`test`,fn,fn)}catch{dn=!1}var pn=null,mn=null,hn=null;function gn(){if(hn)return hn;var e,t=mn,n=t.length,r,i=`value`in pn?pn.value:pn.textContent,a=i.length;for(e=0;e=Jn),Zn=` `,Qn=!1;function $n(e,t){switch(e){case`keyup`:return Kn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function er(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var tr=!1;function nr(e,t){switch(e){case`compositionend`:return er(t);case`keypress`:return t.which===32?(Qn=!0,Zn):null;case`textInput`:return e=t.data,e===Zn&&Qn?null:e;default:return null}}function rr(e,t){if(tr)return e===`compositionend`||!qn&&$n(e,t)?(e=gn(),hn=mn=pn=null,tr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Tr(n)}}function Dr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Dr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Or(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Lt(e.document);t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=Lt(e.document)}return t}function kr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}var Ar=un&&`documentMode`in document&&11>=document.documentMode,jr=null,Mr=null,Nr=null,Pr=!1;function Fr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Pr||jr==null||jr!==Lt(r)||(r=jr,`selectionStart`in r&&kr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Nr&&wr(Nr,r)||(Nr=r,r=Ed(Mr,`onSelect`),0>=o,i-=o,Di=1<<32-ze(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(i,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(i,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(i,d),z&&ki(i,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),z&&ki(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return z&&ki(a,g),u}for(h=r(h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),z&&ki(a,g),u}function b(e,r,o,c){if(typeof o==`object`&&o&&o.type===y&&o.key===null&&(o=o.props.children),typeof o==`object`&&o){switch(o.$$typeof){case _:a:{for(var l=o.key;r!==null;){if(r.key===l){if(l=o.type,l===y){if(r.tag===7){n(e,r.sibling),c=a(r,o.props.children),c.return=e,e=c;break a}}else if(r.elementType===l||typeof l==`object`&&l&&l.$$typeof===O&&Oa(l)===r.type){n(e,r.sibling),c=a(r,o.props),Fa(c,o),c.return=e,e=c;break a}n(e,r);break}t(e,r),r=r.sibling}o.type===y?(c=mi(o.props.children,e.mode,c,o.key),c.return=e,e=c):(c=pi(o.type,o.key,o.props,null,e.mode,c),Fa(c,o),c.return=e,e=c)}return s(e);case v:a:{for(l=o.key;r!==null;){if(r.key===l){if(r.tag===4&&r.stateNode.containerInfo===o.containerInfo&&r.stateNode.implementation===o.implementation){n(e,r.sibling),c=a(r,o.children||[]),c.return=e,e=c;break a}n(e,r);break}t(e,r),r=r.sibling}c=_i(o,e.mode,c),c.return=e,e=c}return s(e);case O:return o=Oa(o),b(e,r,o,c)}if(ie(o))return h(e,r,o,c);if(te(o)){if(l=te(o),typeof l!=`function`)throw Error(i(150));return o=l.call(o),g(e,r,o,c)}if(typeof o.then==`function`)return b(e,r,Pa(o),c);if(o.$$typeof===C)return b(e,r,na(e,o),c);Ia(e,o)}return typeof o==`string`&&o!==``||typeof o==`number`||typeof o==`bigint`?(o=``+o,r!==null&&r.tag===6?(n(e,r.sibling),c=a(r,o),c.return=e,e=c):(n(e,r),c=hi(o,e.mode,c),c.return=e,e=c),s(e)):n(e,r)}return function(e,t,n,r){try{Na=0;var i=b(e,t,n,r);return Ma=null,i}catch(t){if(t===Sa||t===wa)throw t;var a=li(29,t,null,e.mode);return a.lanes=r,a.return=e,a}}}var Ra=La(!0),za=La(!1),Ba=!1;function Va(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function Ha(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function Ua(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function Wa(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,G&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,t=oi(e),ai(e,null,n),t}return ni(e,r,t,n),oi(e)}function Ga(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194048)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tt(e,n)}}function Ka(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={lane:n.lane,tag:n.tag,payload:n.payload,callback:null,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,callbacks:r.callbacks},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}var qa=!1;function Ja(){if(qa){var e=pa;if(e!==null)throw e}}function Ya(e,t,n,r){qa=!1;var i=e.updateQueue;Ba=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane&-536870913,p=f!==s.lane;if(p?(J&f)===f:(r&f)===f){f!==0&&f===fa&&(qa=!0),u!==null&&(u=u.next={lane:0,tag:s.tag,payload:s.payload,callback:null,next:null});a:{var m=e,g=s;f=t;var _=n;switch(g.tag){case 1:if(m=g.payload,typeof m==`function`){d=m.call(_,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=g.payload,f=typeof m==`function`?m.call(_,d,f):m,f==null)break a;d=h({},d,f);break a;case 2:Ba=!0}}f=s.callback,f!==null&&(e.flags|=64,p&&(e.flags|=8192),p=i.callbacks,p===null?i.callbacks=[f]:p.push(f))}else p={lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;p=s,s=p.next,p.next=null,i.lastBaseUpdate=p,i.shared.pending=null}}while(1);u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,a===null&&(i.shared.lanes=0),Gl|=o,e.lanes=o,e.memoizedState=d}}function Xa(e,t){if(typeof e!=`function`)throw Error(i(191,e));e.call(t)}function Za(e,t){var n=e.callbacks;if(n!==null)for(e.callbacks=null,e=0;ea?a:8;var o=j.T,s={};j.T=s,Fs(e,!1,t,n);try{var c=i(),l=j.S;l!==null&&l(s,c),typeof c==`object`&&c&&typeof c.then==`function`?Ps(e,t,ga(c,r),pu(e)):Ps(e,t,r,pu(e))}catch(n){Ps(e,t,{then:function(){},status:`rejected`,reason:n},pu())}finally{M.p=a,o!==null&&s.types!==null&&(o.types=s.types),j.T=o}}function ws(){}function Ts(e,t,n,r){if(e.tag!==5)throw Error(i(476));var a=Es(e).queue;Cs(e,a,t,N,n===null?ws:function(){return Ds(e),n(r)})}function Es(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:N,baseState:N,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Io,lastRenderedState:N},next:null};var n={};return t.next={memoizedState:n,baseState:n,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Io,lastRenderedState:n},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Ds(e){var t=Es(e);t.next===null&&(t=e.alternate.memoizedState),Ps(e,t.next.queue,{},pu())}function Os(){return ta(Qf)}function ks(){return jo().memoizedState}function As(){return jo().memoizedState}function js(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var n=pu();e=Ua(n);var r=Wa(t,e,n);r!==null&&(hu(r,t,n),Ga(r,t,n)),t={cache:ca()},e.payload=t;return}t=t.return}}function Ms(e,t,n){var r=pu();n={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null},Is(e)?Ls(t,n):(n=ri(e,t,n,r),n!==null&&(hu(n,e,r),Rs(n,t,r)))}function Ns(e,t,n){Ps(e,t,n,pu())}function Ps(e,t,n,r){var i={lane:r,revertLane:0,gesture:null,action:n,hasEagerState:!1,eagerState:null,next:null};if(Is(e))Ls(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Cr(s,o))return ni(e,t,i,0),K===null&&ti(),!1}catch{}if(n=ri(e,t,i,r),n!==null)return hu(n,e,r),Rs(n,t,r),!0}return!1}function Fs(e,t,n,r){if(r={lane:2,revertLane:dd(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Is(e)){if(t)throw Error(i(479))}else t=ri(e,n,r,2),t!==null&&hu(t,e,2)}function Is(e){var t=e.alternate;return e===B||t!==null&&t===B}function Ls(e,t){go=ho=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function Rs(e,t,n){if(n&4194048){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,tt(e,n)}}var zs={readContext:ta,use:Po,useCallback:H,useContext:H,useEffect:H,useImperativeHandle:H,useLayoutEffect:H,useInsertionEffect:H,useMemo:H,useReducer:H,useRef:H,useState:H,useDebugValue:H,useDeferredValue:H,useTransition:H,useSyncExternalStore:H,useId:H,useHostTransitionStatus:H,useFormState:H,useActionState:H,useOptimistic:H,useMemoCache:H,useCacheRefresh:H};zs.useEffectEvent=H;var Bs={readContext:ta,use:Po,useCallback:function(e,t){return Ao().memoizedState=[e,t===void 0?null:t],e},useContext:ta,useEffect:us,useImperativeHandle:function(e,t,n){n=n==null?null:n.concat([e]),cs(4194308,4,gs.bind(null,t,e),n)},useLayoutEffect:function(e,t){return cs(4194308,4,e,t)},useInsertionEffect:function(e,t){cs(4,2,e,t)},useMemo:function(e,t){var n=Ao();t=t===void 0?null:t;var r=e();if(_o){Re(!0);try{e()}finally{Re(!1)}}return n.memoizedState=[r,t],r},useReducer:function(e,t,n){var r=Ao();if(n!==void 0){var i=n(t);if(_o){Re(!0);try{n(t)}finally{Re(!1)}}}else i=t;return r.memoizedState=r.baseState=i,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:i},r.queue=e,e=e.dispatch=Ms.bind(null,B,e),[r.memoizedState,e]},useRef:function(e){var t=Ao();return e={current:e},t.memoizedState=e},useState:function(e){e=Ko(e);var t=e.queue,n=Ns.bind(null,B,t);return t.dispatch=n,[e.memoizedState,n]},useDebugValue:vs,useDeferredValue:function(e,t){return xs(Ao(),e,t)},useTransition:function(){var e=Ko(!1);return e=Cs.bind(null,B,e.queue,!0,!1),Ao().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,n){var r=B,a=Ao();if(z){if(n===void 0)throw Error(i(407));n=n()}else{if(n=t(),K===null)throw Error(i(349));J&127||Vo(r,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,us(Uo.bind(null,r,o,e),[e]),r.flags|=2048,os(9,{destroy:void 0},Ho.bind(null,r,o,n,t),null),n},useId:function(){var e=Ao(),t=K.identifierPrefix;if(z){var n=Oi,r=Di;n=(r&~(1<<32-ze(r)-1)).toString(32)+n,t=`_`+t+`R_`+n,n=vo++,0<\/script>`,o=o.removeChild(o.firstChild);break;case`select`:o=typeof r.is==`string`?s.createElement(`select`,{is:r.is}):s.createElement(`select`),r.multiple?o.multiple=!0:r.size&&(o.size=r.size);break;default:o=typeof r.is==`string`?s.createElement(a,{is:r.is}):s.createElement(a)}}o[st]=t,o[ct]=r;a:for(s=t.child;s!==null;){if(s.tag===5||s.tag===6)o.appendChild(s.stateNode);else if(s.tag!==4&&s.tag!==27&&s.child!==null){s.child.return=s,s=s.child;continue}if(s===t)break a;for(;s.sibling===null;){if(s.return===null||s.return===t)break a;s=s.return}s.sibling.return=s.return,s=s.sibling}t.stateNode=o;a:switch(Pd(o,a,r),a){case`button`:case`input`:case`select`:case`textarea`:r=!!r.autoFocus;break a;case`img`:r=!0;break a;default:r=!1}r&&Pc(t)}}return U(t),Fc(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,n),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Pc(t);else{if(typeof r!=`string`&&t.stateNode===null)throw Error(i(166));if(e=ue.current,Vi(t)){if(e=t.stateNode,n=t.memoizedProps,r=null,a=Pi,a!==null)switch(a.tag){case 27:case 5:r=a.memoizedProps}e[st]=t,e=!!(e.nodeValue===n||r!==null&&!0===r.suppressHydrationWarning||Md(e.nodeValue,n)),e||Ri(t,!0)}else e=Bd(e).createTextNode(r),e[st]=t,t.stateNode=e}return U(t),null;case 31:if(n=t.memoizedState,e===null||e.memoizedState!==null){if(r=Vi(t),n!==null){if(e===null){if(!r)throw Error(i(318));if(e=t.memoizedState,e=e===null?null:e.dehydrated,!e)throw Error(i(557));e[st]=t}else Hi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),e=!1}else n=Ui(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=n),e=!0;if(!e)return t.flags&256?(lo(t),t):(lo(t),null);if(t.flags&128)throw Error(i(558))}return U(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(a=Vi(t),r!==null&&r.dehydrated!==null){if(e===null){if(!a)throw Error(i(318));if(a=t.memoizedState,a=a===null?null:a.dehydrated,!a)throw Error(i(317));a[st]=t}else Hi(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;U(t),a=!1}else a=Ui(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=a),a=!0;if(!a)return t.flags&256?(lo(t),t):(lo(t),null)}return lo(t),t.flags&128?(t.lanes=n,t):(n=r!==null,e=e!==null&&e.memoizedState!==null,n&&(r=t.child,a=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(a=r.alternate.memoizedState.cachePool.pool),o=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(o=r.memoizedState.cachePool.pool),o!==a&&(r.flags|=2048)),n!==e&&n&&(t.child.flags|=8192),Lc(t,t.updateQueue),U(t),null);case 4:return pe(),e===null&&Sd(t.stateNode.containerInfo),U(t),null;case 10:return Yi(t.type),U(t),null;case 19:if(P(uo),r=t.memoizedState,r===null)return U(t),null;if(a=!!(t.flags&128),o=r.rendering,o===null){if(a)Rc(r,!1);else{if(X!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(o=fo(e),o!==null){for(t.flags|=128,Rc(r,!1),e=o.updateQueue,t.updateQueue=e,Lc(t,e),t.subtreeFlags=0,e=n,n=t.child;n!==null;)fi(n,e),n=n.sibling;return F(uo,uo.current&1|2),z&&ki(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&I()>tu&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304)}}else{if(!a){if(e=fo(o),e!==null){if(t.flags|=128,a=!0,e=e.updateQueue,t.updateQueue=e,Lc(t,e),Rc(r,!0),r.tail===null&&r.tailMode===`hidden`&&!o.alternate&&!z)return U(t),null}else 2*I()-r.renderingStartTime>tu&&n!==536870912&&(t.flags|=128,a=!0,Rc(r,!1),t.lanes=4194304)}r.isBackwards?(o.sibling=t.child,t.child=o):(e=r.last,e===null?t.child=o:e.sibling=o,r.last=o)}return r.tail===null?(U(t),null):(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=I(),e.sibling=null,n=uo.current,F(uo,a?n&1|2:n&1),z&&ki(t,r.treeForkCount),e);case 22:case 23:return lo(t),no(),r=t.memoizedState!==null,e===null?r&&(t.flags|=8192):e.memoizedState!==null!==r&&(t.flags|=8192),r?n&536870912&&!(t.flags&128)&&(U(t),t.subtreeFlags&6&&(t.flags|=8192)):U(t),n=t.updateQueue,n!==null&&Lc(t,n.retryQueue),n=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(n=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==n&&(t.flags|=2048),e!==null&&P(va),null;case 24:return n=null,e!==null&&(n=e.memoizedState.cache),t.memoizedState.cache!==n&&(t.flags|=2048),Yi(sa),U(t),null;case 25:return null;case 30:return null}throw Error(i(156,t.tag))}function Bc(e,t){switch(Mi(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Yi(sa),pe(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return he(t),null;case 31:if(t.memoizedState!==null){if(lo(t),t.alternate===null)throw Error(i(340));Hi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if(lo(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(i(340));Hi()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return P(uo),null;case 4:return pe(),null;case 10:return Yi(t.type),null;case 22:case 23:return lo(t),no(),e!==null&&P(va),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Yi(sa),null;case 25:return null;default:return null}}function Vc(e,t){switch(Mi(t),t.tag){case 3:Yi(sa),pe();break;case 26:case 27:case 5:he(t);break;case 4:pe();break;case 31:t.memoizedState!==null&&lo(t);break;case 13:lo(t);break;case 19:P(uo);break;case 10:Yi(t.type);break;case 22:case 23:lo(t),no(),e!==null&&P(va);break;case 24:Yi(sa)}}function Hc(e,t){try{var n=t.updateQueue,r=n===null?null:n.lastEffect;if(r!==null){var i=r.next;n=i;do{if((n.tag&e)===e){r=void 0;var a=n.create,o=n.inst;r=a(),o.destroy=r}n=n.next}while(n!==i)}}catch(e){Z(t,t.return,e)}}function Uc(e,t,n){try{var r=t.updateQueue,i=r===null?null:r.lastEffect;if(i!==null){var a=i.next;r=a;do{if((r.tag&e)===e){var o=r.inst,s=o.destroy;if(s!==void 0){o.destroy=void 0,i=t;var c=n,l=s;try{l()}catch(e){Z(i,c,e)}}}r=r.next}while(r!==a)}}catch(e){Z(t,t.return,e)}}function Wc(e){var t=e.updateQueue;if(t!==null){var n=e.stateNode;try{Za(t,n)}catch(t){Z(e,e.return,t)}}}function Gc(e,t,n){n.props=qs(e.type,e.memoizedProps),n.state=e.memoizedState;try{n.componentWillUnmount()}catch(n){Z(e,t,n)}}function Kc(e,t){try{var n=e.ref;if(n!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof n==`function`?e.refCleanup=n(r):n.current=r}}catch(n){Z(e,t,n)}}function qc(e,t){var n=e.ref,r=e.refCleanup;if(n!==null){if(typeof r==`function`)try{r()}catch(n){Z(e,t,n)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof n==`function`)try{n(null)}catch(n){Z(e,t,n)}else n.current=null}}function Jc(e){var t=e.type,n=e.memoizedProps,r=e.stateNode;try{a:switch(t){case`button`:case`input`:case`select`:case`textarea`:n.autoFocus&&r.focus();break a;case`img`:n.src?r.src=n.src:n.srcSet&&(r.srcset=n.srcSet)}}catch(t){Z(e,e.return,t)}}function Yc(e,t,n){try{var r=e.stateNode;Fd(r,e.type,n,t),r[ct]=t}catch(t){Z(e,e.return,t)}}function Xc(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&Zd(e.type)||e.tag===4}function Zc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||Xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&Zd(e.type)||e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Qc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n).insertBefore(e,t):(t=n.nodeType===9?n.body:n.nodeName===`HTML`?n.ownerDocument.body:n,t.appendChild(e),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=en));else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode,t=null),e=e.child,e!==null))for(Qc(e,t,n),e=e.sibling;e!==null;)Qc(e,t,n),e=e.sibling}function $c(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(r===27&&Zd(e.type)&&(n=e.stateNode),e=e.child,e!==null))for($c(e,t,n),e=e.sibling;e!==null;)$c(e,t,n),e=e.sibling}function el(e){var t=e.stateNode,n=e.memoizedProps;try{for(var r=e.type,i=t.attributes;i.length;)t.removeAttributeNode(i[0]);Pd(t,r,n),t[st]=e,t[ct]=n}catch(t){Z(e,e.return,t)}}var tl=!1,nl=!1,rl=!1,il=typeof WeakSet==`function`?WeakSet:Set,al=null;function ol(e,t){if(e=e.containerInfo,Rd=sp,e=Or(e),kr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var a=r.anchorOffset,o=r.focusNode;r=r.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||r!==0&&f.nodeType!==3||(l=s+r),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===r&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(zd={focusedElem:e,selectionRange:n},sp=!1,al=t;al!==null;)if(t=al,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,al=e;else for(;al!==null;){switch(t=al,o=t.alternate,e=t.flags,t.tag){case 0:if(e&4&&(e=t.updateQueue,e=e===null?null:e.events,e!==null))for(n=0;n title`))),Pd(o,r,n),o[st]=e,bt(o),r=o;break a;case`link`:var s=Vf(`link`,`href`,a).get(r+(n.href||``));if(s){for(var c=0;cg&&(o=g,g=h,h=o);var _=Er(s,h),v=Er(s,g);if(_&&v&&(p.rangeCount!==1||p.anchorNode!==_.node||p.anchorOffset!==_.offset||p.focusNode!==v.node||p.focusOffset!==v.offset)){var y=d.createRange();y.setStart(_.node,_.offset),p.removeAllRanges(),h>g?(p.addRange(y),p.extend(v.node,v.offset)):(y.setEnd(v.node,v.offset),p.addRange(y))}}}}for(d=[],p=s;p=p.parentNode;)p.nodeType===1&&d.push({element:p,left:p.scrollLeft,top:p.scrollTop});for(typeof s.focus==`function`&&s.focus(),s=0;sn?32:n,j.T=null,n=lu,lu=null;var o=au,s=su;if(iu=0,ou=au=null,su=0,G&6)throw Error(i(331));var c=G;if(G|=4,Fl(o.current),Dl(o,o.current,s,n),G=c,id(0,!1),Le&&typeof Le.onPostCommitFiberRoot==`function`)try{Le.onPostCommitFiberRoot(Ie,o)}catch{}return!0}finally{M.p=a,j.T=r,Vu(e,t)}}function Wu(e,t,n){t=yi(n,t),t=$s(e.stateNode,t,2),e=Wa(e,t,2),e!==null&&(Qe(e,2),rd(e))}function Z(e,t,n){if(e.tag===3)Wu(e,e,n);else for(;t!==null;){if(t.tag===3){Wu(t,e,n);break}if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError==`function`||typeof r.componentDidCatch==`function`&&(ru===null||!ru.has(r))){e=yi(n,e),n=ec(2),r=Wa(t,n,2),r!==null&&(tc(n,r,t,e),Qe(r,2),rd(r));break}}t=t.return}}function Gu(e,t,n){var r=e.pingCache;if(r===null){r=e.pingCache=new zl;var i=new Set;r.set(t,i)}else i=r.get(t),i===void 0&&(i=new Set,r.set(t,i));i.has(n)||(Ul=!0,i.add(n),e=Ku.bind(null,e,t,n),t.then(e,e))}function Ku(e,t,n){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&n,e.warmLanes&=~n,K===e&&(J&n)===n&&(X===4||X===3&&(J&62914560)===J&&300>I()-$l?!(G&2)&&Su(e,0):ql|=n,Yl===J&&(Yl=0)),rd(e)}function qu(e,t){t===0&&(t=Xe()),e=ii(e,t),e!==null&&(Qe(e,t),rd(e))}function Ju(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),qu(e,n)}function Yu(e,t){var n=0;switch(e.tag){case 31:case 13:var r=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(i(314))}r!==null&&r.delete(t),qu(e,n)}function Xu(e,t){return we(e,t)}var Zu=null,Qu=null,$u=!1,ed=!1,td=!1,nd=0;function rd(e){e!==Qu&&e.next===null&&(Qu===null?Zu=Qu=e:Qu=Qu.next=e),ed=!0,$u||($u=!0,ud())}function id(e,t){if(!td&&ed){td=!0;do for(var n=!1,r=Zu;r!==null;){if(!t){if(e!==0){var i=r.pendingLanes;if(i===0)var a=0;else{var o=r.suspendedLanes,s=r.pingedLanes;a=(1<<31-ze(42|e)+1)-1,a&=i&~(o&~s),a=a&201326741?a&201326741|1:a?a|2:0}a!==0&&(n=!0,ld(r,a))}else a=J,a=qe(r,r===K?a:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),!(a&3)||Je(r,a)||(n=!0,ld(r,a))}r=r.next}while(n);td=!1}}function ad(){od()}function od(){ed=$u=!1;var e=0;nd!==0&&Gd()&&(e=nd);for(var t=I(),n=null,r=Zu;r!==null;){var i=r.next,a=sd(r,t);a===0?(r.next=null,n===null?Zu=i:n.next=i,i===null&&(Qu=n)):(n=r,(e!==0||a&3)&&(ed=!0)),r=i}iu!==0&&iu!==5||id(e,!1),nd!==0&&(nd=0)}function sd(e,t){for(var n=e.suspendedLanes,r=e.pingedLanes,i=e.expirationTimes,a=e.pendingLanes&-62914561;0s)break;var u=c.transferSize,d=c.initiatorType;u&&Id(d)&&(c=c.responseEnd,o+=u*(c`u`?null:document;function xf(e,t,n){var r=bf;if(r&&typeof t==`string`&&t){var i=zt(t);i=`link[rel="`+e+`"][href="`+i+`"]`,typeof n==`string`&&(i+=`[crossorigin="`+n+`"]`),hf.has(i)||(hf.add(i),e={rel:e,crossOrigin:n,href:t},r.querySelector(i)===null&&(t=r.createElement(`link`),Pd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function Sf(e){_f.D(e),xf(`dns-prefetch`,e,null)}function Cf(e,t){_f.C(e,t),xf(`preconnect`,e,t)}function wf(e,t,n){_f.L(e,t,n);var r=bf;if(r&&e&&t){var i=`link[rel="preload"][as="`+zt(t)+`"]`;t===`image`&&n&&n.imageSrcSet?(i+=`[imagesrcset="`+zt(n.imageSrcSet)+`"]`,typeof n.imageSizes==`string`&&(i+=`[imagesizes="`+zt(n.imageSizes)+`"]`)):i+=`[href="`+zt(e)+`"]`;var a=i;switch(t){case`style`:a=Af(e);break;case`script`:a=Pf(e)}mf.has(a)||(e=h({rel:`preload`,href:t===`image`&&n&&n.imageSrcSet?void 0:e,as:t},n),mf.set(a,e),r.querySelector(i)!==null||t===`style`&&r.querySelector(jf(a))||t===`script`&&r.querySelector(Ff(a))||(t=r.createElement(`link`),Pd(t,`link`,e),bt(t),r.head.appendChild(t)))}}function Tf(e,t){_f.m(e,t);var n=bf;if(n&&e){var r=t&&typeof t.as==`string`?t.as:`script`,i=`link[rel="modulepreload"][as="`+zt(r)+`"][href="`+zt(e)+`"]`,a=i;switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:a=Pf(e)}if(!mf.has(a)&&(e=h({rel:`modulepreload`,href:e},t),mf.set(a,e),n.querySelector(i)===null)){switch(r){case`audioworklet`:case`paintworklet`:case`serviceworker`:case`sharedworker`:case`worker`:case`script`:if(n.querySelector(Ff(a)))return}r=n.createElement(`link`),Pd(r,`link`,e),bt(r),n.head.appendChild(r)}}}function Ef(e,t,n){_f.S(e,t,n);var r=bf;if(r&&e){var i=yt(r).hoistableStyles,a=Af(e);t||=`default`;var o=i.get(a);if(!o){var s={loading:0,preload:null};if(o=r.querySelector(jf(a)))s.loading=5;else{e=h({rel:`stylesheet`,href:e,"data-precedence":t},n),(n=mf.get(a))&&Rf(e,n);var c=o=r.createElement(`link`);bt(c),Pd(c,`link`,e),c._p=new Promise(function(e,t){c.onload=e,c.onerror=t}),c.addEventListener(`load`,function(){s.loading|=1}),c.addEventListener(`error`,function(){s.loading|=2}),s.loading|=4,Lf(o,t,r)}o={type:`stylesheet`,instance:o,count:1,state:s},i.set(a,o)}}}function Df(e,t){_f.X(e,t);var n=bf;if(n&&e){var r=yt(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),bt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function Of(e,t){_f.M(e,t);var n=bf;if(n&&e){var r=yt(n).hoistableScripts,i=Pf(e),a=r.get(i);a||(a=n.querySelector(Ff(i)),a||(e=h({src:e,async:!0,type:`module`},t),(t=mf.get(i))&&zf(e,t),a=n.createElement(`script`),bt(a),Pd(a,`link`,e),n.head.appendChild(a)),a={type:`script`,instance:a,count:1,state:null},r.set(i,a))}}function kf(e,t,n,r){var a=(a=ue.current)?gf(a):null;if(!a)throw Error(i(446));switch(e){case`meta`:case`title`:return null;case`style`:return typeof n.precedence==`string`&&typeof n.href==`string`?(t=Af(n.href),n=yt(a).hoistableStyles,r=n.get(t),r||(r={type:`style`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};case`link`:if(n.rel===`stylesheet`&&typeof n.href==`string`&&typeof n.precedence==`string`){e=Af(n.href);var o=yt(a).hoistableStyles,s=o.get(e);if(s||(a=a.ownerDocument||a,s={type:`stylesheet`,instance:null,count:0,state:{loading:0,preload:null}},o.set(e,s),(o=a.querySelector(jf(e)))&&!o._p&&(s.instance=o,s.state.loading=5),mf.has(e)||(n={rel:`preload`,as:`style`,href:n.href,crossOrigin:n.crossOrigin,integrity:n.integrity,media:n.media,hrefLang:n.hrefLang,referrerPolicy:n.referrerPolicy},mf.set(e,n),o||Nf(a,e,n,s.state))),t&&r===null)throw Error(i(528,``));return s}if(t&&r!==null)throw Error(i(529,``));return null;case`script`:return t=n.async,n=n.src,typeof n==`string`&&t&&typeof t!=`function`&&typeof t!=`symbol`?(t=Pf(n),n=yt(a).hoistableScripts,r=n.get(t),r||(r={type:`script`,instance:null,count:0,state:null},n.set(t,r)),r):{type:`void`,instance:null,count:0,state:null};default:throw Error(i(444,e))}}function Af(e){return`href="`+zt(e)+`"`}function jf(e){return`link[rel="stylesheet"][`+e+`]`}function Mf(e){return h({},e,{"data-precedence":e.precedence,precedence:null})}function Nf(e,t,n,r){e.querySelector(`link[rel="preload"][as="style"][`+t+`]`)?r.loading=1:(t=e.createElement(`link`),r.preload=t,t.addEventListener(`load`,function(){return r.loading|=1}),t.addEventListener(`error`,function(){return r.loading|=2}),Pd(t,`link`,n),bt(t),e.head.appendChild(t))}function Pf(e){return`[src="`+zt(e)+`"]`}function Ff(e){return`script[async]`+e}function If(e,t,n){if(t.count++,t.instance===null)switch(t.type){case`style`:var r=e.querySelector(`style[data-href~="`+zt(n.href)+`"]`);if(r)return t.instance=r,bt(r),r;var a=h({},n,{"data-href":n.href,"data-precedence":n.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement(`style`),bt(r),Pd(r,`style`,a),Lf(r,n.precedence,e),t.instance=r;case`stylesheet`:a=Af(n.href);var o=e.querySelector(jf(a));if(o)return t.state.loading|=4,t.instance=o,bt(o),o;r=Mf(n),(a=mf.get(a))&&Rf(r,a),o=(e.ownerDocument||e).createElement(`link`),bt(o);var s=o;return s._p=new Promise(function(e,t){s.onload=e,s.onerror=t}),Pd(o,`link`,r),t.state.loading|=4,Lf(o,n.precedence,e),t.instance=o;case`script`:return o=Pf(n.src),(a=e.querySelector(Ff(o)))?(t.instance=a,bt(a),a):(r=n,(a=mf.get(o))&&(r=h({},n),zf(r,a)),e=e.ownerDocument||e,a=e.createElement(`script`),bt(a),Pd(a,`link`,r),e.head.appendChild(a),t.instance=a);case`void`:return null;default:throw Error(i(443,t.type))}else t.type===`stylesheet`&&!(t.state.loading&4)&&(r=t.instance,t.state.loading|=4,Lf(r,n.precedence,e));return t.instance}function Lf(e,t,n){for(var r=n.querySelectorAll(`link[rel="stylesheet"][data-precedence],style[data-precedence]`),i=r.length?r[r.length-1]:null,a=i,o=0;o title`):null)}function Uf(e,t,n){if(n===1||t.itemProp!=null)return!1;switch(e){case`meta`:case`title`:return!0;case`style`:if(typeof t.precedence!=`string`||typeof t.href!=`string`||t.href===``)break;return!0;case`link`:if(typeof t.rel!=`string`||typeof t.href!=`string`||t.href===``||t.onLoad||t.onError)break;switch(t.rel){case`stylesheet`:return e=t.disabled,typeof t.precedence==`string`&&e==null;default:return!0}case`script`:if(t.async&&typeof t.async!=`function`&&typeof t.async!=`symbol`&&!t.onLoad&&!t.onError&&t.src&&typeof t.src==`string`)return!0}return!1}function Wf(e){return!(e.type===`stylesheet`&&!(e.state.loading&3))}function Gf(e,t,n,r){if(n.type===`stylesheet`&&(typeof r.media!=`string`||!1!==matchMedia(r.media).matches)&&!(n.state.loading&4)){if(n.instance===null){var i=Af(r.href),a=t.querySelector(jf(i));if(a){t=a._p,typeof t==`object`&&t&&typeof t.then==`function`&&(e.count++,e=Jf.bind(e),t.then(e,e)),n.state.loading|=4,n.instance=a,bt(a);return}a=t.ownerDocument||t,r=Mf(r),(i=mf.get(i))&&Rf(r,i),a=a.createElement(`link`),bt(a);var o=a;o._p=new Promise(function(e,t){o.onload=e,o.onerror=t}),Pd(a,`link`,r),n.instance=a}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(n,t),(t=n.state.preload)&&!(n.state.loading&3)&&(e.count++,n=Jf.bind(e),t.addEventListener(`load`,n),t.addEventListener(`error`,n))}}var Kf=0;function qf(e,t){return e.stylesheets&&e.count===0&&Xf(e,e.stylesheets),0Kf?50:800)+t);return e.unsuspend=n,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(i)}}:null}function Jf(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Xf(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Yf=null;function Xf(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Yf=new Map,t.forEach(Zf,e),Yf=null,Jf.call(e))}function Zf(e,t){if(!(t.state.loading&4)){var n=Yf.get(e);if(n)var r=n.get(null);else{n=new Map,Yf.set(e,n);for(var i=e.querySelectorAll(`link[data-precedence],style[data-precedence]`),a=0;a{function n(){if(!(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__>`u`||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!=`function`))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=h()})),_=c(u(),1),v=g(),y=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),b=o(((e,t)=>{t.exports=y()}))(),x=(0,_.createContext)(void 0);function S(){let e=(0,_.useContext)(x);if(!e)throw Error(`useToast must be used within a ToastProvider`);return e.toast}var C=0;function w({children:e}){let[t,n]=(0,_.useState)([]),r=(0,_.useState)(()=>new Map)[0];(0,_.useEffect)(()=>()=>{r.forEach(e=>clearTimeout(e)),r.clear()},[r]);let i=(0,_.useCallback)(e=>{let t=r.get(e);t&&(clearTimeout(t),r.delete(e)),n(t=>t.filter(t=>t.id!==e))},[r]),a=(0,_.useCallback)((e,t=`info`)=>{let i=++C;n(n=>[...n,{id:i,message:e,type:t}]);let a=setTimeout(()=>{r.delete(i),n(e=>e.filter(e=>e.id!==i))},4e3);r.set(i,a)},[r]),o=(0,_.useMemo)(()=>({success:e=>a(e,`success`),error:e=>a(e,`error`),info:e=>a(e,`info`),warning:e=>a(e,`warning`),showToast:(e,t)=>a(e,t||`info`),dismiss:i}),[a,i]);return(0,b.jsxs)(x.Provider,{value:{toast:o},children:[e,(0,b.jsx)(`div`,{className:`toast-container`,"aria-live":`polite`,"aria-atomic":`true`,children:t.map(e=>(0,b.jsxs)(`div`,{className:`toast toast-${e.type}`,role:`status`,children:[e.type===`error`&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`,"aria-hidden":`true`}),e.type===`success`&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`,"aria-hidden":`true`}),e.type===`info`&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-info`,"aria-hidden":`true`}),e.type===`warning`&&(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,"aria-hidden":`true`}),(0,b.jsx)(`span`,{className:`toast-message`,children:e.message}),(0,b.jsx)(`button`,{type:`button`,className:`toast-dismiss-btn`,onClick:()=>i(e.id),"aria-label":`Dismiss notification`,title:`Dismiss`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-xmark`,"aria-hidden":`true`})})]},e.id))})]})}function T({stats:e,refreshStats:t}){let n=S();return e?(0,b.jsxs)(`div`,{className:`tab-content active`,children:[(0,b.jsxs)(`div`,{className:`overview-grid`,children:[(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-brands fa-github`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.repos_count??e.git_repos??0).toLocaleString()}),(0,b.jsx)(`span`,{className:`stat-label`,children:`Git Repositories`})]})]}),(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-code`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.symbols_count||0).toLocaleString()}),(0,b.jsx)(`span`,{className:`stat-label`,children:`AST Code Symbols`})]})]}),(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.files_count||0).toLocaleString()}),(0,b.jsx)(`span`,{className:`stat-label`,children:`Indexed Files`})]})]}),(0,b.jsxs)(`div`,{className:`glass-card stat-metric`,children:[(0,b.jsx)(`div`,{className:`metric-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-network-wired`})}),(0,b.jsxs)(`div`,{className:`metric-info`,children:[(0,b.jsx)(`span`,{className:`stat-number`,children:(e.points_count||0).toLocaleString()}),(0,b.jsxs)(`span`,{className:`stat-label`,children:[(e.vector_store_provider||`Qdrant`).toUpperCase(),` (`,(e.vector_store_mode||`embedded`)===`embedded`?`Embedded`:`Remote`,`) Vectors`]})]})]})]}),(0,b.jsxs)(`div`,{className:`two-col-layout`,style:{marginTop:`20px`},children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-server`}),` System & Embedding Specs`]}),(0,b.jsxs)(`div`,{className:`specs-list`,children:[(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Vector Database:`}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[(0,b.jsxs)(`span`,{className:`badge badge-accent`,children:[e.vector_store_provider===`chroma`?`ChromaDB`:`Qdrant`,` (`,(e.vector_store_mode||`embedded`)===`embedded`?`Embedded Disk`:`Remote Server`,`)`]}),e.vector_db_status&&(0,b.jsx)(`span`,{className:`badge ${e.vector_db_status===`Healthy`?`badge-success`:`badge-danger`}`,"data-testid":`overview-vector-db-status`,children:e.vector_db_status})]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Dense Embedding Model:`}),(0,b.jsx)(`code`,{children:e.dense_model||`bge-small-en-v1.5 (384d)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Sparse BM25 Model:`}),(0,b.jsx)(`code`,{children:e.sparse_model?`${e.sparse_model} (FastEmbed)`:`Qdrant/bm25 (FastEmbed)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Retrieval Strategy:`}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.vector_store_provider===`chroma`?`Dense Vector Cosine Similarity`:`Dense + BM25 Normalized Weighted Fusion`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`AST Chunker:`}),(0,b.jsx)(`span`,{children:`Tree-sitter AST (Classes, Functions, Methods)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Last Global Index:`}),(0,b.jsx)(`span`,{className:`code`,children:e.last_indexed||`Never`})]})]}),(0,b.jsx)(`div`,{style:{marginTop:`20px`},children:(0,b.jsx)(`button`,{className:`btn btn-primary`,onClick:async()=>{try{let e=await fetch(`/admin/api/reindex`,{method:`POST`});if(!e.ok){let t=await e.json().catch(()=>({}));throw Error(t.error||`Failed to trigger reindex`)}n.success(`Re-indexing triggered successfully`),t()}catch(e){n.error(`Reindex error: `+e.message)}},disabled:e.is_indexing,children:e.is_indexing?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Syncing...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Reindex All Sources`]})})})]}),(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-tags`}),` Top Extracted Topics & Symbols`]}),(0,b.jsx)(`div`,{className:`tag-cloud`,children:!e.top_keywords||e.top_keywords.length===0?(0,b.jsx)(`span`,{className:`text-muted`,children:`No topics extracted yet. Sync repositories to populate.`}):e.top_keywords.map(e=>(0,b.jsx)(`span`,{className:`topic-tag`,children:e},e))})]})]})]}):(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsx)(`p`,{children:`Loading...`})})}function E({isOpen:e,onClose:t,onSave:n,alias:r,setAlias:i,url:a,setUrl:o,branch:s,setBranch:c,provider:l,setProvider:u,authUser:d,setAuthUser:f,token:p,setToken:m,isSaving:h}){return e?(0,b.jsx)(`div`,{className:`modal-backdrop`,onClick:e=>{e.target===e.currentTarget&&t()},children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`}),` Register Git Repository`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:t,children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:n,children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-alias`,children:`Repository Alias / Identifier`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-alias`,required:!0,placeholder:`e.g. backend-api or contextcortex`,value:r,onChange:e=>i(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-provider`,children:`Git Provider`}),(0,b.jsxs)(`select`,{id:`repo-provider`,value:l,onChange:e=>u(e.target.value),children:[(0,b.jsx)(`option`,{value:`auto`,children:`Auto-Detect`}),(0,b.jsx)(`option`,{value:`github`,children:`GitHub / GitHub Enterprise`}),(0,b.jsx)(`option`,{value:`gitlab`,children:`GitLab (Cloud / Self-Hosted)`}),(0,b.jsx)(`option`,{value:`gitea`,children:`Gitea / Forgejo`}),(0,b.jsx)(`option`,{value:`bitbucket`,children:`Bitbucket`}),(0,b.jsx)(`option`,{value:`generic`,children:`Generic Git (HTTP / HTTPS)`})]})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-url`,children:`Git Clone URL (HTTP / HTTPS)`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-url`,required:!0,placeholder:`https://github.com/owner/repo.git or http://git.lan:3000/repo.git`,value:a,onChange:e=>o(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-row form-row-3col`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-branch`,children:`Branch / Tag`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-branch`,placeholder:`main`,value:s,onChange:e=>c(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-user`,children:`Auth User (Optional)`}),(0,b.jsx)(`input`,{type:`text`,id:`repo-user`,placeholder:`e.g. oauth2`,value:d,onChange:e=>f(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`repo-token`,children:`Auth Token (Optional)`}),(0,b.jsx)(`input`,{type:`password`,id:`repo-token`,placeholder:`Token override`,value:p,onChange:e=>m(e.target.value)})]})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:t,children:`Cancel`}),(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:h,children:h?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Adding & Syncing...`]}):`Add & Start Sync`})]})]})]})}):null}function D({repo:e,onClose:t,onCopyUrl:n,copiedUrl:r}){if(!e)return null;let i=`${typeof window<`u`?window.location.origin:``}/api/webhooks/git`;return(0,b.jsx)(`div`,{className:`modal-backdrop`,onClick:e=>{e.target===e.currentTarget&&t()},"data-testid":`webhook-modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`650px`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Webhook Setup: `,e.name]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:t,"aria-label":`Close webhook modal`,children:`×`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`16px`,fontSize:`0.9rem`},children:[(0,b.jsx)(`p`,{className:`text-muted`,children:`Configure a webhook in your Git repository provider to automatically trigger synchronization on every push event.`}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Webhook URL (Payload URL)`}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`input`,{type:`text`,readOnly:!0,value:i,style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`},"aria-label":`Webhook Payload URL`}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>n(i),style:{minWidth:`95px`},"aria-label":`Copy Webhook URL`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${r?`fa-check`:`fa-copy`}`}),` `,r?`Copied!`:`Copy`]})]})]}),e.webhook_secret&&(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Repository Secret Token (HMAC)`}),(0,b.jsx)(`input`,{type:`text`,readOnly:!0,value:e.webhook_secret,style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`},"aria-label":`Repository Secret Token`})]}),(0,b.jsxs)(`div`,{style:{background:`rgba(0, 0, 0, 0.25)`,border:`1px solid var(--border-card)`,borderRadius:`8px`,padding:`14px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`0.95rem`,marginBottom:`10px`,color:`var(--text)`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-list-check`}),` Provider Setup Instructions`]}),(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`10px`,fontSize:`0.85rem`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`strong`,{style:{color:`#fff`},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`,style:{marginRight:`6px`}}),` GitHub:`]}),(0,b.jsxs)(`div`,{style:{color:`var(--text-muted)`,marginTop:`2px`,marginLeft:`18px`},children:[`Navigate to `,(0,b.jsx)(`code`,{children:`Settings > Webhooks > Add webhook`}),` → set `,(0,b.jsx)(`em`,{children:`Payload URL`}),` to the URL above → set `,(0,b.jsx)(`em`,{children:`Content type`}),` to `,(0,b.jsx)(`code`,{children:`application/json`}),` → select `,(0,b.jsx)(`em`,{children:`Push events`}),` → click `,(0,b.jsx)(`strong`,{children:`Add webhook`}),`.`]})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`strong`,{style:{color:`#fff`},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-gitlab`,style:{color:`#fc6d26`,marginRight:`6px`}}),` GitLab:`]}),(0,b.jsxs)(`div`,{style:{color:`var(--text-muted)`,marginTop:`2px`,marginLeft:`18px`},children:[`Navigate to `,(0,b.jsx)(`code`,{children:`Settings > Webhooks`}),` (or `,(0,b.jsx)(`code`,{children:`Settings > Integrations`}),`) → set `,(0,b.jsx)(`em`,{children:`URL`}),` → select `,(0,b.jsx)(`em`,{children:`Push events`}),` → click `,(0,b.jsx)(`strong`,{children:`Add webhook`}),`.`]})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`strong`,{style:{color:`#fff`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-mug-hot`,style:{color:`#609926`,marginRight:`6px`}}),` Gitea / Forgejo:`]}),(0,b.jsxs)(`div`,{style:{color:`var(--text-muted)`,marginTop:`2px`,marginLeft:`18px`},children:[`Navigate to `,(0,b.jsx)(`code`,{children:`Settings > Webhooks > Add Webhook > Gitea`}),` → set `,(0,b.jsx)(`em`,{children:`Target URL`}),` → set `,(0,b.jsx)(`em`,{children:`HTTP Method`}),` to `,(0,b.jsx)(`code`,{children:`POST`}),` → select `,(0,b.jsx)(`em`,{children:`Push Events`}),` → click `,(0,b.jsx)(`strong`,{children:`Add Webhook`}),`.`]})]})]})]}),(0,b.jsx)(`div`,{className:`modal-footer`,style:{marginTop:`8px`,padding:0},children:(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:t,children:`Close`})})]})]})})}function O({repos:e,isLoading:t,syncStates:n,onSync:r,onToggleAutoSync:i,onOpenWebhook:a,onDelete:o,onOpenSyncDrawer:s}){let c=e=>{let t=(e||`github`).toLowerCase();return t===`gitlab`?(0,b.jsx)(`i`,{className:`fa-brands fa-gitlab`,style:{color:`#fc6d26`,marginRight:`6px`},title:`GitLab`}):t===`gitea`||t===`forgejo`?(0,b.jsx)(`i`,{className:`fa-solid fa-mug-hot`,style:{color:`#609926`,marginRight:`6px`},title:`Gitea / Forgejo`}):t===`bitbucket`?(0,b.jsx)(`i`,{className:`fa-brands fa-bitbucket`,style:{color:`#2684ff`,marginRight:`6px`},title:`Bitbucket`}):t===`generic`?(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`,style:{color:`var(--accent)`,marginRight:`6px`},title:`Generic Git`}):(0,b.jsx)(`i`,{className:`fa-brands fa-github`,style:{marginRight:`6px`},title:`GitHub`})},l=(e,t)=>{let n=t?.step||1,r=t?.total_steps||5,i=t?.step_name||`Syncing...`,a=t?.percent??0,o=t?.current_file;return(0,b.jsxs)(`div`,{className:`sync-progress-container`,onClick:()=>s?.(e.id),role:`button`,tabIndex:0,style:{cursor:`pointer`},title:`Click to view live ingestion progress & logs`,onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&s?.(e.id)},children:[(0,b.jsxs)(`div`,{className:`progress-pill badge badge-warning`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),(0,b.jsxs)(`span`,{children:[`Step `,n,`/`,r,`: `,i,` (`,a,`%)`]})]}),(0,b.jsx)(`div`,{className:`sync-progress-bar-wrapper`,children:(0,b.jsx)(`div`,{className:`sync-progress-bar-fill fill-active`,style:{width:`${a}%`}})}),o&&(0,b.jsxs)(`div`,{className:`sync-file-caption`,title:o,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{marginRight:`4px`}}),(0,b.jsx)(`code`,{children:o})]})]})};return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Repo Alias`}),(0,b.jsx)(`th`,{children:`Git URL`}),(0,b.jsx)(`th`,{children:`Branch`}),(0,b.jsx)(`th`,{children:`Commit SHA`}),(0,b.jsx)(`th`,{children:`Status`}),(0,b.jsx)(`th`,{children:`Auto-Sync`}),(0,b.jsx)(`th`,{children:`Files`}),(0,b.jsx)(`th`,{children:`Last Synced`}),(0,b.jsx)(`th`,{children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:t&&e.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsxs)(`td`,{colSpan:9,className:`empty-state`,"data-testid":`repo-loading-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading repositories...`]})}):e.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:9,className:`empty-state`,children:`No Git repositories registered. Click "Add Repository" to index a remote repo.`})}):e.map(e=>{let t=e.auto_sync!==!1&&e.auto_sync!==0,u=n?.[e.id],d=e.status===`syncing`||u?.status===`syncing`;return(0,b.jsxs)(`tr`,{children:[(0,b.jsxs)(`td`,{children:[c(e.provider),(0,b.jsx)(`strong`,{children:e.name})]}),(0,b.jsx)(`td`,{children:(0,b.jsxs)(`a`,{href:e.url,target:`_blank`,rel:`noreferrer`,className:`repo-url-link`,style:{color:`var(--primary)`,textDecoration:`none`,fontSize:`0.85rem`},title:e.url,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrow-up-right-from-square`}),` `,e.url]})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.branch})}),(0,b.jsx)(`td`,{children:e.commit_sha?(0,b.jsx)(`code`,{children:e.commit_sha.substring(0,8)}):(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:d?l(e,u):e.status===`error`||u?.status===`error`?(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`span`,{className:`badge badge-danger`,title:e.last_error||u?.error||`Sync failed`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`}),` Error`]}),(e.last_error||u?.error)&&(0,b.jsx)(`div`,{style:{fontSize:`0.75rem`,color:`var(--danger)`,marginTop:`4px`,maxWidth:`180px`,overflow:`hidden`,textOverflow:`ellipsis`,whiteSpace:`nowrap`},title:e.last_error||u?.error||``,children:e.last_error||u?.error})]}):e.status===`pending`||u?.status===`pending`?(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock`}),` Pending`]}):(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`}),` Synced`]})}),(0,b.jsx)(`td`,{children:(0,b.jsxs)(`button`,{type:`button`,className:`badge ${t?`badge-success`:`badge-danger`}`,style:{cursor:`pointer`,background:t?`rgba(16, 185, 129, 0.2)`:`rgba(239, 68, 68, 0.2)`,border:t?`1px solid rgba(16, 185, 129, 0.4)`:`1px solid rgba(239, 68, 68, 0.4)`,color:t?`#6ee7b7`:`#fca5a5`,padding:`4px 8px`,display:`inline-flex`,alignItems:`center`,gap:`6px`},onClick:()=>i(e.id,t),title:`Auto-Sync: ${t?`ON`:`OFF`} (Click to toggle)`,"aria-label":`Toggle auto-sync for ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${t?`fa-toggle-on`:`fa-toggle-off`}`}),`Auto-Sync: `,t?`ON`:`OFF`]})}),(0,b.jsxs)(`td`,{children:[(e.file_count||0).toLocaleString(),` files`]}),(0,b.jsx)(`td`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`},children:e.last_synced||`Never`}),(0,b.jsx)(`td`,{children:(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`6px`},children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 8px`,fontSize:`0.8rem`},onClick:()=>s?.(e.id),title:`View Ingestion Logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Logs`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 8px`,fontSize:`0.8rem`},onClick:()=>r(e.id),title:`Trigger Sync`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Sync`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 8px`,fontSize:`0.8rem`},onClick:()=>a(e),title:`Webhook Setup`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Webhook`]}),(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>o(e.id,e.name),title:`Delete Repo`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})]})})]},e.id)})})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:t&&e.length===0?(0,b.jsxs)(`div`,{className:`empty-state`,"data-testid":`repo-loading-state-mobile`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading repositories...`]}):e.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No Git repositories registered. Click "Add Repository" to index a remote repo.`}):e.map(e=>{let t=e.auto_sync!==!1&&e.auto_sync!==0,u=n?.[e.id],d=e.status===`syncing`||u?.status===`syncing`;return(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:[c(e.provider),(0,b.jsx)(`strong`,{style:{fontSize:`1rem`},children:e.name})]}),!d&&(e.status===`error`||u?.status===`error`?(0,b.jsxs)(`span`,{className:`badge badge-danger`,title:e.last_error||u?.error||`Sync failed`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`}),` Error`]}):e.status===`pending`||u?.status===`pending`?(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock`}),` Pending`]}):(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`}),` Synced`]}))]}),d&&(0,b.jsx)(`div`,{style:{margin:`4px 0 2px 0`},children:l(e,u)}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`URL:`}),(0,b.jsx)(`a`,{href:e.url,target:`_blank`,rel:`noreferrer`,style:{color:`var(--primary)`,textDecoration:`none`},children:e.url})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Branch:`}),(0,b.jsx)(`code`,{children:e.branch})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Commit:`}),e.commit_sha?(0,b.jsx)(`code`,{children:e.commit_sha.substring(0,8)}):`-`]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Auto-Sync:`}),(0,b.jsx)(`button`,{type:`button`,className:`badge ${t?`badge-success`:`badge-danger`}`,style:{cursor:`pointer`,padding:`2px 6px`,fontSize:`0.75rem`},onClick:()=>i(e.id,t),title:`Auto-Sync: ${t?`ON`:`OFF`} (Click to toggle)`,"aria-label":`Toggle auto-sync for ${e.name}`,children:t?`ON`:`OFF`})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Files:`}),(e.file_count||0).toLocaleString(),` files`]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Last Synced:`}),e.last_synced||`Never`]}),!d&&(e.last_error||u?.error)&&(0,b.jsxs)(`div`,{style:{color:`var(--danger)`,fontSize:`0.75rem`},children:[(0,b.jsx)(`span`,{className:`data-label`,children:`Error:`}),e.last_error||u?.error]})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-actions`,children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>s?.(e.id),title:`View Ingestion Logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Logs`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>r(e.id),title:`Trigger Sync`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Sync`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>a(e),title:`Webhook Setup`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Webhook`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>o(e.id,e.name),title:`Delete Repo`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})]})]},`card-${e.id}`)})})]})}var k=[{step:1,title:`1. Connecting & Remote Check`},{step:2,title:`2. Shallow Cloning Repository`},{step:3,title:`3. Computing File Delta & Scanning`},{step:4,title:`4. Parsing AST Symbols & API Routes`},{step:5,title:`5. Upserting Embeddings & Finalizing`}];function ee({isOpen:e,onClose:t,repoId:n,repoName:r,job:i,onCancelSync:a}){let[o,s]=(0,_.useState)(``),[c,l]=(0,_.useState)(!0),[u,d]=(0,_.useState)(!1),[f,p]=(0,_.useState)(0),[m,h]=(0,_.useState)(!1),g=(0,_.useRef)(null),v=(0,_.useRef)(null),y=n??i?.repo_id??null,x=r||i?.repo_name||`Repository`;(0,_.useEffect)(()=>{if(!e||!i?.started_at){p(0);return}let t=()=>{let e=i.started_at>1e11?i.started_at:i.started_at*1e3;return Math.max(0,Math.floor((Date.now()-e)/1e3))};if(p(t()),i.status===`syncing`||i.status===`pending`){let e=setInterval(()=>{p(t())},1e3);return()=>clearInterval(e)}},[e,i?.started_at,i?.status]);let S=e=>{let t=Math.floor(e/60),n=e%60;return`${t.toString().padStart(2,`0`)}:${n.toString().padStart(2,`0`)}`},C=i?.logs,w=(0,_.useMemo)(()=>{let e=C||[];if(!o.trim())return e;let t=o.toLowerCase();return e.filter(e=>e.message.toLowerCase().includes(t)||e.level.toLowerCase().includes(t)||e.timestamp.toLowerCase().includes(t))},[C,o]);(0,_.useEffect)(()=>{c&&g.current&&typeof g.current.scrollIntoView==`function`&&g.current.scrollIntoView({behavior:`smooth`})},[w,c]);let T=async()=>{let e=(i?.logs||[]).map(e=>`[${e.timestamp}] [${e.level.toUpperCase()}] ${e.message}`).join(` +`);try{await navigator.clipboard.writeText(e),d(!0),setTimeout(()=>d(!1),2e3)}catch(e){console.error(`Failed to copy logs:`,e)}},E=async()=>{if(!(!y||!a))try{h(!0),await a(y)}catch(e){console.error(`Failed to cancel sync:`,e)}finally{h(!1)}};if(!e)return null;let D=i?.status||`pending`,O=i?.percent??(D===`synced`?100:0),ee=i?.step??(D===`synced`?5:1);return(0,b.jsx)(`div`,{className:`sync-drawer-backdrop`,onClick:e=>{e.target===e.currentTarget&&t()},"data-testid":`sync-drawer-backdrop`,children:(0,b.jsxs)(`div`,{className:`sync-drawer`,children:[(0,b.jsxs)(`div`,{className:`sync-drawer-header`,children:[(0,b.jsxs)(`div`,{className:`sync-drawer-title-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`10px`,flexWrap:`wrap`},children:[(0,b.jsxs)(`h2`,{style:{fontSize:`1.1rem`,margin:0,fontWeight:700,color:`var(--text)`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`,style:{marginRight:`8px`,color:`var(--primary)`}}),x,` Ingestion Progress & Live Logs`]}),D===`syncing`?(0,b.jsxs)(`span`,{className:`badge badge-warning`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Syncing`]}):D===`synced`?(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`}),` Synced`]}):D===`error`?(0,b.jsxs)(`span`,{className:`badge badge-danger`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-exclamation`}),` Error`]}):(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock`}),` Pending`]})]}),(0,b.jsxs)(`div`,{className:`sync-drawer-meta`,style:{display:`flex`,alignItems:`center`,gap:`12px`,marginTop:`6px`,fontSize:`0.82rem`,color:`var(--text-muted)`},children:[(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`i`,{className:`fa-regular fa-clock`,style:{marginRight:`4px`}}),`Elapsed: `,(0,b.jsx)(`strong`,{children:S(f)})]}),i?.step_name&&(0,b.jsxs)(`span`,{children:[`• Current: `,(0,b.jsx)(`strong`,{children:i.step_name})]})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[D===`syncing`&&a&&y!=null&&(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary btn-cancel-sync`,onClick:E,disabled:m,style:{fontSize:`0.8rem`,padding:`6px 12px`,color:`var(--danger)`,borderColor:`rgba(239, 68, 68, 0.4)`},children:[(0,b.jsx)(`i`,{className:`fa-solid ${m?`fa-spinner fa-spin`:`fa-stop`}`}),m?`Cancelling...`:`Cancel Sync`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:t,"aria-label":`Close sync drawer`,style:{fontSize:`1.4rem`,lineHeight:1},children:`×`})]})]}),(0,b.jsxs)(`div`,{className:`sync-drawer-body`,children:[(0,b.jsxs)(`div`,{className:`sync-progress-section`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`span`,{style:{fontWeight:600,color:`var(--text)`},children:`Overall Ingestion`}),(0,b.jsxs)(`span`,{style:{fontWeight:700,color:D===`error`?`var(--danger)`:`var(--primary)`},children:[O,`%`]})]}),(0,b.jsx)(`div`,{className:`sync-progress-bar-container`,children:(0,b.jsx)(`div`,{className:`sync-progress-bar-fill ${D===`error`?`fill-error`:D===`synced`?`fill-success`:`fill-active`}`,style:{width:`${O}%`}})})]}),(0,b.jsxs)(`div`,{className:`sync-stepper-container`,children:[(0,b.jsx)(`h4`,{style:{fontSize:`0.82rem`,textTransform:`uppercase`,letterSpacing:`0.05em`,color:`var(--text-muted)`,marginBottom:`10px`},children:`Ingestion Stages`}),(0,b.jsx)(`div`,{className:`sync-stepper-list`,children:k.map(e=>{let t=D===`synced`||D!==`error`&&ee>e.step||D===`error`&&ee>e.step,n=D===`syncing`&&ee===e.step,r=D===`error`&&ee===e.step;return(0,b.jsxs)(`div`,{className:`sync-stepper-item ${t?`item-completed`:n?`item-active`:r?`item-error`:`item-pending`}`,children:[(0,b.jsxs)(`div`,{className:`sync-stepper-icon`,children:[t&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`,style:{color:`#10b981`}}),n&&(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{color:`#f59e0b`}}),r&&(0,b.jsx)(`i`,{className:`fa-solid fa-circle-xmark`,style:{color:`#ef4444`}}),!t&&!n&&!r&&(0,b.jsx)(`i`,{className:`fa-regular fa-circle`,style:{color:`var(--text-muted)`}})]}),(0,b.jsxs)(`div`,{className:`sync-stepper-content`,children:[(0,b.jsx)(`div`,{className:`sync-stepper-title`,style:{fontWeight:n?600:500},children:e.title}),n&&(0,b.jsxs)(`div`,{className:`sync-stepper-details`,children:[i?.current_file&&(0,b.jsxs)(`div`,{className:`sync-current-file`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{marginRight:`4px`}}),(0,b.jsx)(`code`,{children:i.current_file})]}),i?.total_files!=null&&i.total_files>0&&(0,b.jsxs)(`div`,{className:`sync-file-count`,style:{marginTop:`2px`,color:`var(--text-muted)`},children:[i.processed_files,` / `,i.total_files,` files (`,O,`%)`]})]}),r&&i?.error&&(0,b.jsxs)(`div`,{className:`sync-stepper-error-msg`,style:{marginTop:`4px`,color:`var(--danger)`,fontSize:`0.82rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,style:{marginRight:`4px`}}),i.error]})]})]},e.step)})})]}),(0,b.jsxs)(`div`,{className:`sync-terminal-section`,children:[(0,b.jsxs)(`div`,{className:`sync-terminal-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`,style:{color:`var(--accent)`}}),(0,b.jsx)(`span`,{style:{fontSize:`0.85rem`,fontWeight:600,color:`var(--text)`},children:`Live Terminal Output`}),(0,b.jsxs)(`span`,{className:`badge badge-secondary`,style:{fontSize:`0.75rem`,padding:`1px 6px`},children:[w.length,` `,w.length===1?`event`:`events`]})]}),(0,b.jsxs)(`div`,{className:`sync-terminal-actions`,children:[(0,b.jsxs)(`label`,{className:`sync-autoscroll-toggle`,children:[(0,b.jsx)(`input`,{type:`checkbox`,checked:c,onChange:e=>l(e.target.checked),"aria-label":`Autoscroll`}),(0,b.jsx)(`span`,{children:`Autoscroll`})]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary btn-sm`,onClick:T,"aria-label":`Copy logs`,style:{fontSize:`0.75rem`,padding:`3px 8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid ${u?`fa-check`:`fa-copy`}`}),` `,u?`Copied!`:`Copy Logs`]})]})]}),(0,b.jsxs)(`div`,{className:`sync-terminal-search`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`,style:{color:`var(--text-muted)`,fontSize:`0.8rem`}}),(0,b.jsx)(`input`,{type:`text`,placeholder:`Filter logs by keyword or level...`,value:o,onChange:e=>s(e.target.value),style:{width:`100%`,background:`transparent`,border:`none`,outline:`none`,color:`var(--text)`,fontSize:`0.82rem`,padding:`4px 0`}}),o&&(0,b.jsx)(`button`,{type:`button`,onClick:()=>s(``),style:{background:`transparent`,border:`none`,color:`var(--text-muted)`,cursor:`pointer`,fontSize:`0.8rem`},children:`×`})]}),(0,b.jsx)(`div`,{className:`sync-terminal-body`,ref:v,children:w.length===0?(0,b.jsxs)(`div`,{className:`sync-terminal-empty`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-clock-rotate-left`,style:{marginBottom:`6px`,fontSize:`1.2rem`,opacity:.5}}),(0,b.jsx)(`div`,{children:(C?.length||0)===0?`Waiting for sync activity...`:`No logs matching filter`})]}):(0,b.jsxs)(`div`,{className:`sync-terminal-lines`,children:[w.map((e,t)=>{let n=(e.level||`INFO`).toUpperCase(),r=`level-info`;return(n===`WARN`||n===`WARNING`)&&(r=`level-warn`),(n===`ERROR`||n===`FATAL`)&&(r=`level-error`),(0,b.jsxs)(`div`,{className:`sync-terminal-line`,children:[(0,b.jsxs)(`span`,{className:`log-time`,children:[`[`,e.timestamp,`]`]}),(0,b.jsx)(`span`,{className:`log-badge ${r}`,children:n}),(0,b.jsx)(`span`,{className:`log-msg`,children:e.message})]},t)}),(0,b.jsx)(`div`,{ref:g})]})})]})]})]})})}function A(){let[e,t]=(0,_.useState)({}),[n,r]=(0,_.useState)(!1),i=(0,_.useRef)(null),a=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/repos/sync-status`);if(e&&e.ok){let n=await e.json();if(n&&typeof n==`object`&&!Array.isArray(n)){let e={};Object.entries(n).forEach(([t,n])=>{let r=n;r&&(r.repo_id!=null||r.step!=null||r.status!=null)&&(e[Number(t)]=r)}),t(t=>({...t,...e}))}else if(Array.isArray(n)){let e={};n.forEach(t=>{t&&t.repo_id!=null&&(t.step!=null||t.status===`syncing`)&&(e[t.repo_id]=t)}),Object.keys(e).length>0&&t(t=>({...t,...e}))}}}catch(e){console.error(`Failed to fetch initial sync status snapshot:`,e)}},[]);return(0,_.useEffect)(()=>{if(a(),typeof EventSource>`u`)return;let e=null;try{e=new EventSource(`/admin/api/repos/sync/stream`),i.current=e,e.onopen=()=>{r(!0)},e.onerror=()=>{r(!1)},e.addEventListener(`init`,e=>{try{let n=JSON.parse(e.data);if(n&&typeof n==`object`){let e={};Object.entries(n).forEach(([t,n])=>{e[Number(t)]=n}),t(e),r(!0)}}catch(e){console.error(`Failed to parse init sync stream event:`,e)}}),e.addEventListener(`progress`,e=>{try{let n=JSON.parse(e.data),i=n.data||n;i&&i.repo_id!=null&&(t(e=>{let t=e[i.repo_id];return{...e,[i.repo_id]:{...t||{},...i,logs:i.logs??t?.logs??[]}}}),r(!0))}catch(e){console.error(`Failed to parse progress event:`,e)}}),e.addEventListener(`log`,e=>{try{let n=JSON.parse(e.data),r=n.repo_id??n.data?.repo_id,i=n.data&&!n.data.repo_id?n.data:n.log||n.data;r!=null&&i&&t(e=>{let t=e[r];if(!t)return e;let n=t.logs||[];return{...e,[r]:{...t,logs:[...n,i]}}})}catch(e){console.error(`Failed to parse log event:`,e)}})}catch(e){console.error(`Failed to initialize EventSource:`,e),r(!1)}return()=>{e&&(e.close(),i.current=null)}},[a]),{syncStates:e,isConnected:n,cancelSync:(0,_.useCallback)(async e=>{try{let t=await fetch(`/admin/api/repos/${e}/cancel-sync`,{method:`POST`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error||`Failed to cancel sync: ${t.statusText}`)}return await t.json()}catch(t){throw console.error(`Error cancelling sync for repo ${e}:`,t),t}},[])}}function te({refreshStats:e}){let[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!0),[a,o]=(0,_.useState)(!1),[s,c]=(0,_.useState)(null),[l,u]=(0,_.useState)(!1),[d,f]=(0,_.useState)(null),p=S(),{syncStates:m,cancelSync:h}=A(),[g,v]=(0,_.useState)(``),[y,x]=(0,_.useState)(``),[C,w]=(0,_.useState)(`main`),[T,k]=(0,_.useState)(`auto`),[te,ne]=(0,_.useState)(``),[re,ie]=(0,_.useState)(``),[j,M]=(0,_.useState)(!1),N=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/repos`);if(!e.ok){p.error(`Failed to load repositories`);return}let t=await e.json();n(Array.isArray(t)?t:[])}catch(e){p.error(`Error loading repos: `+e.message),console.error(`Error loading repos:`,e)}finally{i(!1)}},[p]);(0,_.useEffect)(()=>{N();let e=setInterval(N,8e3);return()=>clearInterval(e)},[N]);let ae=async t=>{t.preventDefault(),M(!0);try{let t=await fetch(`/admin/api/repos`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({name:g.trim(),url:y.trim(),branch:C.trim()||`main`,provider:T===`auto`?void 0:T,auth_user:te.trim()||null,auth_token:re.trim()||null})}),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to add repository`);o(!1),v(``),x(``),w(`main`),k(`auto`),ne(``),ie(``),N(),e(),p.success(`Repository '${g.trim()}' added successfully`)}catch(e){p.error(`Error: ${e.message}`)}finally{M(!1)}},oe=async t=>{n(e=>e.map(e=>e.id===t?{...e,status:`syncing`}:e));try{let n=await fetch(`/admin/api/repos/sync/${t}`,{method:`POST`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to trigger sync`)}N(),e(),p.info(`Sync triggered successfully`)}catch(e){N(),p.error(`Failed to trigger sync: `+e.message)}},se=async(e,t)=>{let r=!t;n(t=>t.map(t=>t.id===e?{...t,auto_sync:r}:t));try{let t=await fetch(`/admin/api/repos/${e}/auto-sync`,{method:`PATCH`,headers:{"Content-Type":`application/json`},body:JSON.stringify({auto_sync:r})});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error||e.detail||`Failed to update auto-sync`)}p.info(`Auto-sync ${r?`enabled`:`disabled`}`),N()}catch(e){N(),p.error(`Failed to update auto-sync: `+e.message)}},P=async e=>{try{navigator?.clipboard?.writeText&&await navigator.clipboard.writeText(e),u(!0),p.info(`Webhook URL copied to clipboard`),setTimeout(()=>u(!1),2e3)}catch(e){p.error(`Failed to copy: `+e.message)}},F=async(t,r)=>{if(window.confirm(`Are you sure you want to delete repository '${r}'? All vectors and indexed symbols for this repo will be permanently purged.`)){n(e=>e.filter(e=>e.id!==t));try{let n=await fetch(`/admin/api/repos/${t}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to delete repo`)}N(),e(),p.success(`Repository '${r}' deleted successfully`)}catch(e){N(),p.error(`Failed to delete repo: `+e.message)}}},ce=d===null?null:m[d],le=t.find(e=>e.id===d)?.name||ce?.repo_name||``;return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-branch`}),` Registered Git Repositories`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Supports GitHub, GitLab, Gitea, Bitbucket, and custom self-hosted Git repositories over HTTP/HTTPS.`})]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>o(!0),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plus`}),` Add Repository`]})]}),(0,b.jsx)(O,{repos:t,isLoading:r,syncStates:m,onSync:oe,onToggleAutoSync:se,onOpenWebhook:e=>c(e),onDelete:F,onOpenSyncDrawer:e=>f(e)}),(0,b.jsx)(E,{isOpen:a,onClose:()=>o(!1),onSave:ae,alias:g,setAlias:v,url:y,setUrl:x,branch:C,setBranch:w,provider:T,setProvider:k,authUser:te,setAuthUser:ne,token:re,setToken:ie,isSaving:j}),(0,b.jsx)(D,{repo:s,onClose:()=>c(null),onCopyUrl:P,copiedUrl:l}),(0,b.jsx)(ee,{isOpen:d!==null,onClose:()=>f(null),repoId:d,repoName:le,job:ce,onCancelSync:h})]})})}function ne({refreshStats:e}){let[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!0),a=S(),[o,s]=(0,_.useState)(!1),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(``),[f,p]=(0,_.useState)(`local`),[m,h]=(0,_.useState)(``),[g,v]=(0,_.useState)(`directory`),[y,x]=(0,_.useState)(1),[C,w]=(0,_.useState)(null),T=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/paths`);if(!e.ok){a.error(`Failed to load local paths`);return}let t=await e.json();n(t)}catch(e){a.error(`Error loading paths: `+e.message),console.error(`Error loading paths:`,e)}finally{i(!1)}},[a]);(0,_.useEffect)(()=>{T();let e=setInterval(T,8e3);return()=>clearInterval(e)},[T]);let E=async t=>{t.preventDefault();try{let t=await fetch(`/admin/api/paths`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:u.trim(),repo:f.trim()||`local`,category:m.trim()||null,type:g,recursive:y,enabled:1})}),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to add path`);s(!1),d(``),p(`local`),h(``),v(`directory`),x(1),T(),e(),a.success(`Path added successfully`)}catch(e){a.error(`Error: ${e.message}`)}},D=async t=>{if(window.confirm(`Are you sure you want to delete this local search path?`)){n(e=>e.filter(e=>e.id!==t));try{let n=await fetch(`/admin/api/paths/${t}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to delete path`)}a.success(`Path deleted successfully`),T(),e()}catch(e){T(),a.error(`Failed to delete path: `+e.message)}}},O=(e=`/`)=>{l(!0),k(e)},k=async e=>{try{let t=await fetch(`/admin/api/browse?path=${encodeURIComponent(e)}`),n=await t.json();if(!t.ok){a.error(n.error||`Failed to browse directory`);return}w(n)}catch(e){a.error(`Browse error: `+e.message),console.error(`Browse error:`,e)}};return(0,b.jsxs)(`div`,{className:`tab-content active`,children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`}),` Monitored Local Paths`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Mounted documentation vaults and local workspaces scanned for changes.`})]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>s(!0),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plus`}),` Add Local Path`]})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Path`}),(0,b.jsx)(`th`,{children:`Repo Alias`}),(0,b.jsx)(`th`,{children:`Type`}),(0,b.jsx)(`th`,{children:`Recursive`}),(0,b.jsx)(`th`,{children:`Category`}),(0,b.jsx)(`th`,{children:`Enabled`}),(0,b.jsx)(`th`,{children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:r&&t.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsxs)(`td`,{colSpan:7,className:`empty-state`,"data-testid":`path-loading-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading local paths...`]})}):t.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:7,className:`empty-state`,children:`No local search paths configured.`})}):t.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.repo||`local`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.type})}),(0,b.jsx)(`td`,{children:e.recursive?`Yes`:`No`}),(0,b.jsx)(`td`,{children:e.category?(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category}):(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:e.enabled?(0,b.jsx)(`span`,{className:`badge badge-success`,children:`Enabled`}):(0,b.jsx)(`span`,{className:`badge badge-danger`,children:`Disabled`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>D(e.id),title:`Delete Path`,"aria-label":`Delete Path`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})})]},e.id))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:r&&t.length===0?(0,b.jsxs)(`div`,{className:`empty-state`,"data-testid":`path-loading-state-mobile`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`,color:`var(--primary)`}}),`Loading local paths...`]}):t.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No local search paths configured.`}):t.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,minWidth:0},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`,style:{color:`var(--accent)`}}),(0,b.jsx)(`strong`,{style:{fontSize:`1rem`},children:e.repo||`local`})]}),e.enabled?(0,b.jsx)(`span`,{className:`badge badge-success`,children:`Enabled`}):(0,b.jsx)(`span`,{className:`badge badge-danger`,children:`Disabled`})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.path})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,flexWrap:`wrap`,alignItems:`center`},children:[(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Type: `}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.type})]}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Recursive: `}),(0,b.jsx)(`span`,{children:e.recursive?`Yes`:`No`})]})]}),e.category&&(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Category: `}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category})]})]}),(0,b.jsx)(`div`,{className:`data-mobile-card-actions`,children:(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>D(e.id),title:`Delete Path`,"aria-label":`Delete Path`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})})]},`card-${e.id}`))})]}),o&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-open`}),` Add Monitored Local Path`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>s(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:E,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Selected Directory / File`}),(0,b.jsxs)(`div`,{className:`path-input-row`,children:[(0,b.jsx)(`input`,{type:`text`,readOnly:!0,required:!0,placeholder:`Browse workspace directories...`,value:u}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>O(C?.current_path||`/`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`}),` Browse`]})]})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-repo-alias`,children:`Repo / Vault Alias`}),(0,b.jsx)(`input`,{type:`text`,id:`path-repo-alias`,placeholder:`local`,value:f,onChange:e=>p(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-category`,children:`Category Override`}),(0,b.jsx)(`input`,{type:`text`,id:`path-category`,placeholder:`Optional category`,value:m,onChange:e=>h(e.target.value)})]})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-type`,children:`Path Type`}),(0,b.jsxs)(`select`,{id:`path-type`,value:g,onChange:e=>v(e.target.value),children:[(0,b.jsx)(`option`,{value:`directory`,children:`Directory`}),(0,b.jsx)(`option`,{value:`file`,children:`Single File`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`path-recursive`,children:`Scan Subfolders`}),(0,b.jsxs)(`select`,{id:`path-recursive`,value:y,onChange:e=>x(parseInt(e.target.value)),children:[(0,b.jsx)(`option`,{value:1,children:`Yes (Recursive)`}),(0,b.jsx)(`option`,{value:0,children:`No (Top-level only)`})]})]})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>s(!1),children:`Cancel`}),(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,children:`Save Path`})]})]})]})}),c&&C&&(0,b.jsx)(`div`,{className:`modal-backdrop`,style:{zIndex:1100},children:(0,b.jsxs)(`div`,{className:`glass-card modal-card browser-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-search`}),` Browse Workspace Files`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>l(!1),children:`×`})]}),(0,b.jsxs)(`div`,{className:`browser-body`,children:[(0,b.jsxs)(`div`,{className:`browser-breadcrumbs`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Current: `}),(0,b.jsx)(`span`,{className:`code`,style:{wordBreak:`break-all`},children:C.current_path})]}),(0,b.jsx)(`div`,{className:`browser-list-container`,children:(0,b.jsxs)(`ul`,{className:`browser-list`,children:[C.parent_path&&(0,b.jsxs)(`li`,{className:`browser-item`,onClick:()=>k(C.parent_path),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-level-up-alt`,style:{color:`var(--accent)`}}),` `,(0,b.jsx)(`span`,{children:`.. (Parent Directory)`})]}),C.directories.map(e=>(0,b.jsxs)(`li`,{className:`browser-item`,onClick:()=>k(e.path),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder`,style:{color:`#fbbf24`}}),` `,(0,b.jsx)(`span`,{style:{wordBreak:`break-all`},children:e.name})]},e.path)),C.files.map(e=>(0,b.jsxs)(`li`,{className:`browser-item`,onClick:()=>{d(e.path),v(`file`),l(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{color:`var(--text-muted)`}}),` `,(0,b.jsx)(`span`,{style:{wordBreak:`break-all`},children:e.name})]},e.path))]})})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>l(!1),children:`Cancel`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:()=>{C&&(d(C.current_path),v(`directory`),l(!1))},children:`Select Current Folder`})]})]})})]})}function re(){let e=S(),[t,n]=(0,_.useState)(``),[r,i]=(0,_.useState)(`code`),[a,o]=(0,_.useState)(``),[s,c]=(0,_.useState)(!1),[l,u]=(0,_.useState)(null),[d,f]=(0,_.useState)(null);return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`}),` Live Hybrid Search Inspector`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Test hybrid search results across code and documentation directly from the browser.`}),(0,b.jsx)(`form`,{onSubmit:async n=>{n.preventDefault(),c(!0),f(null),u(null);try{let e=await fetch(`/admin/api/search/test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({query:t.trim(),type:r,repo:a.trim()||null})}),n=await e.json();if(!e.ok)throw Error(n.error||`Search failed`);u(n.results||[])}catch(t){f(t.message),e.error(`Search failed: `+t.message)}finally{c(!1)}},style:{marginTop:`16px`},children:(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:2},children:[(0,b.jsx)(`label`,{children:`Search Query`}),(0,b.jsx)(`input`,{type:`text`,required:!0,placeholder:`e.g. JWT token authentication or chunk_markdown`,value:t,onChange:e=>n(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Target Type`}),(0,b.jsxs)(`select`,{value:r,onChange:e=>i(e.target.value),children:[(0,b.jsx)(`option`,{value:`code`,children:`Code Snippets & Symbols`}),(0,b.jsx)(`option`,{value:`doc`,children:`Documentation & Notes`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Repo Filter (Optional)`}),(0,b.jsx)(`input`,{type:`text`,placeholder:`All Repos`,value:a,onChange:e=>o(e.target.value)})]}),(0,b.jsx)(`div`,{className:`form-group search-form-btn-group`,style:{alignSelf:`flex-end`},children:(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:s,children:s?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Searching...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-play`}),` Search`]})})})]})}),(0,b.jsxs)(`div`,{style:{marginTop:`20px`},children:[s&&(0,b.jsx)(`div`,{className:`empty-state`,children:`Running hybrid retrieval with Normalized Weighted Fusion...`}),d&&(0,b.jsxs)(`div`,{className:`empty-state`,style:{color:`var(--danger)`},children:[`Search error: `,d]}),!s&&!d&&l===null&&(0,b.jsx)(`div`,{className:`empty-state`,children:`Enter a query above to test hybrid retrieval.`}),!s&&!d&&l!==null&&l.length===0&&(0,b.jsx)(`div`,{className:`empty-state`,children:`No matching results found in index.`}),!s&&!d&&l!==null&&l.length>0&&l.map((e,t)=>{let n=e.payload;return(0,b.jsxs)(`div`,{className:`search-hit-card`,children:[(0,b.jsxs)(`div`,{className:`search-hit-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,flexWrap:`wrap`,alignItems:`center`,gap:`6px`},children:[(0,b.jsx)(`span`,{className:`badge badge-primary`,children:n.repo}),(0,b.jsx)(`strong`,{children:n.rel_path}),n.symbol&&(0,b.jsx)(`span`,{className:`badge badge-accent`,children:n.symbol}),(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:[`(Lines `,n.start_line,`-`,n.end_line,`)`]}),n.github_url&&(()=>{let e=n.github_url.toLowerCase(),t=`View Source`,r=`fa-solid fa-code-branch`;return e.includes(`gitlab`)||e.includes(`/-/blob/`)?(t=`View on GitLab`,r=`fa-brands fa-gitlab`):e.includes(`gitea`)||e.includes(`forgejo`)?(t=`View on Gitea`,r=`fa-solid fa-mug-hot`):e.includes(`bitbucket`)?(t=`View on Bitbucket`,r=`fa-brands fa-bitbucket`):e.includes(`github.com`)&&(t=`View on GitHub`,r=`fa-brands fa-github`),(0,b.jsxs)(`a`,{href:n.github_url,target:`_blank`,rel:`noreferrer`,style:{color:`var(--primary)`,fontSize:`0.8rem`},children:[(0,b.jsx)(`i`,{className:r,style:{marginRight:`4px`}}),t]})})()]}),(0,b.jsx)(`div`,{children:(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[`Score: `,(e.score*100).toFixed(1),`% (`,e.score.toFixed(4),`)`]})})]}),(0,b.jsx)(`pre`,{className:`search-hit-code`,children:n.content})]},t)})]})]})})}function ie({vectorStore:e,isLoadingVs:t,testFeedback:n,vsProvider:r,vsMode:i,vsStoragePath:a,setVsStoragePath:o,vsUrl:s,setVsUrl:c,vsCollection:l,setVsCollection:u,isTestingVs:d,isSwitchingVs:f,onProviderChange:p,onModeChange:m,onTestConnection:h,onSwitchBackend:g}){return(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-database`}),` Vector Database Engine`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure and switch between vector database backends (Qdrant & ChromaDB). Switching backends updates system metadata and triggers full re-indexing.`}),(0,b.jsxs)(`div`,{className:`vs-config-layout`,children:[(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-nodes`}),` Active Vector Backend`]}),t&&!e?(0,b.jsx)(`p`,{className:`text-muted`,children:`Loading vector store configuration...`}):e?(0,b.jsxs)(`div`,{className:`specs-list`,style:{marginTop:0},children:[(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Provider:`}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider===`chroma`?`ChromaDB`:`Qdrant`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Operating Mode:`}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.mode===`embedded`?`Embedded Disk`:`Remote Server`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:e.mode===`embedded`?`Storage Path:`:`Server URL:`}),(0,b.jsx)(`code`,{children:e.mode===`embedded`?e.storage_path||`data/qdrant_db`:e.url||`http://localhost:6333`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Collection Name:`}),(0,b.jsx)(`code`,{children:e.collection||`knowledge_rag_v1`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Points Count:`}),(0,b.jsx)(`span`,{style:{fontSize:`0.9rem`,fontWeight:600},children:(e.points_count||0).toLocaleString()})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Health Status:`}),e.healthy?(0,b.jsxs)(`span`,{className:`badge badge-success`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`}),` Healthy`]}):(0,b.jsxs)(`span`,{className:`badge badge-danger`,title:e.health_message||`Unhealthy`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`}),` `,e.health_message?e.health_message.length>35?e.health_message.slice(0,35)+`...`:e.health_message:`Unhealthy`]})]})]}):(0,b.jsx)(`p`,{className:`text-muted`,children:`No vector store configuration found.`})]}),(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-sliders`}),` Configure & Switch Backend`]}),n&&(0,b.jsxs)(`div`,{className:`vs-feedback-banner ${n.success?`feedback-success`:`feedback-error`}`,children:[(0,b.jsx)(`i`,{className:n.success?`fa-solid fa-circle-check`:`fa-solid fa-circle-exclamation`}),(0,b.jsx)(`span`,{children:n.message})]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),g()},children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-provider`,children:`Vector Store Provider`}),(0,b.jsxs)(`select`,{id:`vs-provider`,value:r,onChange:e=>p(e.target.value),children:[(0,b.jsx)(`option`,{value:`qdrant`,children:`Qdrant (Hybrid Dense + BM25)`}),(0,b.jsx)(`option`,{value:`chroma`,children:`ChromaDB (Dense Vectors)`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-mode`,children:`Operating Mode`}),(0,b.jsxs)(`select`,{id:`vs-mode`,value:i,onChange:e=>m(e.target.value),children:[(0,b.jsx)(`option`,{value:`embedded`,children:`Embedded Disk Storage`}),(0,b.jsx)(`option`,{value:`remote`,children:`Remote Server URL`})]})]})]}),i===`embedded`?(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-storage-path`,children:`Storage Directory Path`}),(0,b.jsx)(`input`,{id:`vs-storage-path`,type:`text`,value:a,onChange:e=>o(e.target.value),placeholder:r===`chroma`?`data/chroma_db`:`data/qdrant_db`})]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-url`,children:`Remote Server URL`}),(0,b.jsx)(`input`,{id:`vs-url`,type:`text`,value:s,onChange:e=>c(e.target.value),placeholder:r===`chroma`?`http://localhost:8000`:`http://localhost:6333`})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`vs-collection`,children:`Collection Name`}),(0,b.jsx)(`input`,{id:`vs-collection`,type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`knowledge_rag_v1`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`10px`,marginTop:`16px`,flexWrap:`wrap`},children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:h,disabled:d||f,children:d?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Testing Connection...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plug`}),` Test Connection`]})}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-primary`,onClick:g,disabled:d||f,children:f?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Switching Backend...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Save & Switch Backend`]})})]})]})]})]})]})}function j({embeddingConfig:e,isLoadingEmb:t,isSavingEmb:n,embProvider:r,setEmbProvider:i,embThreads:a,setEmbThreads:o,embBatchSize:s,setEmbBatchSize:c,embDenseModel:l,setEmbDenseModel:u,embSparseModel:d,setEmbSparseModel:f,embLitellmUrl:p,setEmbLitellmUrl:m,embLitellmApiKey:h=``,setEmbLitellmApiKey:g,embVisionOcrModel:v=`gemini-2.5-flash`,setEmbVisionOcrModel:y,embChatModel:x=`gemini-2.5-flash`,setEmbChatModel:S,discoveryResult:C=null,isDiscovering:w=!1,onDiscoverModels:T,onSaveEmbeddingSettings:E}){let D=e?.system_cpus||2,O=e?.system_memory_gb||4,[k,ee]=(0,_.useState)(!1),[A,te]=(0,_.useState)(!1),[ne,re]=(0,_.useState)(!1),ie=C?.embedding_models||[],j=C?.vision_models||[],M=C?.chat_models||[];return(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-microchip`}),` Embedding Engine & Resource Limits`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure local FastEmbed (ONNX) resource limits, CPU thread concurrency, or remote LiteLLM endpoints with dynamic model discovery for embeddings, Vision AI OCR, and chat synthesis.`}),(0,b.jsxs)(`div`,{className:`vs-config-layout`,children:[(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-gauge-high`}),` Active Embedding Engine`]}),t&&!e?(0,b.jsx)(`p`,{className:`text-muted`,children:`Loading embedding configuration...`}):e?(0,b.jsxs)(`div`,{className:`specs-list`,style:{marginTop:0},children:[(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Execution Provider:`}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider===`api`?`Remote API (LiteLLM)`:`Local FastEmbed (ONNX)`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`CPU Threads Allocation:`}),(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[e.threads,` `,e.threads===1?`Core`:`Cores`,` (of `,D,` detected)`]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Batch Processing Size:`}),(0,b.jsxs)(`span`,{style:{fontSize:`0.9rem`,fontWeight:600},children:[e.batch_size,` chunks/batch`]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`System RAM Capacity:`}),(0,b.jsxs)(`span`,{style:{fontSize:`0.9rem`,fontWeight:600},children:[O,` GB`]})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Dense Model:`}),(0,b.jsx)(`code`,{children:e.dense_model||`BAAI/bge-small-en-v1.5`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Sparse Model (BM25):`}),(0,b.jsx)(`code`,{children:e.sparse_model||`Qdrant/bm25`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Vision AI OCR Model:`}),(0,b.jsx)(`code`,{children:e.vision_ocr_model||`gemini-2.5-flash`})]}),(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`Chat Completion Model:`}),(0,b.jsx)(`code`,{children:e.chat_model||`gemini-2.5-flash`})]}),e.provider===`api`&&(0,b.jsxs)(`div`,{className:`spec-row`,children:[(0,b.jsx)(`span`,{children:`API Endpoint URL:`}),(0,b.jsx)(`code`,{children:e.litellm_url||`http://litellm:4000/v1`})]})]}):(0,b.jsx)(`p`,{className:`text-muted`,children:`No embedding configuration found.`})]}),(0,b.jsxs)(`div`,{className:`vs-box`,children:[(0,b.jsxs)(`h3`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-sliders`}),` Configure Models & Resources`]}),(0,b.jsxs)(`form`,{onSubmit:E,children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-provider`,children:`Embedding Provider`}),(0,b.jsxs)(`select`,{id:`emb-provider`,value:r,onChange:e=>i(e.target.value),children:[(0,b.jsx)(`option`,{value:`local`,children:`Local Model (FastEmbed / ONNX Runtime)`}),(0,b.jsx)(`option`,{value:`api`,children:`API Endpoint (LiteLLM / OpenAI Compatible)`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-threads`,children:`CPU Thread Cap`}),(0,b.jsx)(`input`,{id:`emb-threads`,type:`number`,min:`1`,max:Math.max(D,128),value:a,onChange:e=>o(Math.max(1,parseInt(e.target.value)||1)),placeholder:`2`}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`,marginTop:`2px`,display:`block`},children:`Recommended: 2 cores. Prevents container CPU spikes.`})]})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-batch-size`,children:`Embedding Batch Size`}),(0,b.jsxs)(`select`,{id:`emb-batch-size`,value:s,onChange:e=>c(parseInt(e.target.value)||32),children:[(0,b.jsx)(`option`,{value:`16`,children:`16 chunks (Lowest RAM footprint)`}),(0,b.jsx)(`option`,{value:`32`,children:`32 chunks (Balanced Default)`}),(0,b.jsx)(`option`,{value:`64`,children:`64 chunks (High throughput)`}),(0,b.jsx)(`option`,{value:`128`,children:`128 chunks (Large RAM environments)`}),(0,b.jsx)(`option`,{value:`256`,children:`256 chunks (FastEmbed default)`})]})]}),r===`api`?(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-litellm-url`,children:`API Endpoint URL (LiteLLM)`}),(0,b.jsx)(`input`,{id:`emb-litellm-url`,type:`text`,value:p,onChange:e=>m(e.target.value),placeholder:`http://litellm:4000/v1`})]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-dense-model`,children:`Dense Model Name`}),(0,b.jsx)(`input`,{id:`emb-dense-model`,type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`BAAI/bge-small-en-v1.5`})]})]}),r===`api`&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-litellm-api-key`,children:`LiteLLM API Key (Optional / Bearer)`}),(0,b.jsx)(`input`,{id:`emb-litellm-api-key`,type:`password`,value:h,onChange:e=>g?.(e.target.value),placeholder:`sk-...`,autoComplete:`off`})]}),(0,b.jsx)(`div`,{className:`form-group`,style:{display:`flex`,flexDirection:`column`,justifyContent:`flex-end`},children:(0,b.jsx)(`button`,{type:`button`,id:`btn-discover-models`,className:`btn btn-secondary`,onClick:T,disabled:w,style:{height:`38px`,whiteSpace:`nowrap`},children:w?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Discovering...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-bolt`}),` Discover Models`]})})})]}),C&&(0,b.jsx)(`div`,{style:{marginBottom:`16px`},children:C.status===`success`?(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`8px 12px`,background:`rgba(16, 185, 129, 0.1)`,border:`1px solid rgba(16, 185, 129, 0.3)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-check`,style:{color:`#10b981`}}),(0,b.jsxs)(`span`,{children:[`Connected to LiteLLM — `,(0,b.jsxs)(`strong`,{children:[C.total_models,` models available`]}),` (`,ie.length,` embedding, `,j.length,` vision, `,M.length,` chat)`]})]}):(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,padding:`8px 12px`,background:`rgba(239, 68, 68, 0.1)`,border:`1px solid rgba(239, 68, 68, 0.3)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,style:{color:`#ef4444`}}),(0,b.jsx)(`span`,{children:C.message||`Could not connect to LiteLLM endpoint`})]})}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[(0,b.jsx)(`label`,{htmlFor:`emb-dense-model`,style:{marginBottom:0},children:`Dense Embedding Model`}),ie.length>0&&(0,b.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:()=>ee(!k),style:{fontSize:`0.75rem`,background:`none`,border:`none`,color:`#38bdf8`,cursor:`pointer`,padding:0},children:k?`← Select from discovered`:`Enter custom model →`})]}),!k&&ie.length>0?(0,b.jsxs)(`select`,{id:`emb-dense-model`,value:l,onChange:e=>{e.target.value===`__custom__`?ee(!0):u(e.target.value)},children:[ie.map(e=>(0,b.jsx)(`option`,{value:e,children:e},e)),(0,b.jsx)(`option`,{value:`__custom__`,children:`Custom / Enter manually...`})]}):(0,b.jsx)(`input`,{id:`emb-dense-model`,type:`text`,value:l,onChange:e=>u(e.target.value),placeholder:`gemini-embedding-2`})]})]}),r===`local`&&(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`emb-sparse-model`,children:`Sparse BM25 Model`}),(0,b.jsx)(`input`,{id:`emb-sparse-model`,type:`text`,value:d,onChange:e=>f(e.target.value),placeholder:`Qdrant/bm25`})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[(0,b.jsxs)(`label`,{htmlFor:`emb-vision-ocr-model`,style:{marginBottom:0},children:[`Vision AI OCR Model `,(0,b.jsx)(`span`,{className:`text-muted`,style:{fontWeight:400,fontSize:`0.8rem`},children:`(PDF Ingestion Fallback)`})]}),j.length>0&&(0,b.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:()=>te(!A),style:{fontSize:`0.75rem`,background:`none`,border:`none`,color:`#38bdf8`,cursor:`pointer`,padding:0},children:A?`← Select from discovered`:`Enter custom model →`})]}),!A&&j.length>0?(0,b.jsxs)(`select`,{id:`emb-vision-ocr-model`,value:v,onChange:e=>{e.target.value===`__custom__`?te(!0):y?.(e.target.value)},children:[j.map(e=>(0,b.jsx)(`option`,{value:e,children:e},e)),(0,b.jsx)(`option`,{value:`__custom__`,children:`Custom / Enter manually...`})]}):(0,b.jsx)(`input`,{id:`emb-vision-ocr-model`,type:`text`,value:v,onChange:e=>y?.(e.target.value),placeholder:`gemini-2.5-flash`})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,marginBottom:`4px`},children:[(0,b.jsx)(`label`,{htmlFor:`emb-chat-model`,style:{marginBottom:0},children:`General Chat & Synthesis Model`}),M.length>0&&(0,b.jsx)(`button`,{type:`button`,className:`btn-link`,onClick:()=>re(!ne),style:{fontSize:`0.75rem`,background:`none`,border:`none`,color:`#38bdf8`,cursor:`pointer`,padding:0},children:ne?`← Select from discovered`:`Enter custom model →`})]}),!ne&&M.length>0?(0,b.jsxs)(`select`,{id:`emb-chat-model`,value:x,onChange:e=>{e.target.value===`__custom__`?re(!0):S?.(e.target.value)},children:[M.map(e=>(0,b.jsx)(`option`,{value:e,children:e},e)),(0,b.jsx)(`option`,{value:`__custom__`,children:`Custom / Enter manually...`})]}):(0,b.jsx)(`input`,{id:`emb-chat-model`,type:`text`,value:x,onChange:e=>S?.(e.target.value),placeholder:`gemini-2.5-flash`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,gap:`10px`,marginTop:`16px`},children:(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:n||t,children:n?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving & Applying...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-floppy-disk`}),` Save & Apply Embedding Limits & Model Settings`]})})})]})]})]})]})}function M({isLoadingAutoSync:e,intervalMins:t,setIntervalMins:n,hasGlobalSecret:r,showWebhookSecret:i,setShowWebhookSecret:a,webhookSecret:o,setWebhookSecret:s,fullWebhookUrl:c,copiedWebhookUrl:l,isSavingAutoSync:u,onSaveAutoSync:d,onClearWebhookSecret:f,onCopyWebhookUrl:p}){return(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate`}),` Auto-Sync & Webhooks`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure scheduled background repository polling interval and global incoming webhook triggers.`}),e&&!t?(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`12px`},children:`Loading auto-sync settings...`}):(0,b.jsxs)(`form`,{onSubmit:d,style:{marginTop:`16px`},children:[(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,b.jsx)(`label`,{htmlFor:`auto-sync-interval`,children:`Repository Polling Interval`}),(0,b.jsxs)(`select`,{id:`auto-sync-interval`,value:t,onChange:e=>n(Number(e.target.value)),style:{width:`100%`},children:[(0,b.jsx)(`option`,{value:0,children:`Disabled (0m)`}),(0,b.jsx)(`option`,{value:5,children:`5 minutes`}),(0,b.jsx)(`option`,{value:15,children:`15 minutes (Default)`}),(0,b.jsx)(`option`,{value:30,children:`30 minutes`}),(0,b.jsx)(`option`,{value:60,children:`1 hour`}),(0,b.jsx)(`option`,{value:360,children:`6 hours`}),![0,5,15,30,60,360].includes(t)&&(0,b.jsxs)(`option`,{value:t,children:[t,` minutes (Custom)`]})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`6px`},children:[(0,b.jsx)(`label`,{htmlFor:`auto-sync-secret`,style:{marginBottom:0},children:`Global Webhook Secret (HMAC / Token)`}),r?(0,b.jsx)(`span`,{className:`badge badge-accent`,children:`Secret Active`}):(0,b.jsx)(`span`,{className:`badge badge-secondary`,style:{color:`var(--text-muted)`},children:`None`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`input`,{id:`auto-sync-secret`,type:i?`text`:`password`,value:o,onChange:e=>s(e.target.value),placeholder:r?`Secret configured (enter new to change)`:`Enter webhook secret (optional)`,style:{flex:1}}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>a(!i),title:i?`Hide secret`:`Reveal secret`,"aria-label":i?`Hide secret`:`Reveal secret`,style:{minWidth:`42px`,padding:`0 12px`},children:(0,b.jsx)(`i`,{className:`fa-solid ${i?`fa-eye-slash`:`fa-eye`}`})}),(r||o)&&(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:f,title:`Clear secret`,"aria-label":`Clear secret`,disabled:u,style:{padding:`0 12px`},children:`Clear`})]})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{marginTop:`14px`,minWidth:0,width:`100%`},children:[(0,b.jsx)(`label`,{htmlFor:`auto-sync-webhook-url`,children:`Incoming Webhook Payload URL`}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,minWidth:0,width:`100%`},children:[(0,b.jsx)(`input`,{id:`auto-sync-webhook-url`,type:`text`,readOnly:!0,value:c,style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`,flex:1,minWidth:0,width:`100%`},"aria-label":`Webhook Payload URL`}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:p,style:{minWidth:`95px`},"aria-label":`Copy Webhook URL`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${l?`fa-check`:`fa-copy`}`}),` `,l?`Copied!`:`Copy`]})]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{fontSize:`0.8rem`,marginTop:`6px`},children:`Payload URL for repository push webhooks. Webhooks trigger immediate background synchronization for registered repositories.`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,gap:`10px`,marginTop:`18px`},children:(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:u,children:u?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-floppy-disk`}),` Save Auto-Sync Settings`]})})})]})]})}function N({stats:e,ghAuth:t,glAuth:n,gtAuth:r,ghToken:i,setGhToken:a,glToken:o,setGlToken:s,gtToken:c,setGtToken:l,hostCredentials:u,isHostModalOpen:d,setIsHostModalOpen:f,newHost:p,setNewHost:m,newHostProvider:h,setNewHostProvider:g,newHostUser:_,setNewHostUser:v,newHostToken:y,setNewHostToken:x,isSavingHost:S,onSaveToken:C,onClearToken:w,onSaveHostCredential:T,onDeleteHostCredential:E}){return(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-key`}),` Global Git Provider Authentication`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Default tokens are automatically applied to repositories matching these providers when no per-repo or host-specific override exists.`}),(0,b.jsxs)(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(min(100%, 300px), 1fr))`,gap:`20px`,marginTop:`20px`},children:[(0,b.jsxs)(`div`,{className:`settings-provider-box`,style:{background:`rgba(255,255,255,0.02)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,fontWeight:600},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github fa-lg`}),` GitHub`]}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:t.token_source})]}),(0,b.jsxs)(`div`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`,marginBottom:`8px`,wordBreak:`break-all`},children:[`Active Token: `,(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:t.masked_token})]}),e?.rate_limit&&(0,b.jsxs)(`div`,{style:{fontSize:`0.78rem`,color:`var(--text-muted)`,marginBottom:`12px`},children:[`Rate Limit: `,e.rate_limit.remaining,` / `,e.rate_limit.limit,` requests`]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(`github_token`,i,`GitHub`)},children:[(0,b.jsx)(`div`,{className:`form-group`,style:{marginBottom:`10px`},children:(0,b.jsx)(`input`,{type:`password`,placeholder:`ghp_xxxxxxxxxxxx`,value:i,onChange:e=>a(e.target.value)})}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},children:`Save`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},onClick:()=>w(`github_token`,`GitHub`),children:`Clear`})]})]})]}),(0,b.jsxs)(`div`,{className:`settings-provider-box`,style:{background:`rgba(255,255,255,0.02)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,fontWeight:600},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-gitlab fa-lg`,style:{color:`#fc6d26`}}),` GitLab (Global)`]}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:n.token_source})]}),(0,b.jsxs)(`div`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`,marginBottom:`16px`,wordBreak:`break-all`},children:[`Active Token: `,(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:n.masked_token})]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(`gitlab_token`,o,`GitLab`)},children:[(0,b.jsx)(`div`,{className:`form-group`,style:{marginBottom:`10px`},children:(0,b.jsx)(`input`,{type:`password`,placeholder:`glpat-xxxxxxxxxxxx`,value:o,onChange:e=>s(e.target.value)})}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},children:`Save`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},onClick:()=>w(`gitlab_token`,`GitLab`),children:`Clear`})]})]})]}),(0,b.jsxs)(`div`,{className:`settings-provider-box`,style:{background:`rgba(255,255,255,0.02)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,fontWeight:600},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-mug-hot fa-lg`,style:{color:`#609926`}}),` Gitea / Forgejo`]}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:r.token_source})]}),(0,b.jsxs)(`div`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`,marginBottom:`16px`,wordBreak:`break-all`},children:[`Active Token: `,(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:r.masked_token})]}),(0,b.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(`gitea_token`,c,`Gitea`)},children:[(0,b.jsx)(`div`,{className:`form-group`,style:{marginBottom:`10px`},children:(0,b.jsx)(`input`,{type:`password`,placeholder:`Token / Personal Token`,value:c,onChange:e=>l(e.target.value)})}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`},children:[(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},children:`Save`}),(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.8rem`},onClick:()=>w(`gitea_token`,`Gitea`),children:`Clear`})]})]})]})]})]}),(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-shield-halved`}),` Custom & Self-Hosted Git Host Vault`]}),(0,b.jsxs)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:[`Define credentials for self-hosted GitLab Enterprise, Gitea, or custom servers (e.g. `,(0,b.jsx)(`code`,{children:`gitlab.mycorp.com`}),` or `,(0,b.jsx)(`code`,{children:`git.lan:3000`}),`).`]})]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>f(!0),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-plus`}),` Add Host Credential`]})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,style:{marginTop:`16px`},children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Host Domain / Address`}),(0,b.jsx)(`th`,{children:`Provider Type`}),(0,b.jsx)(`th`,{children:`Auth User`}),(0,b.jsx)(`th`,{children:`Masked Token`}),(0,b.jsx)(`th`,{children:`Added At`}),(0,b.jsx)(`th`,{children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:u.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:6,className:`empty-state`,children:`No custom host credentials configured. Add a host domain to authenticate self-hosted instances.`})}):u.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.host})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider.toUpperCase()})}),(0,b.jsx)(`td`,{children:e.auth_user?(0,b.jsx)(`code`,{children:e.auth_user}):(0,b.jsx)(`span`,{className:`text-muted`,children:`Default`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.masked_token})}),(0,b.jsx)(`td`,{style:{fontSize:`0.8rem`,color:`var(--text-muted)`},children:e.added_at}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>E(e.id,e.host),title:`Delete Credential`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})})]},e.id))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:u.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No custom host credentials configured. Add a host domain to authenticate self-hosted instances.`}):u.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`},children:(0,b.jsx)(`code`,{style:{fontSize:`0.95rem`},children:e.host})}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.provider.toUpperCase()})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Auth User: `}),e.auth_user?(0,b.jsx)(`code`,{children:e.auth_user}):(0,b.jsx)(`span`,{className:`text-muted`,children:`Default`})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Masked Token: `}),(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.masked_token})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Added At: `}),(0,b.jsx)(`span`,{style:{color:`var(--text-muted)`},children:e.added_at})]})]}),(0,b.jsx)(`div`,{className:`data-mobile-card-actions`,children:(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>E(e.id,e.host),title:`Delete Credential`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})})]},`card-${e.id}`))})]}),d&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-shield-halved`}),` Add Host Credential`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>f(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:T,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-domain`,children:`Host Domain / IP`}),(0,b.jsx)(`input`,{type:`text`,id:`host-domain`,required:!0,placeholder:`e.g. gitlab.mycorp.internal or git.lan:3000`,value:p,onChange:e=>m(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-provider`,children:`Provider Type`}),(0,b.jsxs)(`select`,{id:`host-provider`,value:h,onChange:e=>g(e.target.value),children:[(0,b.jsx)(`option`,{value:`gitlab`,children:`GitLab Enterprise / Self-Hosted`}),(0,b.jsx)(`option`,{value:`gitea`,children:`Gitea / Forgejo`}),(0,b.jsx)(`option`,{value:`github`,children:`GitHub Enterprise`}),(0,b.jsx)(`option`,{value:`bitbucket`,children:`Bitbucket Server / Cloud`}),(0,b.jsx)(`option`,{value:`generic`,children:`Generic Git (HTTP / HTTPS)`})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-user`,children:`Auth User (Optional)`}),(0,b.jsx)(`input`,{type:`text`,id:`host-user`,placeholder:`e.g. oauth2 or gitlab-ci-token`,value:_,onChange:e=>v(e.target.value)})]})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`host-token`,children:`Personal Access Token / Password`}),(0,b.jsx)(`input`,{type:`password`,id:`host-token`,required:!0,placeholder:`Token or password`,value:y,onChange:e=>x(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>f(!1),children:`Cancel`}),(0,b.jsx)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:S,children:S?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving...`]}):`Save Host Credential`})]})]})]})})]})}var ae=`contextcortex_theme`,oe=`deep-ocean`,se=[{id:`deep-ocean`,name:`Deep Ocean`,mode:`dark`,description:`Monochromatic petrol slate with vibrant cyan and mint accents.`,swatches:[`#07181b`,`#0d2c2f`,`#0891b2`,`#2dd4bf`]},{id:`midnight-blue`,name:`Midnight Blue`,mode:`dark`,description:`Classic deep space navy with cobalt blue and teal highlights.`,swatches:[`#0a0f1d`,`#121a2f`,`#3b82f6`,`#14b8a6`]},{id:`lavender-haze`,name:`Lavender Haze`,mode:`light`,description:`Elegant soft violet canvas with vibrant purple, fuchsia accents, and plum text.`,swatches:[`#f5f3ff`,`#faf8ff`,`#7c3aed`,`#ec4899`]},{id:`amber-warmth`,name:`Amber Warmth`,mode:`light`,description:`Warm sandstone canvas with terracotta orange, amber accents, and espresso text.`,swatches:[`#fdf8f4`,`#ffffff`,`#ea580c`,`#d97706`]}];function P(){if(typeof window>`u`)return oe;try{let e=localStorage.getItem(ae);if(e===`arctic-frost`||e===`aqua-breeze`)return`lavender-haze`;if(e===`solar-daybreak`||e===`azure-daylight`)return`amber-warmth`;if(e&&se.some(t=>t.id===e))return e}catch{}return oe}function F(e){if(!(typeof document>`u`)){document.documentElement.setAttribute(`data-theme`,e);try{localStorage.setItem(ae,e)}catch{}}}function ce(){let[e,t]=(0,_.useState)(`deep-ocean`),n=S();(0,_.useEffect)(()=>{t(P())},[]);let r=(e,r)=>{F(e),t(e),n.success(`Switched theme to ${r}`)};return(0,b.jsxs)(`section`,{className:`settings-section glass-card`,"aria-labelledby":`theme-settings-heading`,children:[(0,b.jsxs)(`div`,{className:`section-header`,children:[(0,b.jsx)(`div`,{className:`header-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-palette`})}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h2`,{id:`theme-settings-heading`,style:{fontSize:`1.1rem`,fontWeight:600},children:`Appearance & Theme`}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Choose your preferred color scheme. The selected theme will persist across browser sessions.`})]})]}),(0,b.jsx)(`div`,{className:`theme-options-grid`,role:`radiogroup`,"aria-label":`Appearance Themes`,children:se.map(t=>{let n=e===t.id;return(0,b.jsxs)(`button`,{type:`button`,className:`theme-card ${n?`active`:``}`,onClick:()=>r(t.id,t.name),role:`radio`,"aria-checked":n,"aria-label":`Select ${t.name} theme`,children:[(0,b.jsxs)(`div`,{className:`theme-card-header`,children:[(0,b.jsxs)(`div`,{className:`theme-card-title`,children:[(0,b.jsx)(`span`,{children:t.name}),(0,b.jsxs)(`span`,{className:`badge`,style:{fontSize:`0.68rem`,fontWeight:500,opacity:.85,padding:`2px 6px`},children:[(0,b.jsx)(`i`,{className:`fa-solid ${t.mode===`dark`?`fa-moon`:`fa-sun`}`,style:{marginRight:`3px`}}),t.mode===`dark`?`Dark`:`Light`]})]}),n?(0,b.jsxs)(`span`,{className:`badge badge-accent`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-check`,style:{marginRight:`4px`}}),` Active`]}):(0,b.jsx)(`span`,{className:`badge badge-primary`,children:`Select`})]}),(0,b.jsx)(`div`,{className:`theme-card-desc`,children:t.description}),(0,b.jsx)(`div`,{className:`theme-swatches`,"aria-hidden":`true`,children:t.swatches.map((e,t)=>(0,b.jsx)(`span`,{className:`theme-swatch`,style:{backgroundColor:e},title:e},t))})]},t.id)})})]})}function le(){let[e,t]=(0,_.useState)({summary_enabled:!0,summary_threshold_kb:500,summary_max_file_size_mb:10,read_file_max_lines:2e3,summary_chat_model:`gemini-2.5-flash`}),[n,r]=(0,_.useState)(!1),[i,a]=(0,_.useState)(!1),o=S(),s=async()=>{r(!0);try{let e=await fetch(`/admin/api/settings/files`);if(e.ok){let n=await e.json();t({summary_enabled:n.summary_enabled!==!1,summary_threshold_kb:n.summary_threshold_kb??500,summary_max_file_size_mb:n.summary_max_file_size_mb??10,read_file_max_lines:n.read_file_max_lines??2e3,summary_chat_model:n.summary_chat_model||`gemini-2.5-flash`})}}catch(e){console.error(`Failed to load file settings:`,e)}finally{r(!1)}};return(0,_.useEffect)(()=>{s()},[]),(0,b.jsxs)(`section`,{className:`settings-section glass-card`,"aria-labelledby":`file-settings-heading`,children:[(0,b.jsxs)(`div`,{className:`section-header`,children:[(0,b.jsx)(`div`,{className:`header-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`})}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`h2`,{id:`file-settings-heading`,style:{fontSize:`1.1rem`,fontWeight:600},children:`Files & Large File Summarization`}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Configure retrieval ceilings for AI agents and automatic LLM summarization thresholds for large files in watched folders and uploads.`})]})]}),n?(0,b.jsxs)(`div`,{style:{padding:`24px`,textAlign:`center`},className:`text-muted`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`8px`}}),` Loading settings...`]}):(0,b.jsx)(`form`,{onSubmit:async n=>{n.preventDefault(),a(!0);try{let n=await fetch(`/admin/api/settings/files`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)});if(n.ok){let e=await n.json();t(e),o.success(`File and summarization settings updated successfully`)}else{let e=await n.json();o.error(e.error||`Failed to save settings`)}}catch(e){o.error(`Save failed: ${e.message}`)}finally{a(!1)}},style:{marginTop:`16px`},children:(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`16px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,padding:`12px 16px`,background:`rgba(255,255,255,0.03)`,borderRadius:`8px`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`label`,{htmlFor:`summary-enabled-toggle`,style:{fontWeight:600,display:`block`,cursor:`pointer`},children:`Enable Large File Summarization`}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:`Automatically generate and vector-embed an executive summary when files exceed the size threshold instead of skipping them.`})]}),(0,b.jsx)(`input`,{id:`summary-enabled-toggle`,type:`checkbox`,checked:e.summary_enabled,onChange:n=>t({...e,summary_enabled:n.target.checked}),style:{width:`18px`,height:`18px`,cursor:`pointer`},"aria-label":`Enable Large File Summarization`})]}),(0,b.jsxs)(`div`,{style:{display:`grid`,gridTemplateColumns:`repeat(auto-fit, minmax(220px, 1fr))`,gap:`16px`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`label`,{htmlFor:`summary-threshold-input`,style:{fontSize:`0.85rem`,fontWeight:500,display:`block`,marginBottom:`6px`},children:`Auto-Summarize Threshold (KB)`}),(0,b.jsx)(`input`,{id:`summary-threshold-input`,type:`number`,min:`10`,max:`50000`,value:e.summary_threshold_kb,onChange:n=>t({...e,summary_threshold_kb:Number(n.target.value)}),className:`input-field`,style:{width:`100%`},disabled:!e.summary_enabled}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`,marginTop:`4px`,display:`block`},children:`Files larger than this (default: 500 KB) trigger LLM summarization.`})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`label`,{htmlFor:`summary-max-size-input`,style:{fontSize:`0.85rem`,fontWeight:500,display:`block`,marginBottom:`6px`},children:`Max File Size for Summarization (MB)`}),(0,b.jsx)(`input`,{id:`summary-max-size-input`,type:`number`,min:`1`,max:`100`,value:e.summary_max_file_size_mb,onChange:n=>t({...e,summary_max_file_size_mb:Number(n.target.value)}),className:`input-field`,style:{width:`100%`},disabled:!e.summary_enabled}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`,marginTop:`4px`,display:`block`},children:`Files larger than this ceiling (default: 10 MB) are skipped to protect memory.`})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`label`,{htmlFor:`read-file-max-lines-input`,style:{fontSize:`0.85rem`,fontWeight:500,display:`block`,marginBottom:`6px`},children:`Max Lines Per Read`}),(0,b.jsx)(`input`,{id:`read-file-max-lines-input`,type:`number`,min:`50`,max:`20000`,value:e.read_file_max_lines,onChange:n=>t({...e,read_file_max_lines:Number(n.target.value)}),className:`input-field`,style:{width:`100%`}}),(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`,marginTop:`4px`,display:`block`},children:[`Default line ceiling for `,(0,b.jsx)(`code`,{children:`read_file`}),` tool calls (default: 2000 lines).`]})]})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`label`,{htmlFor:`summary-chat-model-input`,style:{fontSize:`0.85rem`,fontWeight:500,display:`block`,marginBottom:`6px`},children:`Summarization Chat Model`}),(0,b.jsx)(`input`,{id:`summary-chat-model-input`,type:`text`,value:e.summary_chat_model,onChange:n=>t({...e,summary_chat_model:n.target.value}),placeholder:`e.g. gemini-2.5-flash or gpt-4o-mini`,className:`input-field`,style:{width:`100%`},disabled:!e.summary_enabled}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`,marginTop:`4px`,display:`block`},children:`LiteLLM chat model identifier used for generating file summaries.`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,justifyContent:`flex-end`,marginTop:`8px`},children:(0,b.jsx)(`button`,{type:`submit`,disabled:i,className:`btn btn-primary`,style:{display:`flex`,alignItems:`center`,gap:`8px`},children:i?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Saving...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-floppy-disk`}),` Save File Settings`]})})})]})})]})}function ue({stats:e,refreshStats:t}){let[n,r]=(0,_.useState)(``),[i,a]=(0,_.useState)(``),[o,s]=(0,_.useState)(``),[c,l]=(0,_.useState)([]),[u,d]=(0,_.useState)(15),[f,p]=(0,_.useState)(``),[m,h]=(0,_.useState)(!1),[g,v]=(0,_.useState)(`/api/webhooks/git`),[y,x]=(0,_.useState)(!1),[C,w]=(0,_.useState)(!1),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(!1),[k,ee]=(0,_.useState)(!1),[A,te]=(0,_.useState)(``),[ne,re]=(0,_.useState)(`gitlab`),[ae,oe]=(0,_.useState)(``),[se,P]=(0,_.useState)(``),[F,ue]=(0,_.useState)(!1),[de,fe]=(0,_.useState)(null),[pe,me]=(0,_.useState)(!1),[he,ge]=(0,_.useState)(`qdrant`),[_e,ve]=(0,_.useState)(`embedded`),[ye,be]=(0,_.useState)(`data/qdrant_db`),[xe,Se]=(0,_.useState)(`http://localhost:6333`),[Ce,we]=(0,_.useState)(`knowledge_rag_v1`),[Te,Ee]=(0,_.useState)(!1),[De,I]=(0,_.useState)(null),[Oe,ke]=(0,_.useState)(!1),[Ae,je]=(0,_.useState)(null),[Me,Ne]=(0,_.useState)(!1),[Pe,Fe]=(0,_.useState)(!1),[Ie,Le]=(0,_.useState)(`local`),[Re,ze]=(0,_.useState)(2),[Be,Ve]=(0,_.useState)(32),[He,Ue]=(0,_.useState)(`BAAI/bge-small-en-v1.5`),[We,Ge]=(0,_.useState)(`Qdrant/bm25`),[Ke,qe]=(0,_.useState)(`http://litellm:4000/v1`),[Je,Ye]=(0,_.useState)(``),[Xe,Ze]=(0,_.useState)(`gemini-2.5-flash`),[Qe,$e]=(0,_.useState)(`gemini-2.5-flash`),[et,tt]=(0,_.useState)(null),[nt,rt]=(0,_.useState)(!1),L=S(),it=(0,_.useCallback)(async()=>{try{let e=await fetch(`/admin/api/settings/hosts`);if(e.ok){let t=await e.json();l(Array.isArray(t)?t:[])}}catch(e){console.error(`Failed to load host credentials:`,e),l([])}},[]),at=(0,_.useCallback)(async()=>{me(!0);try{let e=await fetch(`/admin/api/vector-store`);if(e.ok){let t=await e.json();fe(t),t.provider&&ge(t.provider),t.mode&&ve(t.mode),t.storage_path&&be(t.storage_path),t.url&&Se(t.url),t.collection&&we(t.collection)}}catch(e){console.error(`Failed to load vector store config:`,e)}finally{me(!1)}},[]),ot=(0,_.useCallback)(async()=>{x(!0);try{let e=await fetch(`/admin/api/settings/auto-sync`);if(e.ok){let t=await e.json();typeof t.interval_mins==`number`&&d(t.interval_mins),typeof t.webhook_url==`string`&&v(t.webhook_url),typeof t.has_global_secret==`boolean`&&h(t.has_global_secret)}}catch(e){console.error(`Failed to load auto-sync settings:`,e)}finally{x(!1)}},[]),st=(0,_.useCallback)(async()=>{Ne(!0);try{let e=await fetch(`/admin/api/settings/embedding`);if(e.ok){let t=await e.json();je(t),t.provider&&Le(t.provider),typeof t.threads==`number`&&ze(t.threads),typeof t.batch_size==`number`&&Ve(t.batch_size),t.dense_model&&Ue(t.dense_model),t.sparse_model&&Ge(t.sparse_model),t.litellm_url&&qe(t.litellm_url),t.litellm_api_key&&Ye(t.litellm_api_key),t.vision_ocr_model&&Ze(t.vision_ocr_model),t.chat_model&&$e(t.chat_model)}}catch(e){console.error(`Failed to load embedding config:`,e)}finally{Ne(!1)}},[]);(0,_.useEffect)(()=>{it(),at(),ot(),st()},[it,at,ot,st]),(0,_.useEffect)(()=>{e?.vector_store?(fe(e.vector_store),e.vector_store.provider&&ge(e.vector_store.provider),e.vector_store.mode&&ve(e.vector_store.mode),e.vector_store.storage_path&&be(e.vector_store.storage_path),e.vector_store.url&&Se(e.vector_store.url),e.vector_store.collection&&we(e.vector_store.collection)):e?.vector_store_provider&&fe(t=>t?{...t,provider:e.vector_store_provider||t.provider,mode:e.vector_store_mode||t.mode,collection:e.vector_store_collection||t.collection,points_count:e.points_count??t.points_count,healthy:e.vector_db_status?e.vector_db_status===`Healthy`:t.healthy}:null)},[e]);let ct=async()=>{rt(!0);try{let e=new URLSearchParams;Ke&&e.set(`url`,Ke.trim()),Je&&e.set(`api_key`,Je.trim());let t=await(await fetch(`/admin/api/models/discover?${e.toString()}`)).json();tt(t),t.status===`success`?L.success(`Discovered ${t.total_models} models from LiteLLM`):L.error(t.message||`Failed to discover models from LiteLLM`)}catch(e){tt({status:`error`,total_models:0,models:[],embedding_models:[],vision_models:[],chat_models:[],message:e.message||`Network error discovering models`}),L.error(`Error discovering models: ${e.message}`)}finally{rt(!1)}},lt=async e=>{e.preventDefault(),Fe(!0);try{let e={provider:Ie,threads:Number(Re),batch_size:Number(Be),dense_model:He.trim()||void 0,sparse_model:We.trim()||void 0,litellm_url:Ie===`api`&&Ke.trim()||void 0,litellm_api_key:Ie===`api`&&Je.trim()||void 0,vision_ocr_model:Xe.trim()||void 0,chat_model:Qe.trim()||void 0},n=await fetch(`/admin/api/settings/embedding`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}),r=await n.json();if(!n.ok)throw Error(r.error||r.message||`Failed to save embedding settings`);r.config&&je(r.config),L.success(`Embedding resource limits updated successfully`),t()}catch(e){L.error(`Error saving embedding settings: `+e.message)}finally{Fe(!1)}},ut=`${typeof window<`u`?window.location.origin:``}${g||`/api/webhooks/git`}`,dt=async()=>{try{navigator?.clipboard?.writeText&&await navigator.clipboard.writeText(ut),O(!0),L.info(`Webhook URL copied to clipboard`),setTimeout(()=>O(!1),2e3)}catch(e){L.error(`Failed to copy: `+e.message)}},ft=async e=>{e.preventDefault(),w(!0);try{let e={interval_mins:Number(u)};f.trim()&&(e.global_webhook_secret=f.trim());let t=await fetch(`/admin/api/settings/auto-sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to save auto-sync settings`);typeof n.has_global_secret==`boolean`?h(n.has_global_secret):f.trim()&&h(!0),typeof n.interval_mins==`number`&&d(n.interval_mins),p(``),L.success(`Auto-sync settings saved successfully`)}catch(e){L.error(`Error saving auto-sync settings: `+e.message)}finally{w(!1)}},pt=async()=>{if(f&&!m){p(``);return}if(window.confirm(`Clear the global webhook secret? Incoming webhook payloads will no longer require secret verification unless configured per-repository.`)){w(!0);try{let e=await fetch(`/admin/api/settings/auto-sync`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({interval_mins:Number(u),global_webhook_secret:``})}),t=await e.json();if(!e.ok)throw Error(t.error||`Failed to clear global webhook secret`);h(!1),p(``),L.success(`Global webhook secret cleared`)}catch(e){L.error(`Failed to clear webhook secret: `+e.message)}finally{w(!1)}}},mt=e=>{ge(e),e===`qdrant`?((!ye||ye===`data/chroma_db`)&&be(`data/qdrant_db`),(!xe||xe===`http://localhost:8000`)&&Se(`http://localhost:6333`)):((!ye||ye===`data/qdrant_db`)&&be(`data/chroma_db`),(!xe||xe===`http://localhost:6333`)&&Se(`http://localhost:8000`))},ht=e=>{ve(e),e===`embedded`&&!ye&&be(he===`chroma`?`data/chroma_db`:`data/qdrant_db`),e===`remote`&&!xe&&Se(he===`chroma`?`http://localhost:8000`:`http://localhost:6333`)},gt=async()=>{Ee(!0),I(null);try{let e={provider:he,mode:_e,storage_path:_e===`embedded`?ye.trim():null,url:_e===`remote`?xe.trim():null,collection:Ce.trim()||`knowledge_rag_v1`},t=await fetch(`/admin/api/vector-store/test`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}),n=await t.json();if(!t.ok||!n.success){let e=n.message||n.error||`Vector store connection test failed`;I({success:!1,message:e}),L.error(`Vector store test: `+e)}else{let e=n.message||`Vector store connection test successful`;I({success:!0,message:e}),L.success(e)}}catch(e){let t=e.message||`Connection error`;I({success:!1,message:t}),L.error(`Vector store test error: `+t)}finally{Ee(!1)}},_t=async()=>{let e=he===`chroma`?`ChromaDB`:`Qdrant`,n=_e===`embedded`?`Embedded Disk`:`Remote Server`;if(window.confirm(`Switch active vector database backend to ${e} (${n})? This will update settings and trigger a full re-indexing of all sources.`)){ke(!0);try{let n={provider:he,mode:_e,storage_path:_e===`embedded`?ye.trim():null,url:_e===`remote`?xe.trim():null,collection:Ce.trim()||`knowledge_rag_v1`},r=await fetch(`/admin/api/vector-store/switch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(n)}),i=await r.json();if(!r.ok||i.status===`error`){let e=i.error||i.message||`Failed to switch vector database backend`;I({success:!1,message:e}),L.error(`Switch error: `+e)}else{let n=i.message||`Switched vector backend to ${e}`;I({success:!0,message:n}),L.success(n),await at(),t()}}catch(e){I({success:!1,message:e.message}),L.error(`Switch error: `+e.message)}finally{ke(!1)}}},vt=async(e,n,i)=>{if(n.trim())try{let o=await fetch(`/admin/api/settings/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({[e]:n.trim()})}),c=await o.json();if(!o.ok)throw Error(c.error||`Failed to save token`);L.success(`${i} token saved successfully.`),e===`github_token`&&r(``),e===`gitlab_token`&&a(``),e===`gitea_token`&&s(``),t()}catch(e){L.error(`Error saving ${i} token: `+e.message)}},yt=async(e,n)=>{if(window.confirm(`Clear the stored ${n} token from database?`))try{let r=await fetch(`/admin/api/settings/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({[e]:``})});if(!r.ok){let e=await r.json().catch(()=>({}));throw Error(e.error||`Failed to clear token`)}L.success(`${n} token cleared`),t()}catch(e){L.error(`Failed to clear ${n} token: `+e.message)}},bt=async e=>{if(e.preventDefault(),!(!A.trim()||!se.trim())){ue(!0);try{let e=await fetch(`/admin/api/settings/hosts`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({host:A.trim(),provider:ne,auth_user:ae.trim()||null,auth_token:se.trim()})}),t=await e.json();if(!e.ok)throw Error(t.error||`Failed to save host credential`);L.success(`Host credential for '${A.trim()}' saved`),ee(!1),te(``),re(`gitlab`),oe(``),P(``),it()}catch(e){L.error(`Error: `+e.message)}finally{ue(!1)}}},xt=async(e,t)=>{if(window.confirm(`Remove stored credentials for host '${t}'?`))try{let n=await fetch(`/admin/api/settings/hosts/${e}`,{method:`DELETE`});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to delete`)}L.success(`Removed credentials for '${t}'`),it()}catch(e){L.error(`Failed to remove: `+e.message)}},St=e?.providers_auth?.github||{token_source:e?.token_source||`None`,masked_token:e?.masked_token||`None`},Ct=e?.providers_auth?.gitlab||{token_source:`None`,masked_token:`None`},wt=e?.providers_auth?.gitea||{token_source:`None`,masked_token:`None`};return(0,b.jsxs)(`div`,{className:`tab-content active`,style:{display:`flex`,flexDirection:`column`,gap:`24px`},children:[(0,b.jsx)(ce,{}),(0,b.jsx)(ie,{vectorStore:de,isLoadingVs:pe,testFeedback:De,vsProvider:he,vsMode:_e,vsStoragePath:ye,setVsStoragePath:be,vsUrl:xe,setVsUrl:Se,vsCollection:Ce,setVsCollection:we,isTestingVs:Te,isSwitchingVs:Oe,onProviderChange:mt,onModeChange:ht,onTestConnection:gt,onSwitchBackend:_t}),(0,b.jsx)(j,{embeddingConfig:Ae,isLoadingEmb:Me,isSavingEmb:Pe,embProvider:Ie,setEmbProvider:Le,embThreads:Re,setEmbThreads:ze,embBatchSize:Be,setEmbBatchSize:Ve,embDenseModel:He,setEmbDenseModel:Ue,embSparseModel:We,setEmbSparseModel:Ge,embLitellmUrl:Ke,setEmbLitellmUrl:qe,embLitellmApiKey:Je,setEmbLitellmApiKey:Ye,embVisionOcrModel:Xe,setEmbVisionOcrModel:Ze,embChatModel:Qe,setEmbChatModel:$e,discoveryResult:et,isDiscovering:nt,onDiscoverModels:ct,onSaveEmbeddingSettings:lt}),(0,b.jsx)(M,{isLoadingAutoSync:y,intervalMins:u,setIntervalMins:d,hasGlobalSecret:m,showWebhookSecret:T,setShowWebhookSecret:E,webhookSecret:f,setWebhookSecret:p,fullWebhookUrl:ut,copiedWebhookUrl:D,isSavingAutoSync:C,onSaveAutoSync:ft,onClearWebhookSecret:pt,onCopyWebhookUrl:dt}),(0,b.jsx)(N,{stats:e,ghAuth:St,glAuth:Ct,gtAuth:wt,ghToken:n,setGhToken:r,glToken:i,setGlToken:a,gtToken:o,setGtToken:s,hostCredentials:c,isHostModalOpen:k,setIsHostModalOpen:ee,newHost:A,setNewHost:te,newHostProvider:ne,setNewHostProvider:re,newHostUser:ae,setNewHostUser:oe,newHostToken:se,setNewHostToken:P,isSavingHost:F,onSaveToken:vt,onClearToken:yt,onSaveHostCredential:bt,onDeleteHostCredential:xt}),(0,b.jsx)(le,{})]})}function de(){let e=S(),[t,n]=(0,_.useState)([]),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(`ALL`),[s,c]=(0,_.useState)(``),[l,u]=(0,_.useState)(!0),[d,f]=(0,_.useState)(new Set),p=(0,_.useRef)(null),m=(0,_.useRef)(null),h=(0,_.useCallback)(async()=>{i(!0);try{let e=await fetch(`/admin/api/logs`);if(!e.ok)throw Error(`HTTP ${e.status}`);let t=await e.json();n(Array.isArray(t)?t:[])}catch(t){e.error(`Failed to load diagnostics logs: ${t.message}`)}finally{i(!1)}},[e]);(0,_.useEffect)(()=>{h();let e=setInterval(h,8e3);return()=>clearInterval(e)},[h]),(0,_.useEffect)(()=>{l&&m.current&&(m.current.scrollTop=m.current.scrollHeight)},[t,l]);let g=async()=>{if(window.confirm(`Are you sure you want to clear all server diagnostics logs?`))try{let t=await fetch(`/admin/api/logs`,{method:`DELETE`});if(!t.ok){let e=await t.json().catch(()=>({}));throw Error(e.error||`HTTP ${t.status}`)}n([]),f(new Set),e.success(`Diagnostics logs cleared.`)}catch(t){e.error(`Failed to clear logs: ${t.message}`)}},v=e=>{f(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},y=e=>{switch(e.toUpperCase()){case`ERROR`:return`badge badge-danger`;case`WARNING`:return`badge badge-warning`;case`INFO`:return`badge badge-primary`;case`DEBUG`:return`badge badge-secondary`;default:return`badge badge-secondary`}},x=t.filter(e=>{if(a!==`ALL`&&e.level.toUpperCase()!==a)return!1;if(s.trim()){let t=s.toLowerCase(),n=e.message?.toLowerCase().includes(t),r=e.logger?.toLowerCase().includes(t),i=e.traceback?.toLowerCase().includes(t),a=e.level?.toLowerCase().includes(t);if(!n&&!r&&!i&&!a)return!1}return!0}),C={ALL:t.length,INFO:t.filter(e=>e.level===`INFO`).length,WARNING:t.filter(e=>e.level===`WARNING`).length,ERROR:t.filter(e=>e.level===`ERROR`).length,DEBUG:t.filter(e=>e.level===`DEBUG`).length};return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card log-viewer-container`,children:[(0,b.jsxs)(`div`,{className:`log-viewer-header`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Diagnostics & Server Logs`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Inspect real-time server runtime events, tree-sitter AST parsing, background indexing, and MCP tool traces.`})]}),(0,b.jsxs)(`div`,{className:`log-viewer-actions`,children:[(0,b.jsxs)(`label`,{className:`log-autoscroll-label`,children:[(0,b.jsx)(`input`,{type:`checkbox`,checked:l,onChange:e=>u(e.target.checked)}),`Auto-scroll`]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:h,disabled:r,title:`Refresh logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-rotate ${r?`fa-spin`:``}`}),` Refresh`]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-danger`,onClick:g,title:`Clear all logs`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Clear Logs`]})]})]}),(0,b.jsxs)(`div`,{className:`log-toolbar`,children:[(0,b.jsx)(`div`,{className:`log-filter-pills`,children:[`ALL`,`INFO`,`WARNING`,`ERROR`,`DEBUG`].map(e=>(0,b.jsxs)(`button`,{type:`button`,className:`log-filter-btn ${a===e?`active`:``} ${e.toLowerCase()}`,onClick:()=>o(e),children:[e,` `,(0,b.jsx)(`span`,{className:`pill-count`,children:C[e]})]},e))}),(0,b.jsxs)(`div`,{className:`log-search-wrapper`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass search-icon`}),(0,b.jsx)(`input`,{type:`text`,className:`log-search-input`,placeholder:`Search logs by message, logger, or traceback...`,value:s,onChange:e=>c(e.target.value)}),s&&(0,b.jsx)(`button`,{type:`button`,className:`clear-search-btn`,onClick:()=>c(``),title:`Clear search`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-xmark`})})]})]}),(0,b.jsx)(`div`,{className:`log-stream-container`,ref:m,children:x.length===0?(0,b.jsxs)(`div`,{className:`empty-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-circle-info`,style:{fontSize:`2rem`,marginBottom:`12px`,opacity:.5}}),(0,b.jsxs)(`p`,{children:[`No logs available `,s||a!==`ALL`?`matching current filter`:``,`.`]})]}):(0,b.jsxs)(`div`,{className:`log-stream-list`,children:[x.map((e,t)=>{let n=!!e.traceback,r=d.has(t);return(0,b.jsxs)(`div`,{className:`log-entry log-level-${e.level.toLowerCase()} ${n?`has-traceback`:``}`,children:[(0,b.jsxs)(`div`,{className:`log-entry-main`,children:[(0,b.jsx)(`span`,{className:`log-timestamp`,children:e.timestamp}),(0,b.jsx)(`span`,{className:y(e.level),children:e.level}),(0,b.jsx)(`span`,{className:`log-logger code`,children:e.logger}),(0,b.jsx)(`span`,{className:`log-message`,children:e.message}),n&&(0,b.jsxs)(`button`,{type:`button`,className:`btn-traceback-toggle`,onClick:()=>v(t),title:`Toggle traceback details`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${r?`fa-chevron-down`:`fa-chevron-right`}`}),(0,b.jsx)(`span`,{children:r?`Hide Stack Trace`:`View Stack Trace`})]})]}),n&&r&&(0,b.jsx)(`div`,{className:`log-traceback-wrapper`,children:(0,b.jsx)(`pre`,{className:`traceback-box`,children:e.traceback})})]},`${e.timestamp}-${t}`)}),(0,b.jsx)(`div`,{ref:p})]})})]})})}var fe=({repos:e,selectedRepo:t,onSelectRepo:n,density:r,onChangeDensity:i,searchQuery:a=``,onSearchChange:o,totalFiles:s=0,totalSymbols:c=0,onRefresh:l,loading:u=!1})=>(0,b.jsxs)(`div`,{className:`nav-toolbar`,"data-testid":`navigator-toolbar`,children:[(0,b.jsxs)(`div`,{className:`nav-toolbar-left`,children:[(0,b.jsxs)(`div`,{className:`nav-repo-selector-wrapper`,children:[(0,b.jsx)(`label`,{htmlFor:`nav-repo-select`,className:`nav-repo-label`,children:`Repository:`}),(0,b.jsxs)(`select`,{id:`nav-repo-select`,"aria-label":`Repository`,className:`nav-repo-select`,value:t,onChange:e=>n(e.target.value),disabled:u,children:[(0,b.jsx)(`option`,{value:`__all__`,children:`All Repositories (__all__)`}),e.filter(e=>e.name!==`__all__`).map(e=>(0,b.jsx)(`option`,{value:e.name,children:e.name},e.id??e.name))]})]}),(0,b.jsxs)(`div`,{className:`nav-stats-badges`,children:[(0,b.jsxs)(`span`,{className:`nav-stat-badge`,title:`Total Indexed Files`,children:[(0,b.jsx)(`span`,{className:`stat-num`,children:s}),` files`]}),(0,b.jsxs)(`span`,{className:`nav-stat-badge`,title:`Total Extracted AST Symbols`,children:[(0,b.jsx)(`span`,{className:`stat-num`,children:c}),` symbols`]})]})]}),(0,b.jsx)(`div`,{className:`nav-toolbar-center`,children:o&&(0,b.jsxs)(`div`,{className:`nav-global-search`,children:[(0,b.jsxs)(`svg`,{className:`search-icon`,width:`14`,height:`14`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,b.jsx)(`circle`,{cx:`11`,cy:`11`,r:`8`}),(0,b.jsx)(`line`,{x1:`21`,y1:`21`,x2:`16.65`,y2:`16.65`})]}),(0,b.jsx)(`input`,{type:`text`,className:`nav-search-input`,placeholder:`Search files (Ctrl+P / /)...`,value:a,onChange:e=>o(e.target.value),"aria-label":`Quick search files`}),a&&(0,b.jsx)(`button`,{type:`button`,className:`nav-search-clear-btn`,onClick:()=>o(``),"aria-label":`Clear search`,children:`✕`})]})}),(0,b.jsxs)(`div`,{className:`nav-toolbar-right`,children:[(0,b.jsxs)(`div`,{className:`nav-density-switcher`,role:`group`,"aria-label":`Density mode`,children:[(0,b.jsx)(`span`,{className:`density-label`,children:`Density:`}),(0,b.jsx)(`button`,{type:`button`,className:`density-btn ${r===`compact`?`active`:``}`,onClick:()=>i(`compact`),title:`Compact (20px rows - IDE mode)`,"aria-pressed":r===`compact`,children:`Compact`}),(0,b.jsx)(`button`,{type:`button`,className:`density-btn ${r===`balanced`?`active`:``}`,onClick:()=>i(`balanced`),title:`Balanced (28px rows - Default)`,"aria-pressed":r===`balanced`,children:`Balanced`}),(0,b.jsx)(`button`,{type:`button`,className:`density-btn ${r===`spacious`?`active`:``}`,onClick:()=>i(`spacious`),title:`Spacious (36px rows - Cards)`,"aria-pressed":r===`spacious`,children:`Spacious`})]}),l&&(0,b.jsx)(`button`,{type:`button`,className:`nav-refresh-btn ${u?`spinning`:``}`,onClick:l,title:`Refresh codebase tree`,disabled:u,"aria-label":`Refresh codebase tree`,children:(0,b.jsx)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:(0,b.jsx)(`path`,{d:`M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67`})})})]})]});function pe(e,t){let n=e.toLowerCase();return n.endsWith(`.py`)||t===`python`?{icon:`🐍`,className:`icon-py`}:n.endsWith(`.tsx`)||n.endsWith(`.ts`)||t===`typescript`?{icon:`⚡`,className:`icon-ts`}:n.endsWith(`.jsx`)||n.endsWith(`.js`)||n.endsWith(`.mjs`)||t===`javascript`?{icon:`📜`,className:`icon-js`}:n.endsWith(`.go`)||t===`go`?{icon:`🔷`,className:`icon-go`}:n.endsWith(`.rs`)||t===`rust`?{icon:`🦀`,className:`icon-rs`}:n.endsWith(`.json`)?{icon:`📄`,className:`icon-json`}:n.endsWith(`.md`)||n.endsWith(`.markdown`)?{icon:`📝`,className:`icon-md`}:n.endsWith(`.css`)||n.endsWith(`.scss`)?{icon:`🎨`,className:`icon-css`}:n.endsWith(`.sql`)?{icon:`🗄️`,className:`icon-sql`}:n.endsWith(`.yaml`)||n.endsWith(`.yml`)||n.endsWith(`.toml`)?{icon:`⚙️`,className:`icon-yaml`}:{icon:`📄`,className:`icon-file`}}var me=({nodes:e,selectedPath:t,onSelectFile:n,filterText:r,onFilterChange:i,density:a=`balanced`,loading:o=!1})=>{let[s,c]=(0,_.useState)(``),l=r===void 0?s:r,u=i||c,[d,f]=(0,_.useState)(new Set),[p,m]=(0,_.useState)(-1),h=(0,_.useRef)(null),g=(0,_.useCallback)(e=>{let t=[],n=e=>{if(!(!e||!Array.isArray(e)))for(let r of e)r&&r.is_dir&&(t.push(r.id),Array.isArray(r.children)&&n(r.children))};return n(e),t},[]),v=(0,_.useCallback)((e,t)=>{if(!e||!Array.isArray(e))return{filteredNodes:[],matchedDirIds:new Set};let n=t.toLowerCase().trim(),r=new Set,i=e=>{if(!e)return null;let t=(e.name||``).toLowerCase().includes(n)||(e.path||``).toLowerCase().includes(n);if(e.is_dir){let n=Array.isArray(e.children)?e.children:[],a=n.map(i).filter(e=>e!==null);return a.length>0||t?(r.add(e.id),{...e,children:a.length>0?a:n}):null}return t?e:null};return{filteredNodes:e.map(i).filter(e=>e!==null),matchedDirIds:r}},[]),{filteredNodes:y,matchedDirIds:x}=(0,_.useMemo)(()=>l.trim()?v(e,l):{filteredNodes:Array.isArray(e)?e:[],matchedDirIds:new Set},[e,l,v]);(0,_.useEffect)(()=>{l.trim()&&f(e=>{let t=new Set(e);return x.forEach(e=>t.add(e)),t})},[l,x]),(0,_.useEffect)(()=>{if(t){let e=t.split(`/`),n=[];for(let t=1;t0&&f(e=>{let t=new Set(e);return n.forEach(e=>t.add(e)),t})}},[t]);let S=(0,_.useCallback)(e=>{f(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),C=(0,_.useCallback)(()=>{let t=g(e);f(new Set(t))},[e,g]),w=(0,_.useCallback)(()=>{f(new Set)},[]),T=(0,_.useMemo)(()=>{let e=[],t=!!l.trim(),n=(r,i)=>{if(!(!r||!Array.isArray(r)))for(let a of r){if(!a)continue;let r=!!(a.is_dir&&Array.isArray(a.children)&&a.children.length>0),o=d.has(a.id)||t&&x.has(a.id);e.push({node:a,depth:i,isExpanded:o,hasChildren:r}),a.is_dir&&o&&Array.isArray(a.children)&&n(a.children,i+1)}};return n(y,0),e},[y,d,l,x]);return(0,b.jsxs)(`div`,{className:`nav-tree-pane density-${a}`,"data-testid":`navigator-tree-container`,tabIndex:0,ref:h,onKeyDown:e=>{if(T.length!==0){if(e.key===`ArrowDown`)e.preventDefault(),m(e=>ee>0?e-1:T.length-1);else if(e.key===`ArrowRight`){if(e.preventDefault(),p>=0&&p=0&&p=0&&pu(e.target.value)}),l&&(0,b.jsx)(`button`,{type:`button`,className:`nav-tree-clear-btn`,onClick:()=>u(``),"aria-label":`Clear filter`,children:`✕`})]})]}),(0,b.jsx)(`div`,{className:`nav-tree-content`,children:o?(0,b.jsxs)(`div`,{className:`nav-loading-wrapper`,"data-testid":`tree-loading-spinner`,children:[(0,b.jsx)(`div`,{className:`nav-spinner`}),(0,b.jsx)(`span`,{children:`Loading codebase tree...`})]}):T.length===0?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`p`,{children:`No matching files found`}),l&&(0,b.jsx)(`button`,{type:`button`,className:`nav-clear-filter-btn`,onClick:()=>u(``),children:`Clear filter`})]}):(0,b.jsx)(`div`,{className:`nav-tree-list`,role:`tree`,children:T.map((e,r)=>{let{node:i,depth:a,isExpanded:o}=e,s=!i.is_dir&&i.path===t,c=r===p,{icon:l,className:u}=i.is_dir?{icon:o?`📂`:`📁`,className:`icon-dir`}:pe(i.name,i.language);return(0,b.jsxs)(`div`,{role:`treeitem`,"aria-expanded":i.is_dir?o:void 0,"aria-selected":s,className:`nav-tree-item ${i.is_dir?`dir-item`:`file-item`} ${s?`selected`:``} ${c?`focused`:``}`,style:{paddingLeft:`${a*14+10}px`},onClick:()=>{m(r),i.is_dir?S(i.id):n(i)},children:[(0,b.jsx)(`span`,{className:`tree-chevron`,children:i.is_dir?(0,b.jsx)(`span`,{className:`chevron-arrow ${o?`open`:``}`,children:`▶`}):(0,b.jsx)(`span`,{className:`chevron-spacer`})}),(0,b.jsx)(`span`,{className:`tree-icon ${u}`,"aria-hidden":`true`,children:l}),(0,b.jsx)(`span`,{className:`tree-label`,title:i.path,children:i.name}),(0,b.jsxs)(`div`,{className:`tree-badges`,children:[i.symbol_count>0&&(0,b.jsxs)(`span`,{className:`badge-symbols`,title:`${i.symbol_count} AST Symbols`,children:[i.symbol_count,` sym`]}),i.route_count>0&&(0,b.jsxs)(`span`,{className:`badge-routes`,title:`${i.route_count} API Routes`,children:[i.route_count,` rts`]})]})]},i.id)})})})]})};function he(e){switch(e.toUpperCase()){case`GET`:return`method-get`;case`POST`:return`method-post`;case`PUT`:return`method-put`;case`DELETE`:return`method-delete`;case`PATCH`:return`method-patch`;default:return`method-other`}}function ge(e){switch(e.toLowerCase()){case`class`:return`kind-class`;case`function`:case`method`:case`async function`:return`kind-function`;case`variable`:case`constant`:return`kind-variable`;case`interface`:case`type`:return`kind-type`;default:return`kind-default`}}var _e=({outline:e,selectedSymbolId:t,onSelectSymbol:n,density:r=`balanced`,loading:i=!1})=>{let[a,o]=(0,_.useState)(`all`),[s,c]=(0,_.useState)(``),l=e?.symbols||[],u=(0,_.useMemo)(()=>{let e=0,t=0,n=0;for(let r of l){r.route&&e++;let i=r.kind.toLowerCase();i===`class`||i===`interface`?t++:(i.includes(`func`)||i===`method`)&&(r.route||n++)}return{all:l.length,routes:e,classes:t,functions:n}},[l]),d=(0,_.useMemo)(()=>l.filter(e=>{if(a===`routes`){if(!e.route)return!1}else if(a===`classes`){let t=e.kind.toLowerCase();if(t!==`class`&&t!==`interface`)return!1}else if(a===`functions`){let t=e.kind.toLowerCase();if(!t.includes(`func`)&&t!==`method`||e.route)return!1}if(s.trim()){let t=s.toLowerCase(),n=e.name.toLowerCase().includes(t),r=(e.signature||``).toLowerCase().includes(t),i=e.route?e.route.path_pattern.toLowerCase().includes(t)||e.route.http_method.toLowerCase().includes(t):!1;if(!n&&!r&&!i)return!1}return!0}),[l,a,s]),f=e?.filepath?e.filepath.split(`/`).pop():``;return(0,b.jsxs)(`div`,{className:`nav-outline-pane density-${r}`,"data-testid":`navigator-outline-container`,children:[(0,b.jsxs)(`div`,{className:`nav-outline-header`,children:[(0,b.jsxs)(`div`,{className:`nav-outline-title-row`,children:[(0,b.jsxs)(`div`,{className:`nav-outline-title`,children:[(0,b.jsxs)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,b.jsx)(`line`,{x1:`8`,y1:`6`,x2:`21`,y2:`6`}),(0,b.jsx)(`line`,{x1:`8`,y1:`12`,x2:`21`,y2:`12`}),(0,b.jsx)(`line`,{x1:`8`,y1:`18`,x2:`21`,y2:`18`}),(0,b.jsx)(`line`,{x1:`3`,y1:`6`,x2:`3.01`,y2:`6`}),(0,b.jsx)(`line`,{x1:`3`,y1:`12`,x2:`3.01`,y2:`12`}),(0,b.jsx)(`line`,{x1:`3`,y1:`18`,x2:`3.01`,y2:`18`})]}),(0,b.jsx)(`span`,{children:`Symbols & Routes`})]}),e&&(0,b.jsx)(`div`,{className:`nav-file-badge`,title:e.filepath,children:(0,b.jsx)(`span`,{className:`file-name`,children:f})})]}),e&&(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`div`,{className:`nav-outline-search-bar`,children:[(0,b.jsxs)(`svg`,{className:`search-icon`,width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`circle`,{cx:`11`,cy:`11`,r:`8`}),(0,b.jsx)(`line`,{x1:`21`,y1:`21`,x2:`16.65`,y2:`16.65`})]}),(0,b.jsx)(`input`,{type:`text`,className:`nav-outline-search-input`,placeholder:`Filter symbols...`,value:s,onChange:e=>c(e.target.value)}),s&&(0,b.jsx)(`button`,{type:`button`,className:`nav-outline-clear-btn`,onClick:()=>c(``),"aria-label":`Clear symbol search`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`nav-category-chips`,role:`tablist`,"aria-label":`Symbol Category Filter`,children:[(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`all`?`active`:``}`,onClick:()=>o(`all`),children:[`All `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.all})]}),(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`routes`?`active`:``}`,onClick:()=>o(`routes`),children:[`Routes `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.routes})]}),(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`classes`?`active`:``}`,onClick:()=>o(`classes`),children:[`Classes `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.classes})]}),(0,b.jsxs)(`button`,{type:`button`,role:`button`,className:`category-chip ${a===`functions`?`active`:``}`,onClick:()=>o(`functions`),children:[`Functions `,(0,b.jsx)(`span`,{className:`chip-count`,children:u.functions})]})]})]})]}),(0,b.jsx)(`div`,{className:`nav-outline-content`,children:i?(0,b.jsxs)(`div`,{className:`nav-outline-skeleton`,"data-testid":`outline-loading-skeleton`,children:[(0,b.jsx)(`div`,{className:`skeleton-item shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-item shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-item shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-item shimmer`})]}):e?l.length===0?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`div`,{className:`empty-icon`,children:`⚡`}),(0,b.jsx)(`h4`,{children:`No Symbols Found`}),(0,b.jsx)(`p`,{children:`No symbols found in this file.`})]}):d.length===0?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`h4`,{children:`No Matching Symbols`}),(0,b.jsx)(`p`,{children:`No symbols match the current category and search filters.`}),(0,b.jsx)(`button`,{type:`button`,className:`nav-clear-filter-btn`,onClick:()=>{o(`all`),c(``)},children:`Reset Filters`})]}):(0,b.jsx)(`div`,{className:`nav-symbol-list`,role:`list`,children:d.map(e=>{let r=e.id===t,i=ge(e.kind);return(0,b.jsxs)(`div`,{"data-testid":`symbol-item-${e.id}`,className:`nav-symbol-item ${r?`active`:``}`,onClick:()=>n(e),role:`listitem`,tabIndex:0,onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),n(e))},children:[(0,b.jsxs)(`div`,{className:`symbol-header-row`,children:[(0,b.jsxs)(`div`,{className:`symbol-name-col`,children:[(0,b.jsx)(`span`,{className:`symbol-kind-badge ${i}`,children:e.kind}),(0,b.jsx)(`span`,{className:`symbol-name-text`,title:e.full_symbol||e.name,children:e.name})]}),(0,b.jsx)(`div`,{className:`symbol-meta-col`,children:(0,b.jsxs)(`span`,{className:`symbol-line-badge`,children:[`L`,e.start_line,e.end_line&&e.end_line!==e.start_line?` - L${e.end_line}`:``]})})]}),e.route&&(0,b.jsxs)(`div`,{className:`symbol-route-row`,children:[(0,b.jsx)(`span`,{className:`route-method-badge ${he(e.route.http_method)}`,children:e.route.http_method}),(0,b.jsx)(`span`,{className:`route-path-text`,title:e.route.path_pattern,children:e.route.path_pattern}),e.route.framework&&(0,b.jsx)(`span`,{className:`route-framework-tag`,children:e.route.framework})]}),e.signature&&(0,b.jsx)(`div`,{className:`symbol-signature-snippet`,children:(0,b.jsx)(`code`,{children:e.signature})})]},e.id)})}):(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`div`,{className:`empty-icon`,children:`📂`}),(0,b.jsx)(`h4`,{children:`No File Selected`}),(0,b.jsx)(`p`,{children:`Select a file from the tree to inspect its symbols and routes.`})]})})]})},ve=({impact:e,onSelectCaller:t,onSelectCallee:n,density:r=`balanced`,loading:i=!1})=>{let[a,o]=(0,_.useState)(!1),s=async()=>{if(!e?.symbol)return;let{filepath:t,start_line:n,end_line:r}=e.symbol,i=`${t}#L${n}${r&&r!==n?`-L${r}`:``}`;try{navigator?.clipboard?.writeText&&await navigator.clipboard.writeText(i),o(!0),setTimeout(()=>o(!1),2e3)}catch{}},c=e?.symbol,l=e?.route,u=e?.callers||[],d=e?.callees||[],f=e?.imports||[];return(0,b.jsxs)(`div`,{className:`nav-inspector-pane density-${r}`,"data-testid":`navigator-inspector-container`,children:[(0,b.jsxs)(`div`,{className:`nav-inspector-header`,children:[(0,b.jsxs)(`div`,{className:`nav-inspector-title`,children:[(0,b.jsxs)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,strokeLinecap:`round`,strokeLinejoin:`round`,children:[(0,b.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,b.jsx)(`path`,{d:`M12 16v-4M12 8h.01`})]}),(0,b.jsx)(`span`,{children:`Code Intelligence & Impact`})]}),c&&(0,b.jsx)(`button`,{type:`button`,className:`nav-copy-permalink-btn`,onClick:s,title:`Copy file path & line range permalink`,"aria-label":`Copy Permalink`,children:a?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:(0,b.jsx)(`polyline`,{points:`20 6 9 17 4 12`})}),(0,b.jsx)(`span`,{children:`Copied!`})]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`path`,{d:`M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71`}),(0,b.jsx)(`path`,{d:`M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71`})]}),(0,b.jsx)(`span`,{children:`Copy Permalink`})]})})]}),(0,b.jsx)(`div`,{className:`nav-inspector-content`,children:i?(0,b.jsxs)(`div`,{className:`nav-inspector-skeleton`,"data-testid":`inspector-loading-skeleton`,children:[(0,b.jsx)(`div`,{className:`skeleton-header shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-metrics shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-block shimmer`}),(0,b.jsx)(`div`,{className:`skeleton-block shimmer`})]}):!e||!c?(0,b.jsxs)(`div`,{className:`nav-empty-state`,children:[(0,b.jsx)(`div`,{className:`empty-icon`,children:`🔍`}),(0,b.jsx)(`h4`,{children:`No Symbol Selected`}),(0,b.jsx)(`p`,{children:`Select a symbol from the outline to inspect its callers, dependencies, and impact.`})]}):(0,b.jsxs)(`div`,{className:`nav-inspector-body`,children:[(0,b.jsxs)(`div`,{className:`inspector-card symbol-summary-card`,children:[(0,b.jsxs)(`div`,{className:`summary-title-row`,children:[(0,b.jsx)(`span`,{className:`symbol-kind-badge ${ge(c.kind)}`,children:c.kind}),(0,b.jsx)(`h3`,{className:`summary-name`,title:c.full_symbol||c.name,children:c.name})]}),(0,b.jsxs)(`div`,{className:`summary-location-row`,children:[(0,b.jsxs)(`span`,{className:`summary-file-path`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`path`,{d:`M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z`}),(0,b.jsx)(`polyline`,{points:`13 2 13 9 20 9`})]}),c.filepath]}),(0,b.jsxs)(`span`,{className:`summary-line-range`,children:[`L`,c.start_line,` - L`,c.end_line]})]})]}),(0,b.jsxs)(`div`,{className:`inspector-metrics-grid`,children:[(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Incoming Callers`}),(0,b.jsx)(`span`,{className:`metric-value`,"data-testid":`metric-callers`,children:u.length})]}),(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Outgoing Callees`}),(0,b.jsx)(`span`,{className:`metric-value`,"data-testid":`metric-callees`,children:d.length})]}),(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Total Imports`}),(0,b.jsx)(`span`,{className:`metric-value`,"data-testid":`metric-imports`,children:f.length})]}),(0,b.jsxs)(`div`,{className:`metric-box`,children:[(0,b.jsx)(`span`,{className:`metric-label`,children:`Language`}),(0,b.jsx)(`span`,{className:`metric-value metric-lang`,"data-testid":`metric-scope`,children:c.language||`code`})]})]}),l&&(0,b.jsxs)(`div`,{className:`inspector-card route-card`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,b.jsx)(`line`,{x1:`2`,y1:`12`,x2:`22`,y2:`12`}),(0,b.jsx)(`path`,{d:`M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z`})]}),(0,b.jsx)(`span`,{children:`API Route Mapping`})]}),(0,b.jsxs)(`div`,{className:`route-detail-row`,children:[(0,b.jsx)(`span`,{className:`route-method-badge ${he(l.http_method)}`,children:l.http_method}),(0,b.jsx)(`span`,{className:`route-path-code`,children:l.path_pattern}),l.framework&&(0,b.jsx)(`span`,{className:`route-framework-tag`,children:l.framework})]})]}),c.signature&&(0,b.jsxs)(`div`,{className:`inspector-card code-preview-card`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`polyline`,{points:`16 18 22 12 16 6`}),(0,b.jsx)(`polyline`,{points:`8 6 2 12 8 18`})]}),(0,b.jsx)(`span`,{children:`Signature`})]}),(0,b.jsx)(`pre`,{className:`signature-code-block`,children:(0,b.jsx)(`code`,{children:c.signature})})]}),c.docstring&&(0,b.jsxs)(`div`,{className:`inspector-card docstring-card`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsxs)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`path`,{d:`M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z`}),(0,b.jsx)(`polyline`,{points:`14 2 14 8 20 8`}),(0,b.jsx)(`line`,{x1:`16`,y1:`13`,x2:`8`,y2:`13`}),(0,b.jsx)(`line`,{x1:`16`,y1:`17`,x2:`8`,y2:`17`}),(0,b.jsx)(`polyline`,{points:`10 9 9 9 8 9`})]}),(0,b.jsx)(`span`,{children:`Documentation`})]}),(0,b.jsx)(`p`,{className:`docstring-text`,children:c.docstring})]}),(0,b.jsxs)(`div`,{className:`inspector-card relations-card callers-section`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:(0,b.jsx)(`path`,{d:`M12 19V5M5 12l7-7 7 7`})}),(0,b.jsxs)(`span`,{children:[`Incoming Callers (`,u.length,`)`]})]}),u.length===0?(0,b.jsx)(`div`,{className:`nav-no-items-text`,children:`No incoming callers found in this repository.`}):(0,b.jsx)(`div`,{className:`relation-list`,children:u.map((e,n)=>(0,b.jsxs)(`div`,{"data-testid":`caller-item-${e.id??n}`,className:`relation-item caller-item`,onClick:()=>{e.source_filepath&&t&&t(e.source_filepath,e.source_symbol,e.source_symbol_id??void 0)},role:`button`,tabIndex:0,title:`Jump to ${e.source_symbol||`caller`} in ${e.source_filepath||``}`,children:[(0,b.jsxs)(`div`,{className:`relation-top`,children:[(0,b.jsx)(`span`,{className:`rel-symbol-name`,children:e.source_symbol||`Unknown Caller`}),(0,b.jsx)(`span`,{className:`rel-jump-hint`,"aria-hidden":`true`,children:`Jump ↗`})]}),(0,b.jsxs)(`div`,{className:`relation-bottom`,children:[e.source_filepath&&(0,b.jsx)(`span`,{className:`rel-filepath`,children:e.source_filepath}),e.all_lines?(0,b.jsxs)(`span`,{className:`rel-line`,title:`Lines: ${e.all_lines}`,children:[`L`,e.all_lines.includes(`,`)?e.all_lines.split(`,`).slice(0,3).join(`, L`)+(e.all_lines.split(`,`).length>3?`...`:``):e.all_lines]}):e.line_number?(0,b.jsxs)(`span`,{className:`rel-line`,children:[`L`,e.line_number]}):null,e.call_count&&e.call_count>1?(0,b.jsxs)(`span`,{className:`rel-count-badge`,children:[e.call_count,` calls`]}):null,e.relationship_type&&(0,b.jsx)(`span`,{className:`rel-type-tag`,children:e.relationship_type})]})]},e.id??n))})]}),(0,b.jsxs)(`div`,{className:`inspector-card relations-card dependencies-section`,children:[(0,b.jsxs)(`div`,{className:`card-section-title`,children:[(0,b.jsx)(`svg`,{width:`13`,height:`13`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:(0,b.jsx)(`path`,{d:`M12 5v14M5 12l7 7 7-7`})}),(0,b.jsxs)(`span`,{children:[`Outgoing Dependencies (`,d.length+f.length,`)`]})]}),d.length===0&&f.length===0?(0,b.jsx)(`div`,{className:`nav-no-items-text`,children:`No outgoing calls or imports.`}):(0,b.jsxs)(`div`,{className:`relation-list`,children:[d.map((e,t)=>(0,b.jsxs)(`div`,{"data-testid":`callee-item-${e.id??t}`,className:`relation-item callee-item ${e.target_filepath?`is-clickable`:``}`,onClick:()=>{e.target_filepath&&n&&n(e.target_filepath,e.target_symbol)},role:e.target_filepath?`button`:void 0,tabIndex:e.target_filepath?0:void 0,title:e.target_filepath?`Jump to ${e.target_symbol} in ${e.target_filepath}`:void 0,onKeyDown:t=>{e.target_filepath&&n&&(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),n(e.target_filepath,e.target_symbol))},children:[(0,b.jsxs)(`div`,{className:`relation-top`,children:[(0,b.jsx)(`span`,{className:`rel-symbol-name`,children:e.target_symbol}),(0,b.jsxs)(`div`,{className:`rel-top-right`,children:[(0,b.jsx)(`span`,{className:`rel-type-badge`,children:e.relationship_type||`CALLS`}),e.target_filepath&&(0,b.jsx)(`span`,{className:`rel-jump-hint`,"aria-hidden":`true`,children:`Jump ↗`})]})]}),(0,b.jsxs)(`div`,{className:`relation-bottom`,children:[e.target_filepath&&(0,b.jsx)(`span`,{className:`rel-filepath`,children:e.target_filepath}),e.all_lines?(0,b.jsxs)(`span`,{className:`rel-line`,title:`Lines: ${e.all_lines}`,children:[`L`,e.all_lines.includes(`,`)?e.all_lines.split(`,`).slice(0,3).join(`, L`)+(e.all_lines.split(`,`).length>3?`...`:``):e.all_lines]}):e.line_number?(0,b.jsxs)(`span`,{className:`rel-line`,children:[`L`,e.line_number]}):null,e.call_count&&e.call_count>1?(0,b.jsxs)(`span`,{className:`rel-count-badge`,children:[e.call_count,` calls`]}):null]})]},e.id??`callee-${t}`)),f.map((e,t)=>(0,b.jsxs)(`div`,{className:`relation-item import-item`,children:[(0,b.jsxs)(`div`,{className:`relation-top`,children:[(0,b.jsx)(`span`,{className:`rel-symbol-name`,children:e.target_symbol}),(0,b.jsx)(`span`,{className:`rel-type-badge import-badge`,children:`IMPORTS`})]}),(0,b.jsxs)(`div`,{className:`relation-bottom`,children:[e.all_lines?(0,b.jsxs)(`span`,{className:`rel-line`,title:`Lines: ${e.all_lines}`,children:[`L`,e.all_lines.includes(`,`)?e.all_lines.split(`,`).slice(0,3).join(`, L`)+(e.all_lines.split(`,`).length>3?`...`:``):e.all_lines]}):e.line_number?(0,b.jsxs)(`span`,{className:`rel-line`,children:[`L`,e.line_number]}):null,e.import_count&&e.import_count>1?(0,b.jsxs)(`span`,{className:`rel-count-badge`,children:[e.import_count,` imports`]}):null]})]},e.id??`import-${t}`))]})]})]})})]})},ye=`contextcortex_navigator_density`,be=({initialRepo:e=`__all__`,initialPath:t,initialSymbolId:n})=>{let[r,i]=(0,_.useState)(()=>{let e=localStorage.getItem(ye);return e===`compact`||e===`balanced`||e===`spacious`?e:`balanced`}),a=e=>{i(e),localStorage.setItem(ye,e)},[o,s]=(0,_.useState)([]),[c,l]=(0,_.useState)(e),[u,d]=(0,_.useState)(null),[f,p]=(0,_.useState)(!1),[m,h]=(0,_.useState)(``),[g,v]=(0,_.useState)(t||null),[y,x]=(0,_.useState)(null),[S,C]=(0,_.useState)(!1),[w,T]=(0,_.useState)(n||null),[E,D]=(0,_.useState)(null),[O,k]=(0,_.useState)(!1),[ee,A]=(0,_.useState)(null);(0,_.useEffect)(()=>{(async()=>{try{let e=await fetch(`/admin/api/repositories`);if(e.ok){let t=await e.json();s(Array.isArray(t)?t:[])}else{let e=await fetch(`/admin/api/repos`);if(e.ok){let t=await e.json();s(Array.isArray(t)?t:[])}}}catch(e){console.error(`Error fetching repositories:`,e)}})()},[]);let te=(0,_.useCallback)(async e=>{p(!0),A(null);try{let t=await fetch(`/admin/api/navigator/tree?repo=${encodeURIComponent(e)}`);if(!t.ok)throw Error(`Failed to load tree: ${t.status} ${t.statusText}`);let n=await t.json();d(n)}catch(e){console.error(`Error fetching codebase tree:`,e),A(e.message||`Failed to load codebase tree`)}finally{p(!1)}},[]);(0,_.useEffect)(()=>{te(c)},[c,te]);let ne=(0,_.useCallback)(async(e,t)=>{k(!0);try{let n=await fetch(`/admin/api/navigator/symbol-impact?repo=${encodeURIComponent(e)}&symbol_id=${t}`);if(!n.ok)throw Error(`Failed to load symbol impact: ${n.status}`);let r=await n.json();D(r)}catch(e){console.error(`Error fetching symbol impact:`,e),D(null)}finally{k(!1)}},[]),re=(0,_.useCallback)(async(e,t,n)=>{C(!0);try{let r=await fetch(`/admin/api/navigator/file-outline?repo=${encodeURIComponent(e)}&filepath=${encodeURIComponent(t)}`);if(!r.ok)throw Error(`Failed to load file outline: ${r.status}`);let i=await r.json();if(x(i),i.symbols&&i.symbols.length>0){let t;typeof n==`number`?t=i.symbols.find(e=>e.id===n):typeof n==`string`&&(t=i.symbols.find(e=>e.name===n||e.full_symbol===n));let r=t||i.symbols[0];T(r.id),await ne(e,r.id)}else T(null),D(null)}catch(e){console.error(`Error fetching outline:`,e),x(null),T(null),D(null)}finally{C(!1)}},[ne]);return(0,b.jsxs)(`div`,{className:`code-navigator-container density-${r}`,"data-testid":`code-navigator-container`,children:[(0,b.jsx)(fe,{repos:o,selectedRepo:c,onSelectRepo:e=>{l(e),v(null),x(null),T(null),D(null)},density:r,onChangeDensity:a,searchQuery:m,onSearchChange:h,totalFiles:u?.total_files??0,totalSymbols:u?.total_symbols??0,onRefresh:()=>te(c),loading:f}),ee&&(0,b.jsxs)(`div`,{className:`nav-error-banner`,role:`alert`,children:[(0,b.jsxs)(`svg`,{width:`15`,height:`15`,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:`2`,children:[(0,b.jsx)(`circle`,{cx:`12`,cy:`12`,r:`10`}),(0,b.jsx)(`line`,{x1:`12`,y1:`8`,x2:`12`,y2:`12`}),(0,b.jsx)(`line`,{x1:`12`,y1:`16`,x2:`12.01`,y2:`16`})]}),(0,b.jsx)(`span`,{children:ee}),(0,b.jsx)(`button`,{type:`button`,onClick:()=>A(null),className:`error-close-btn`,children:`✕`})]}),(0,b.jsxs)(`div`,{className:`nav-panes-layout`,children:[(0,b.jsx)(`section`,{className:`nav-pane-column nav-pane-tree`,"aria-label":`File Tree`,children:(0,b.jsx)(me,{nodes:u?.tree??[],selectedPath:g,onSelectFile:e=>{e.is_dir||(v(e.path),re(c,e.path))},filterText:m,onFilterChange:h,density:r,loading:f})}),(0,b.jsx)(`section`,{className:`nav-pane-column nav-pane-outline`,"aria-label":`Symbol and Route Outline`,children:(0,b.jsx)(_e,{outline:y,selectedSymbolId:w,onSelectSymbol:e=>{T(e.id),ne(c,e.id)},density:r,loading:S})}),(0,b.jsx)(`section`,{className:`nav-pane-column nav-pane-inspector`,"aria-label":`Code Intelligence and Impact`,children:(0,b.jsx)(ve,{impact:E,onSelectCaller:(e,t,n)=>{v(e),re(c,e,n??t)},onSelectCallee:(e,t)=>{e&&(v(e),re(c,e,t))},density:r,loading:O})})]})]})};function xe({data:e,onConfirm:t,onCancel:n,isIngesting:r=!1}){let[i,a]=(0,_.useState)(`pages`),[o,s]=(0,_.useState)(0),c=e.total_pages||e.pages.length||1,l=e.pages[o]||{page_number:1,text:``,char_count:0,ocr_applied:!1};return(0,b.jsx)(`div`,{className:`modal-backdrop`,"data-testid":`pdf-preview-modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`850px`,width:`95%`,maxHeight:`90vh`,display:`flex`,flexDirection:`column`},"data-testid":`pdf-preview-modal`,children:[(0,b.jsxs)(`div`,{className:`modal-header`,style:{marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{style:{display:`flex`,alignItems:`center`,gap:`8px`,margin:0,fontSize:`1.25rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf text-red-500 mr-2`,style:{color:`#ef4444`}}),(0,b.jsx)(`span`,{children:`PDF Extraction Preview`})]}),(0,b.jsx)(`div`,{style:{fontSize:`0.85rem`,color:`var(--text-muted)`,marginTop:`4px`},children:(0,b.jsx)(`code`,{children:e.filename})})]}),(0,b.jsx)(`button`,{type:`button`,className:`btn-close`,onClick:n,"aria-label":`Close modal`,children:`×`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,flexWrap:`wrap`,gap:`10px`,padding:`10px 14px`,background:`rgba(255, 255, 255, 0.04)`,borderRadius:`6px`,marginBottom:`14px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`14px`,flexWrap:`wrap`,alignItems:`center`,fontSize:`0.85rem`},children:[(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`strong`,{children:`Total Pages:`}),` `,(0,b.jsx)(`span`,{className:`badge badge-primary`,"data-testid":`total-pages-badge`,children:e.total_pages})]}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`strong`,{children:`Total Characters:`}),` `,(0,b.jsx)(`span`,{className:`badge badge-primary`,"data-testid":`total-chars-badge`,children:e.total_characters.toLocaleString()})]}),(0,b.jsxs)(`span`,{children:[(0,b.jsx)(`strong`,{children:`OCR Applied:`}),` `,(0,b.jsxs)(`span`,{className:`badge ${e.ocr_pages_count>0?`badge-warning`:`badge-secondary`}`,"data-testid":`ocr-count-badge`,children:[e.ocr_pages_count,` `,e.ocr_pages_count===1?`page`:`pages`]})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`6px`},children:[(0,b.jsxs)(`button`,{type:`button`,className:`btn ${i===`pages`?`btn-primary`:`btn-secondary`}`,style:{padding:`4px 10px`,fontSize:`0.82rem`},onClick:()=>a(`pages`),"data-testid":`tab-pages-btn`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`,style:{marginRight:`5px`}}),` Page Text`]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn ${i===`chunks`?`btn-primary`:`btn-secondary`}`,style:{padding:`4px 10px`,fontSize:`0.82rem`},onClick:()=>a(`chunks`),"data-testid":`tab-chunks-btn`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-layer-group`,style:{marginRight:`5px`}}),` Sample Chunks (`,e.sample_chunks?.length||0,`)`]})]})]}),(0,b.jsx)(`div`,{style:{flex:1,overflowY:`auto`,minHeight:`320px`,display:`flex`,flexDirection:`column`},children:i===`pages`?(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,height:`100%`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,flexWrap:`wrap`,gap:`8px`,marginBottom:`10px`,padding:`6px 10px`,background:`rgba(0, 0, 0, 0.2)`,borderRadius:`6px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`3px 8px`,fontSize:`0.8rem`},onClick:()=>{o>0&&s(e=>e-1)},disabled:o<=0,"aria-label":`Previous Page`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-chevron-left`}),` Prev`]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`span`,{children:`Page`}),(0,b.jsx)(`select`,{value:o,onChange:t=>{let n=parseInt(t.target.value,10);!isNaN(n)&&n>=0&&n(0,b.jsxs)(`option`,{value:t,children:[e.page_number,` `,e.ocr_applied?`(OCR)`:``]},e.page_number))}),(0,b.jsxs)(`span`,{children:[`of `,c]})]}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`3px 8px`,fontSize:`0.8rem`},onClick:()=>{oe+1)},disabled:o>=e.pages.length-1,"aria-label":`Next Page`,children:[`Next `,(0,b.jsx)(`i`,{className:`fa-solid fa-chevron-right`})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[l.ocr_applied?(0,b.jsxs)(`span`,{className:`badge badge-warning`,style:{display:`inline-flex`,alignItems:`center`,gap:`4px`},"data-testid":`page-ocr-applied-badge`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-eye`}),` OCR Fallback`]}):(0,b.jsxs)(`span`,{className:`badge badge-secondary`,style:{display:`inline-flex`,alignItems:`center`,gap:`4px`},"data-testid":`page-digital-badge`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-font`}),` Digital`]}),(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:[l.char_count.toLocaleString(),` chars`]})]})]}),(0,b.jsx)(`div`,{style:{flex:1,minHeight:`260px`,position:`relative`},children:l.text?(0,b.jsx)(`pre`,{className:`search-hit-code`,style:{maxHeight:`400px`,overflowY:`auto`,margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,fontSize:`0.85rem`,lineHeight:`1.5`,padding:`12px`,background:`rgba(0, 0, 0, 0.3)`,borderRadius:`6px`},"data-testid":`page-text-content`,children:l.text}):(0,b.jsxs)(`div`,{className:`empty-state`,style:{padding:`30px`,textAlign:`center`,color:`var(--text-muted)`},"data-testid":`page-empty-text`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-circle-question`,style:{fontSize:`1.5rem`,marginBottom:`8px`,display:`block`}}),`No text extracted from Page `,l.page_number,`.`]})})]}):(0,b.jsxs)(`div`,{style:{display:`flex`,flexDirection:`column`,gap:`10px`},"data-testid":`chunks-container`,children:[(0,b.jsx)(`div`,{style:{fontSize:`0.82rem`,color:`var(--text-muted)`,marginBottom:`4px`},children:`Simulated chunking for vector ingestion (approx. 1000 chars / chunk with 200 char overlap):`}),!e.sample_chunks||e.sample_chunks.length===0?(0,b.jsx)(`div`,{className:`empty-state`,style:{padding:`24px`},children:`No vector chunks generated for this document.`}):e.sample_chunks.map(e=>(0,b.jsxs)(`div`,{style:{border:`1px solid var(--border-card)`,borderRadius:`6px`,background:`rgba(0, 0, 0, 0.25)`,padding:`10px 12px`},"data-testid":`chunk-card-${e.chunk_index}`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,fontSize:`0.8rem`,marginBottom:`6px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,alignItems:`center`},children:[(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[`Chunk #`,e.chunk_index+1]}),(0,b.jsxs)(`span`,{className:`text-muted`,children:[e.heading,` (Page `,e.page_number,`)`]})]}),(0,b.jsxs)(`span`,{className:`badge badge-secondary`,children:[e.char_count,` chars`]})]}),(0,b.jsx)(`pre`,{style:{margin:0,whiteSpace:`pre-wrap`,wordBreak:`break-word`,fontFamily:`var(--font-family-mono)`,fontSize:`0.8rem`,color:`var(--text)`,lineHeight:`1.4`,background:`rgba(0, 0, 0, 0.2)`,padding:`8px`,borderRadius:`4px`},children:e.preview})]},e.chunk_index))]})}),(0,b.jsxs)(`div`,{className:`modal-footer`,style:{marginTop:`16px`,paddingTop:`12px`,borderTop:`1px solid var(--border-card)`,display:`flex`,justifyContent:`flex-end`,gap:`10px`},children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:n,disabled:r,children:`Cancel`}),(0,b.jsxs)(`button`,{type:`button`,className:`btn btn-primary`,onClick:t,disabled:r,"data-testid":`confirm-ingest-btn`,children:[(0,b.jsx)(`i`,{className:`fa-solid ${r?`fa-spinner fa-spin`:`fa-database`}`,style:{marginRight:`6px`}}),r?`Ingesting...`:`Confirm & Ingest to Vector DB`]})]})]})})}function Se({refreshStats:e}){let t=S(),[n,r]=(0,_.useState)(null),[i,a]=(0,_.useState)(``),[o,s]=(0,_.useState)(!1),[c,l]=(0,_.useState)(!1),[u,d]=(0,_.useState)(``),[f,p]=(0,_.useState)(``),[m,h]=(0,_.useState)(`local_storage`),[g,v]=(0,_.useState)(``),[y,x]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),[T,E]=(0,_.useState)(!1),[D,O]=(0,_.useState)(!1),[k,ee]=(0,_.useState)(null),[A,te]=(0,_.useState)(!1),[ne,re]=(0,_.useState)(!1),[ie,j]=(0,_.useState)(null),[M,N]=(0,_.useState)(``),[ae,oe]=(0,_.useState)(``),[se,P]=(0,_.useState)(!1),[F,ce]=(0,_.useState)(!1),[le,ue]=(0,_.useState)(!1),[de,fe]=(0,_.useState)(null),[pe,me]=(0,_.useState)(null),[he,ge]=(0,_.useState)(``),[_e,ve]=(0,_.useState)(`local_storage`),[ye,be]=(0,_.useState)(``),[Se,Ce]=(0,_.useState)(!1),we=e=>{if(!e||e===0)return`0 B`;let t=1024,n=[`B`,`KB`,`MB`,`GB`],r=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/t**r).toFixed(1))+` `+n[r]},Te=e=>{if(!e)return`-`;let t=e<1e11?e*1e3:e;return new Date(t).toLocaleString()},Ee=(0,_.useCallback)(async(e=i)=>{s(!0);try{let t=e?`/admin/api/storage/tree?folder=${encodeURIComponent(e)}`:`/admin/api/storage/tree`,n=await fetch(t);if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error||`Failed to load storage tree`)}let i=await n.json();r(i),a(i.current_folder||``)}catch(e){t.error(`Error loading storage: `+e.message),console.error(`Error loading storage tree:`,e)}finally{s(!1)}},[i,t]);(0,_.useEffect)(()=>{Ee(``)},[]);let De=e=>{Ee(e)},I=()=>{if(!i)return;let e=i.split(`/`).filter(Boolean);e.pop(),De(e.join(`/`))},Oe=e=>{let t=e===void 0?i:e;d(t?`${t}/`:``),p(``),h(`local_storage`),v(``),x(null),l(!0)},ke=e=>{if(e.preventDefault(),w(!1),e.dataTransfer.files&&e.dataTransfer.files.length>0){let t=e.dataTransfer.files[0];Pe(t)}},Ae=e=>{e.target.files&&e.target.files.length>0&&Pe(e.target.files[0])},je=async(e,n,r,a)=>{ue(!0);try{let t=new FormData;t.append(`file`,e),t.append(`ocr_fallback`,`true`);let o=await fetch(`/admin/api/storage/pdf/preview`,{method:`POST`,body:t}),s=await o.json();if(!o.ok)throw Error(s.error||`Failed to generate PDF preview`);me(e),ge(n||(i?`${i}/${e.name}`:e.name)),ve(r||m||`local_storage`),be(a||f||``),fe(s),l(!1),ce(!0)}catch(e){t.error(`PDF preview error: ${e.message}`)}finally{ue(!1)}},Me=async()=>{if(pe){Ce(!0);try{let n=new FormData;n.append(`file`,pe),n.append(`path`,he||pe.name),n.append(`repo`,_e||`local_storage`),ye&&n.append(`category`,ye);let r=await fetch(`/admin/api/storage/upload`,{method:`POST`,body:n}),a=await r.json();if(!r.ok)throw Error(a.error||`Failed to ingest PDF`);ce(!1),me(null),fe(null);let o=a.chunks_indexed??0;t.success(`PDF uploaded and indexed (${o} chunks)`),Ee(i),e&&e()}catch(e){t.error(`PDF ingestion error: ${e.message}`)}finally{Ce(!1)}}},Ne=()=>{ce(!1),me(null),fe(null)},Pe=e=>{x(e);let t=i?`${i}/${e.name}`:e.name;if(d(t),e.name.toLowerCase().endsWith(`.pdf`)||e.type===`application/pdf`){v(``),je(e,t,m,f);return}let n=new FileReader;n.onload=e=>{typeof e.target?.result==`string`&&v(e.target.result)},n.readAsText(e)},Fe=async n=>{if(n.preventDefault(),!u.trim()){t.error(`File path is required`);return}if(y&&y.name.toLowerCase().endsWith(`.pdf`)){await je(y,u.trim(),m.trim(),f.trim());return}E(!0);try{let n;if(y&&!g){let e=new FormData;e.append(`file`,y),e.append(`path`,u.trim()),e.append(`repo`,m.trim()||`local_storage`),f.trim()&&e.append(`category`,f.trim()),n=await fetch(`/admin/api/storage/upload`,{method:`POST`,body:e})}else n=await fetch(`/admin/api/storage/upload`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:u.trim(),content:g,repo:m.trim()||`local_storage`,category:f.trim()||null})});let r=await n.json();if(!n.ok)throw Error(r.error||`Failed to upload file`);l(!1);let a=r.chunks_indexed??0;t.success(`File uploaded and indexed (${a} chunks)`),Ee(i),e&&e()}catch(e){t.error(`Upload error: ${e.message}`)}finally{E(!1)}},Ie=async e=>{te(!0),O(!0);try{let t=await fetch(`/admin/api/storage/file?path=${encodeURIComponent(e.rel_path)}`),n=await t.json();if(!t.ok)throw Error(n.error||`Failed to read file`);ee(n)}catch(e){t.error(`Preview error: ${e.message}`),O(!1)}finally{te(!1)}},Le=async e=>{if(j(e),oe(``),re(!0),e.rel_path.toLowerCase().endsWith(`.pdf`)){N(``);return}try{let t=await fetch(`/admin/api/storage/file?path=${encodeURIComponent(e.rel_path)}`),n=await t.json();t.ok&&n.content!==void 0?N(n.content):N(``)}catch{N(``)}},Re=async n=>{if(n.preventDefault(),ie){if(ie.rel_path.toLowerCase().endsWith(`.pdf`)){t.error(`PDF files cannot be edited directly via text editor. Upload a new PDF file instead.`);return}P(!0);try{let n=await fetch(`/admin/api/storage/file`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:ie.rel_path,content:M,repo:`local_storage`,category:ae.trim()||``})}),r=await n.json();if(!n.ok)throw Error(r.error||`Failed to update file`);re(!1);let a=r.chunks_indexed??0;t.success(`File updated and indexed (${a} chunks)`),Ee(i),e&&e()}catch(e){t.error(`Replace error: ${e.message}`)}finally{P(!1)}}},ze=async n=>{if(window.confirm(`Are you sure you want to delete '${n.name}' from local storage and purge its vector embeddings?`))try{let r=await fetch(`/admin/api/storage/file?path=${encodeURIComponent(n.rel_path)}`,{method:`DELETE`}),a=await r.json();if(!r.ok)throw Error(a.error||`Failed to delete file`);t.success(`File deleted successfully: ${n.name}`),Ee(i),e&&e()}catch(e){t.error(`Delete error: ${e.message}`)}},Be=i?i.split(`/`).filter(Boolean):[];return(0,b.jsxs)(`div`,{className:`tab-content active`,children:[(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`}),` Local Storage Explorer`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Upload, browse, inspect, replace, and delete managed documents in ContextCortex local storage with real-time vector indexing.`})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`10px`},children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>Ee(i),title:`Refresh directory`,disabled:o,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate ${o?`fa-spin`:``}`}),` Refresh`]}),(0,b.jsxs)(`button`,{className:`btn btn-primary`,onClick:()=>Oe(),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-upload`}),` Upload File`]})]})]}),(0,b.jsxs)(`div`,{className:`browser-breadcrumbs`,style:{display:`flex`,alignItems:`center`,justifyContent:`space-between`,flexWrap:`wrap`,gap:`10px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`6px`,flexWrap:`wrap`},children:[(0,b.jsx)(`span`,{className:`label`,style:{fontWeight:600},children:`Location:`}),(0,b.jsxs)(`button`,{className:`btn-icon`,style:{padding:`2px 6px`,fontSize:`0.85rem`,color:i===``?`var(--primary)`:`var(--text)`},onClick:()=>De(``),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-house`}),` root`]}),Be.map((e,t)=>{let n=Be.slice(0,t+1).join(`/`),r=t===Be.length-1;return(0,b.jsxs)(`span`,{style:{display:`inline-flex`,alignItems:`center`,gap:`6px`},children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`/`}),(0,b.jsx)(`button`,{className:`btn-icon`,style:{padding:`2px 6px`,fontSize:`0.85rem`,fontWeight:r?`bold`:`normal`,color:r?`var(--primary)`:`var(--text)`},onClick:()=>De(n),children:e})]},n)})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`8px`,fontSize:`0.8rem`,color:`var(--text-muted)`},children:[(0,b.jsxs)(`span`,{children:[`Directories: `,(0,b.jsx)(`strong`,{children:n?.directories.length||0})]}),(0,b.jsx)(`span`,{children:`•`}),(0,b.jsxs)(`span`,{children:[`Files: `,(0,b.jsx)(`strong`,{children:n?.files.length||0})]})]})]}),i!==``&&(0,b.jsx)(`div`,{style:{marginTop:`8px`,marginBottom:`8px`},children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`4px 10px`,fontSize:`0.82rem`},onClick:I,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-level-up-alt`}),` .. (Parent Directory)`]})}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{style:{width:`40%`},children:`Name`}),(0,b.jsx)(`th`,{children:`Path`}),(0,b.jsx)(`th`,{children:`Size`}),(0,b.jsx)(`th`,{children:`Modified`}),(0,b.jsx)(`th`,{style:{textAlign:`right`},children:`Actions`})]})}),(0,b.jsx)(`tbody`,{children:!n||n.directories.length===0&&n.files.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:5,className:`empty-state`,children:`No files or subdirectories found in this storage directory. Click "Upload File" to add documents.`})}):(0,b.jsxs)(b.Fragment,{children:[n.directories.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsxs)(`button`,{className:`btn-icon`,style:{display:`inline-flex`,alignItems:`center`,gap:`8px`,textAlign:`left`,color:`var(--text)`},onClick:()=>De(e.rel_path),"aria-label":`open ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder`,style:{color:`#fbbf24`,fontSize:`1.05rem`}}),(0,b.jsx)(`strong`,{children:e.name})]})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.rel_path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{style:{textAlign:`right`},children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,style:{padding:`3px 8px`,fontSize:`0.8rem`},onClick:()=>De(e.rel_path),title:`Open ${e.name}`,"aria-label":`open ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-open`}),` Open`]})})]},e.rel_path)),n.files.map(e=>{let t=e.name.toLowerCase().endsWith(`.pdf`);return(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[t?(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf text-red-500 mr-2`,style:{color:`#ef4444`,fontSize:`1.05rem`}}):(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`,style:{color:`var(--primary)`,fontSize:`1.05rem`}}),(0,b.jsx)(`span`,{children:e.name})]})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.rel_path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:we(e.size_bytes)})}),(0,b.jsx)(`td`,{style:{fontSize:`0.85rem`},children:Te(e.mtime)}),(0,b.jsx)(`td`,{style:{textAlign:`right`},children:(0,b.jsxs)(`div`,{style:{display:`inline-flex`,gap:`6px`},children:[(0,b.jsx)(`button`,{className:`btn-icon`,onClick:()=>Ie(e),title:`Preview File`,"aria-label":`Preview File`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-eye`})}),(0,b.jsx)(`button`,{className:`btn-icon`,onClick:()=>Le(e),title:`Replace File`,"aria-label":`Replace File`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-file-pen`})}),(0,b.jsx)(`button`,{className:`btn-icon btn-delete`,onClick:()=>ze(e),title:`Delete File`,"aria-label":`Delete File`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`})})]})})]},e.rel_path)})]})})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:!n||n.directories.length===0&&n.files.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No files or subdirectories found.`}):(0,b.jsxs)(b.Fragment,{children:[n.directories.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder`,style:{color:`#fbbf24`}}),(0,b.jsx)(`strong`,{children:e.name})]}),(0,b.jsx)(`span`,{className:`badge badge-warning`,children:`Directory`})]}),(0,b.jsx)(`div`,{className:`data-mobile-card-body`,children:(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{children:e.rel_path})]})}),(0,b.jsx)(`div`,{className:`data-mobile-card-actions`,children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>De(e.rel_path),"aria-label":`open ${e.name}`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-open`}),` Open Folder`]})})]},`m-${e.rel_path}`)),n.files.map(e=>{let t=e.name.toLowerCase().endsWith(`.pdf`);return(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:`8px`},children:[t?(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf text-red-500 mr-2`,style:{color:`#ef4444`}}):(0,b.jsx)(`i`,{className:`fa-solid fa-file-lines`,style:{color:`var(--primary)`}}),(0,b.jsx)(`strong`,{children:e.name})]}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:we(e.size_bytes)})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{children:e.rel_path})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Modified: `}),(0,b.jsx)(`span`,{children:Te(e.mtime)})]})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-actions`,children:[(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>Ie(e),title:`Preview File`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-eye`}),` Preview`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>Le(e),title:`Replace File`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pen`}),` Replace`]}),(0,b.jsxs)(`button`,{className:`btn btn-secondary btn-delete`,onClick:()=>ze(e),title:`Delete File`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-trash-can`}),` Delete`]})]})]},`m-${e.rel_path}`)})]})})]}),c&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`640px`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-cloud-arrow-up`}),` Upload to Local Storage`]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>l(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:Fe,children:[(0,b.jsxs)(`div`,{style:{border:C?`2px dashed var(--primary)`:`2px dashed rgba(255, 255, 255, 0.15)`,borderRadius:`8px`,padding:`20px`,textAlign:`center`,background:C?`rgba(59, 130, 246, 0.08)`:`rgba(0, 0, 0, 0.15)`,marginBottom:`16px`,cursor:`pointer`,transition:`all 0.2s ease`},onDragOver:e=>{e.preventDefault(),w(!0)},onDragLeave:()=>w(!1),onDrop:ke,onClick:()=>document.getElementById(`storage-file-input`)?.click(),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-arrow-up`,style:{fontSize:`2rem`,color:`var(--primary)`,marginBottom:`8px`}}),(0,b.jsx)(`p`,{style:{margin:`4px 0`,fontSize:`0.9rem`},children:y?`Selected: ${y.name} (${we(y.size)})`:`Drag & drop a file here, or click to browse`}),(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.75rem`},children:`Supports Markdown, code, JSON, YAML, plain text, PDF (up to 50MB)`}),le&&(0,b.jsxs)(`div`,{style:{marginTop:`8px`,fontSize:`0.85rem`,color:`var(--primary)`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`,style:{marginRight:`6px`}}),`Extracting and analyzing PDF preview...`]}),(0,b.jsx)(`input`,{id:`storage-file-input`,type:`file`,accept:`.md,.markdown,.txt,.json,.yaml,.yml,.sql,.html,.css,.pdf`,style:{display:`none`},onChange:Ae})]}),(0,b.jsxs)(`div`,{className:`form-row`,children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:2},children:[(0,b.jsx)(`label`,{htmlFor:`upload-path`,children:`Relative File Path (e.g. docs/guide.md)`}),(0,b.jsx)(`input`,{id:`upload-path`,type:`text`,required:!0,placeholder:`folder/document.md`,value:u,onChange:e=>d(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{flex:1},children:[(0,b.jsx)(`label`,{htmlFor:`upload-category`,children:`Category Override`}),(0,b.jsx)(`input`,{id:`upload-category`,type:`text`,placeholder:`Optional category`,value:f,onChange:e=>p(e.target.value)})]})]}),y?.name.toLowerCase().endsWith(`.pdf`)||y?.type===`application/pdf`||u.trim().toLowerCase().endsWith(`.pdf`)?(0,b.jsxs)(`div`,{className:`alert alert-info`,style:{margin:`12px 0`,padding:`12px`,background:`rgba(59, 130, 246, 0.1)`,border:`1px solid var(--primary)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pdf`,style:{color:`#ef4444`,marginRight:`8px`}}),(0,b.jsx)(`strong`,{children:`PDF Document Selected:`}),` Binary PDF content cannot be edited manually as text. Extracted text, page segmentation, and vector chunks will be previewed in the extraction modal before ingestion.`]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`upload-content`,children:`File Content (Optional if file uploaded directly)`}),(0,b.jsx)(`textarea`,{id:`upload-content`,rows:8,placeholder:`# Enter or paste text content here...`,value:g,onChange:e=>v(e.target.value),style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`}})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>l(!1),children:`Cancel`}),(0,b.jsxs)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:T,children:[(0,b.jsx)(`i`,{className:`fa-solid ${T?`fa-spinner fa-spin`:`fa-upload`}`}),` Upload & Index`]})]})]})]})}),D&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`750px`,maxHeight:`90vh`,display:`flex`,flexDirection:`column`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`}),` File Preview: `,k?.rel_path||`Loading...`]}),k&&(0,b.jsxs)(`span`,{className:`text-muted`,style:{fontSize:`0.8rem`},children:[`Size: `,we(k.size_bytes),` • Modified: `,Te(k.mtime)]})]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>O(!1),children:`×`})]}),(0,b.jsx)(`div`,{style:{flex:1,overflowY:`auto`,margin:`10px 0`},children:A?(0,b.jsxs)(`div`,{className:`empty-state`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-spinner fa-spin`}),` Loading content...`]}):(0,b.jsx)(`pre`,{className:`search-hit-code`,style:{maxHeight:`420px`,overflowY:`auto`,margin:0,whiteSpace:`pre-wrap`},children:k?.content||`Empty file.`})}),(0,b.jsx)(`div`,{className:`modal-footer`,children:(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>O(!1),children:`Close`})})]})}),ne&&ie&&(0,b.jsx)(`div`,{className:`modal-backdrop`,children:(0,b.jsxs)(`div`,{className:`glass-card modal-card`,style:{maxWidth:`680px`},children:[(0,b.jsxs)(`div`,{className:`modal-header`,children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-pen`}),` Replace File: `,ie.name]}),(0,b.jsx)(`button`,{className:`btn-close`,onClick:()=>re(!1),children:`×`})]}),(0,b.jsxs)(`form`,{onSubmit:Re,children:[(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{children:`Target File Path`}),(0,b.jsx)(`input`,{type:`text`,readOnly:!0,value:ie.rel_path})]}),(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`replace-category`,children:`Category Override`}),(0,b.jsx)(`input`,{id:`replace-category`,type:`text`,placeholder:`Optional category`,value:ae,onChange:e=>oe(e.target.value)})]}),ie.rel_path.toLowerCase().endsWith(`.pdf`)?(0,b.jsxs)(`div`,{className:`alert alert-warning`,style:{margin:`14px 0`,padding:`12px`,background:`rgba(245, 158, 11, 0.1)`,border:`1px solid rgba(245, 158, 11, 0.3)`,borderRadius:`6px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-triangle-exclamation`,style:{marginRight:`8px`,color:`#f59e0b`}}),(0,b.jsx)(`strong`,{children:`PDF Replacement:`}),` PDF documents contain binary page streams and cannot be edited as plain text. To replace this document, please upload a new `,(0,b.jsx)(`code`,{children:`.pdf`}),` file using the "Upload File" tool.`]}):(0,b.jsxs)(`div`,{className:`form-group`,children:[(0,b.jsx)(`label`,{htmlFor:`replace-content`,children:`File Content`}),(0,b.jsx)(`textarea`,{id:`replace-content`,rows:10,required:!0,placeholder:`Updated file text...`,value:M,onChange:e=>N(e.target.value),style:{fontFamily:`var(--font-family-mono)`,fontSize:`0.85rem`}})]}),(0,b.jsxs)(`div`,{className:`modal-footer`,children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,onClick:()=>re(!1),children:`Cancel`}),(0,b.jsxs)(`button`,{type:`submit`,className:`btn btn-primary`,disabled:se||ie.rel_path.toLowerCase().endsWith(`.pdf`),children:[(0,b.jsx)(`i`,{className:`fa-solid ${se?`fa-spinner fa-spin`:`fa-save`}`}),` Save & Re-Index`]})]})]})]})}),F&&de&&(0,b.jsx)(xe,{data:de,onConfirm:Me,onCancel:Ne,isIngesting:Se})]})}function Ce(){let e=S(),[t,n]=(0,_.useState)(null),[r,i]=(0,_.useState)(!1),[a,o]=(0,_.useState)(`all`),[s,c]=(0,_.useState)(`summary`),[l,u]=(0,_.useState)(``),[d,f]=(0,_.useState)(``),[p,m]=(0,_.useState)(``),[h,g]=(0,_.useState)(``),v=(0,_.useCallback)(async(t=a,r=s,o=l,c=d,u=p)=>{i(!0);try{let e=new URLSearchParams;e.set(`source_type`,t),e.set(`detail_level`,r),o.trim()&&e.set(`repo_name`,o.trim()),c.trim()&&e.set(`path_prefix`,c.trim()),u.trim()&&e.set(`file_extension`,u.trim());let i=await fetch(`/admin/api/ingestion/catalog?${e.toString()}`);if(!i.ok){let e=await i.json().catch(()=>({}));throw Error(e.error||`Failed to load ingestion catalog`)}let a=await i.json();n(a)}catch(t){e.error(`Error loading catalog: `+t.message),console.error(`Error loading ingestion catalog:`,t)}finally{i(!1)}},[a,s,l,d,p,e]);(0,_.useEffect)(()=>{v(a,s,l,d,p)},[a,s]);let y=e=>{e&&e.preventDefault(),v(a,s,l,d,p)},x=()=>{u(``),f(``),m(``),g(``),v(a,s,``,``,``)},C=e=>{o(e)},w=e=>{c(e)},T=e=>{if(!e)return`-`;if(typeof e==`string`)try{return new Date(e).toLocaleString()}catch{return e}let t=e<1e11?e*1e3:e;return new Date(t).toLocaleString()},E=t?.git_repositories||[],D=t?.monitored_paths||[],O=t?.local_storage,k=(t?.files||[]).filter(e=>{if(!h.trim())return!0;let t=h.toLowerCase();return e.filepath.toLowerCase().includes(t)||e.repo.toLowerCase().includes(t)||e.language&&e.language.toLowerCase().includes(t)}),ee=E.reduce((e,t)=>e+(t.file_count||0),0),A=D.reduce((e,t)=>e+(t.file_count||0),0),te=O?.file_count||0,ne=ee+A+te;return(0,b.jsx)(`div`,{className:`tab-content active`,children:(0,b.jsxs)(`div`,{className:`glass-card`,children:[(0,b.jsxs)(`div`,{className:`card-header-btn`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsxs)(`h2`,{children:[(0,b.jsx)(`i`,{className:`fa-solid fa-book-bookmark`}),` Unified Ingestion Catalog`]}),(0,b.jsx)(`p`,{className:`text-muted`,style:{marginTop:`4px`,fontSize:`0.85rem`},children:`Inspect all indexed Git repositories, monitored local workspaces, and uploaded local storage documents.`})]}),(0,b.jsx)(`div`,{style:{display:`flex`,gap:`10px`},children:(0,b.jsxs)(`button`,{className:`btn btn-secondary`,onClick:()=>y(),disabled:r,title:`Refresh catalog`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-arrows-rotate ${r?`fa-spin`:``}`}),` Refresh`]})})]}),(0,b.jsxs)(`div`,{className:`stats-grid`,style:{marginBottom:`20px`},children:[(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-brands fa-github`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Git Repositories`}),(0,b.jsxs)(`span`,{className:`stat-value`,children:[E.length,` `,(0,b.jsxs)(`small`,{style:{fontSize:`0.75rem`,fontWeight:`normal`,color:`var(--text-muted)`},children:[`(`,ee,` files)`]})]})]})]}),(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Monitored Paths`}),(0,b.jsxs)(`span`,{className:`stat-value`,children:[D.length,` `,(0,b.jsxs)(`small`,{style:{fontSize:`0.75rem`,fontWeight:`normal`,color:`var(--text-muted)`},children:[`(`,A,` files)`]})]})]})]}),(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Local Storage`}),(0,b.jsxs)(`span`,{className:`stat-value`,children:[te,` `,(0,b.jsx)(`small`,{style:{fontSize:`0.75rem`,fontWeight:`normal`,color:`var(--text-muted)`},children:`files`})]})]})]}),(0,b.jsxs)(`div`,{className:`stat-card`,children:[(0,b.jsx)(`div`,{className:`stat-icon`,children:(0,b.jsx)(`i`,{className:`fa-solid fa-database`})}),(0,b.jsxs)(`div`,{className:`stat-info`,children:[(0,b.jsx)(`span`,{className:`stat-label`,children:`Total Cataloged Files`}),(0,b.jsx)(`span`,{className:`stat-value`,children:ne})]})]})]}),(0,b.jsxs)(`div`,{style:{background:`rgba(0, 0, 0, 0.2)`,padding:`16px`,borderRadius:`10px`,border:`1px solid var(--border-card)`,marginBottom:`20px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,flexWrap:`wrap`,gap:`12px`,marginBottom:`14px`},children:[(0,b.jsxs)(`div`,{className:`log-filter-pills`,role:`group`,"aria-label":`Source Type Filters`,children:[(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`all`?`active`:``}`,onClick:()=>C(`all`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-layer-group`}),` All Sources`]}),(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`git`?`active`:``}`,onClick:()=>C(`git`),children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`}),` Git Repositories`]}),(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`monitored_path`?`active`:``}`,onClick:()=>C(`monitored_path`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`}),` Monitored Paths`]}),(0,b.jsxs)(`button`,{className:`log-filter-btn ${a===`local_storage`?`active`:``}`,onClick:()=>C(`local_storage`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`}),` Local Storage`]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`6px`},role:`group`,"aria-label":`Detail Level Switch`,children:[(0,b.jsxs)(`button`,{className:`btn ${s===`summary`?`btn-primary`:`btn-secondary`}`,style:{padding:`5px 12px`,fontSize:`0.8rem`},onClick:()=>w(`summary`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-list`}),` Summary`]}),(0,b.jsxs)(`button`,{className:`btn ${s===`detailed`?`btn-primary`:`btn-secondary`}`,style:{padding:`5px 12px`,fontSize:`0.8rem`},onClick:()=>w(`detailed`),children:[(0,b.jsx)(`i`,{className:`fa-solid fa-network-wired`}),` Detailed File Tree`]})]})]}),(0,b.jsxs)(`form`,{onSubmit:y,children:[(0,b.jsxs)(`div`,{className:`form-row-3col`,style:{alignItems:`flex-end`},children:[(0,b.jsxs)(`div`,{className:`form-group`,style:{margin:0},children:[(0,b.jsx)(`label`,{htmlFor:`catalog-repo-filter`,style:{fontSize:`0.8rem`},children:`Repository / Alias`}),(0,b.jsx)(`input`,{id:`catalog-repo-filter`,type:`text`,placeholder:`Filter by repo name...`,value:l,onChange:e=>u(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{margin:0},children:[(0,b.jsx)(`label`,{htmlFor:`catalog-prefix-filter`,style:{fontSize:`0.8rem`},children:`Path Prefix`}),(0,b.jsx)(`input`,{id:`catalog-prefix-filter`,type:`text`,placeholder:`e.g. app/api or docs/`,value:d,onChange:e=>f(e.target.value)})]}),(0,b.jsxs)(`div`,{className:`form-group`,style:{margin:0},children:[(0,b.jsx)(`label`,{htmlFor:`catalog-ext-filter`,style:{fontSize:`0.8rem`},children:`File Extension`}),(0,b.jsx)(`input`,{id:`catalog-ext-filter`,type:`text`,placeholder:`e.g. .md, .py, .ts`,value:p,onChange:e=>m(e.target.value)})]})]}),(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`flex-end`,gap:`8px`,marginTop:`12px`},children:[(0,b.jsx)(`button`,{type:`button`,className:`btn btn-secondary`,style:{padding:`6px 12px`,fontSize:`0.85rem`},onClick:x,children:`Clear`}),(0,b.jsxs)(`button`,{type:`submit`,className:`btn btn-primary`,style:{padding:`6px 14px`,fontSize:`0.85rem`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-filter`}),` Apply`]})]})]})]}),(a===`all`||a===`git`)&&(0,b.jsxs)(`div`,{style:{marginBottom:`28px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,marginBottom:`10px`,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`,style:{color:`var(--primary)`}}),` Git Repositories`,(0,b.jsx)(`span`,{className:`badge badge-primary`,children:E.length})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Name`}),(0,b.jsx)(`th`,{children:`Branch / Commit`}),(0,b.jsx)(`th`,{children:`Status`}),(0,b.jsx)(`th`,{children:`Files`}),(0,b.jsx)(`th`,{children:`Provider`}),(0,b.jsx)(`th`,{children:`URL`})]})}),(0,b.jsx)(`tbody`,{children:E.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:6,className:`empty-state`,children:`No Git repositories match criteria.`})}):E.map(e=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.name})}),(0,b.jsxs)(`td`,{children:[(0,b.jsx)(`code`,{children:e.branch}),e.commit_sha&&(0,b.jsxs)(`span`,{className:`text-muted`,style:{marginLeft:`6px`,fontSize:`0.8rem`},children:[`@`,e.commit_sha.substring(0,7)]})]}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge ${e.status===`synced`?`badge-success`:e.status===`syncing`?`badge-warning`:`badge-danger`}`,children:e.status})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.file_count??0})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.provider||`git`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.82rem`,wordBreak:`break-all`},children:e.url})})]},e.id))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:E.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No Git repositories match criteria.`}):E.map(e=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`strong`,{children:e.name}),(0,b.jsx)(`span`,{className:`badge ${e.status===`synced`?`badge-success`:`badge-warning`}`,children:e.status})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Branch: `}),(0,b.jsx)(`code`,{children:e.branch})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Files: `}),(0,b.jsx)(`strong`,{children:e.file_count??0})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`URL: `}),(0,b.jsx)(`span`,{style:{wordBreak:`break-all`},children:e.url})]})]})]},`gm-${e.id}`))})]}),(a===`all`||a===`monitored_path`)&&(0,b.jsxs)(`div`,{style:{marginBottom:`28px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,marginBottom:`10px`,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`,style:{color:`#fbbf24`}}),` Monitored Local Paths`,(0,b.jsx)(`span`,{className:`badge badge-primary`,children:D.length})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Path`}),(0,b.jsx)(`th`,{children:`Repo Alias`}),(0,b.jsx)(`th`,{children:`Category`}),(0,b.jsx)(`th`,{children:`Files Indexed`})]})}),(0,b.jsx)(`tbody`,{children:D.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:4,className:`empty-state`,children:`No monitored paths match criteria.`})}):D.map((e,t)=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{children:e.path})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.repo})}),(0,b.jsx)(`td`,{children:e.category?(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category}):(0,b.jsx)(`span`,{className:`text-muted`,children:`-`})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.file_count??0})})]},`${e.path}-${t}`))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:D.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No monitored paths match criteria.`}):D.map((e,t)=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`strong`,{children:e.repo}),(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[e.file_count??0,` files`]})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{children:e.path})]}),e.category&&(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Category: `}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.category})]})]})]},`mpm-${t}`))})]}),(a===`all`||a===`local_storage`)&&O&&(0,b.jsxs)(`div`,{style:{marginBottom:`28px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,marginBottom:`10px`,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`,style:{color:`var(--accent)`}}),` Local Storage`,(0,b.jsxs)(`span`,{className:`badge badge-primary`,children:[O.file_count,` files`]})]}),(0,b.jsxs)(`div`,{style:{background:`rgba(255, 255, 255, 0.02)`,padding:`16px`,borderRadius:`8px`,border:`1px solid var(--border-card)`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,gap:`20px`,flexWrap:`wrap`,marginBottom:`12px`},children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.85rem`},children:`Storage Root: `}),(0,b.jsx)(`code`,{children:O.root_path})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,style:{fontSize:`0.85rem`},children:`Total Files: `}),(0,b.jsx)(`strong`,{children:O.file_count})]})]}),O.tree&&(0,b.jsxs)(`div`,{style:{fontSize:`0.85rem`,color:`var(--text-muted)`},children:[`Top-level Subfolders: `,(0,b.jsx)(`strong`,{children:O.tree.directories?.length||0}),` • Top-level Files: `,(0,b.jsx)(`strong`,{children:O.tree.files?.length||0})]})]})]}),s===`detailed`&&(0,b.jsxs)(`div`,{style:{marginTop:`20px`},children:[(0,b.jsxs)(`div`,{style:{display:`flex`,justifyContent:`space-between`,alignItems:`center`,flexWrap:`wrap`,gap:`10px`,marginBottom:`12px`},children:[(0,b.jsxs)(`h3`,{style:{fontSize:`1.05rem`,margin:0,display:`flex`,alignItems:`center`,gap:`8px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-file-code`,style:{color:`var(--primary)`}}),` Ingested Files Details`,(0,b.jsx)(`span`,{className:`badge badge-primary`,children:k.length})]}),(0,b.jsxs)(`div`,{className:`log-search-wrapper`,style:{maxWidth:`320px`},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass search-icon`}),(0,b.jsx)(`input`,{type:`text`,className:`log-search-input`,placeholder:`Search in loaded files...`,value:h,onChange:e=>g(e.target.value)}),h&&(0,b.jsx)(`button`,{className:`clear-search-btn`,onClick:()=>g(``),children:`×`})]})]}),(0,b.jsx)(`div`,{className:`table-container desktop-table-view`,children:(0,b.jsxs)(`table`,{children:[(0,b.jsx)(`thead`,{children:(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`th`,{children:`Filepath`}),(0,b.jsx)(`th`,{children:`Repository`}),(0,b.jsx)(`th`,{children:`Type`}),(0,b.jsx)(`th`,{children:`Language`}),(0,b.jsx)(`th`,{children:`Last Modified`})]})}),(0,b.jsx)(`tbody`,{children:k.length===0?(0,b.jsx)(`tr`,{children:(0,b.jsx)(`td`,{colSpan:5,className:`empty-state`,children:`No detailed files match current search or filters.`})}):k.map((e,t)=>(0,b.jsxs)(`tr`,{children:[(0,b.jsx)(`td`,{children:(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.filepath})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`strong`,{children:e.repo})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.doc_type})}),(0,b.jsx)(`td`,{children:(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.language||`text`})}),(0,b.jsx)(`td`,{style:{fontSize:`0.85rem`},children:T(e.mtime)})]},`${e.filepath}-${t}`))})]})}),(0,b.jsx)(`div`,{className:`mobile-card-list`,children:k.length===0?(0,b.jsx)(`div`,{className:`empty-state`,children:`No detailed files match current search or filters.`}):k.map((e,t)=>(0,b.jsxs)(`div`,{className:`data-mobile-card`,children:[(0,b.jsxs)(`div`,{className:`data-mobile-card-header`,children:[(0,b.jsx)(`strong`,{children:e.repo}),(0,b.jsx)(`span`,{className:`badge badge-accent`,children:e.language||`text`})]}),(0,b.jsxs)(`div`,{className:`data-mobile-card-body`,children:[(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Path: `}),(0,b.jsx)(`code`,{style:{wordBreak:`break-all`},children:e.filepath})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Type: `}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:e.doc_type})]}),(0,b.jsxs)(`div`,{children:[(0,b.jsx)(`span`,{className:`text-muted`,children:`Modified: `}),(0,b.jsx)(`span`,{children:T(e.mtime)})]})]})]},`dfm-${t}`))})]})]})})}function we(){let[e,t]=(0,_.useState)(`overview`),[n,r]=(0,_.useState)(!1),[i,a]=(0,_.useState)(null),o=async()=>{try{let e=await fetch(`/admin/api/stats`);if(!e.ok)return;let t=await e.json();a(t)}catch(e){console.error(`Error loading stats:`,e)}};return(0,_.useEffect)(()=>{o();let e=setInterval(o,8e3);return()=>clearInterval(e)},[]),(0,b.jsx)(b.Fragment,{children:(0,b.jsxs)(`div`,{className:`dashboard-container`,children:[(0,b.jsxs)(`header`,{className:`dashboard-header`,children:[(0,b.jsxs)(`div`,{className:`header-top-row`,children:[(0,b.jsxs)(`div`,{className:`header-logo`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-layer-group logo-icon`}),(0,b.jsxs)(`div`,{className:`header-title`,children:[(0,b.jsx)(`h1`,{children:`ContextCortex`}),(0,b.jsx)(`span`,{className:`badge badge-primary`,children:`v2.15.0`})]})]}),(0,b.jsx)(`button`,{className:`menu-toggle-btn`,"aria-label":`Toggle navigation`,onClick:()=>r(!n),children:(0,b.jsx)(`i`,{className:`fa-solid ${n?`fa-xmark`:`fa-bars`}`})})]}),(0,b.jsxs)(`div`,{className:`header-status`,children:[(0,b.jsxs)(`div`,{className:`status-item`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Engine State`}),(0,b.jsx)(`span`,{className:`value`,children:i?.is_indexing?(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`span`,{className:`indicator indexing`}),` Syncing...`]}):(0,b.jsxs)(b.Fragment,{children:[(0,b.jsx)(`span`,{className:`indicator online`}),` Idle`]})})]}),(0,b.jsxs)(`div`,{className:`status-item`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Vector Backend`}),(0,b.jsxs)(`span`,{className:`value`,children:[(0,b.jsx)(`i`,{className:`fa-solid fa-database`,style:{marginRight:`5px`}}),(0,b.jsxs)(`span`,{children:[i?.vector_store_provider===`chroma`?`ChromaDB`:`Qdrant`,` (`,(i?.vector_store_mode||`embedded`)===`embedded`?`Embedded`:`Remote`,`)`]}),i?.vector_db_status&&(0,b.jsx)(`span`,{className:`badge ${i.vector_db_status===`Healthy`?`badge-success`:`badge-danger`}`,style:{marginLeft:`6px`,fontSize:`0.75rem`,padding:`2px 6px`},"data-testid":`vector-db-status-badge`,children:i.vector_db_status})]})]}),(0,b.jsxs)(`div`,{className:`status-item`,children:[(0,b.jsx)(`span`,{className:`label`,children:`Collection`}),(0,b.jsx)(`span`,{className:`value code`,children:i?.vector_store_collection||`knowledge_rag_v1`})]})]})]}),(0,b.jsxs)(`nav`,{className:`dashboard-nav ${n?`drawer-open`:``}`,children:[(0,b.jsxs)(`button`,{className:`nav-tab ${e===`overview`?`active`:``}`,onClick:()=>{t(`overview`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-chart-pie`}),` Overview`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`navigator`||e===`topology`?`active`:``}`,onClick:()=>{t(`navigator`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-code-fork`}),` Navigator`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`git-repos`?`active`:``}`,onClick:()=>{t(`git-repos`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-brands fa-github`}),` Git Repositories`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`local-paths`?`active`:``}`,onClick:()=>{t(`local-paths`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-folder-tree`}),` Local Paths`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`local-storage`?`active`:``}`,onClick:()=>{t(`local-storage`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-hard-drive`}),` Local Storage`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`ingestion-catalog`?`active`:``}`,onClick:()=>{t(`ingestion-catalog`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-book-bookmark`}),` Ingestion Catalog`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`search-inspector`?`active`:``}`,onClick:()=>{t(`search-inspector`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-magnifying-glass`}),` Search & Inspector`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`settings`?`active`:``}`,onClick:()=>{t(`settings`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-gear`}),` Settings`]}),(0,b.jsxs)(`button`,{className:`nav-tab ${e===`diagnostics`?`active`:``}`,onClick:()=>{t(`diagnostics`),r(!1)},children:[(0,b.jsx)(`i`,{className:`fa-solid fa-terminal`}),` Diagnostics & Logs`]})]}),(0,b.jsxs)(`main`,{className:`dashboard-main`,children:[e===`overview`&&(0,b.jsx)(T,{stats:i,refreshStats:o}),(e===`navigator`||e===`topology`)&&(0,b.jsx)(be,{}),e===`git-repos`&&(0,b.jsx)(te,{refreshStats:o}),e===`local-paths`&&(0,b.jsx)(ne,{refreshStats:o}),e===`local-storage`&&(0,b.jsx)(Se,{refreshStats:o}),e===`ingestion-catalog`&&(0,b.jsx)(Ce,{}),e===`search-inspector`&&(0,b.jsx)(re,{}),e===`settings`&&(0,b.jsx)(ue,{stats:i,refreshStats:o}),e===`diagnostics`&&(0,b.jsx)(de,{})]}),(0,b.jsx)(`footer`,{className:`dashboard-footer`,children:(0,b.jsx)(`p`,{children:`ContextCortex MCP • Universal Code & Knowledge RAG • 2026`})})]})})}(0,v.createRoot)(document.getElementById(`root`)).render((0,b.jsx)(_.StrictMode,{children:(0,b.jsx)(w,{children:(0,b.jsx)(we,{})})})); \ No newline at end of file diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 81aff15..33c0d2d 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -17,7 +17,7 @@ } catch (e) {} })(); - + diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d290f98..9c68471 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "contextcortex-frontend", - "version": "2.14.0", + "version": "2.15.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "contextcortex-frontend", - "version": "2.14.0", + "version": "2.15.0", "dependencies": { "react": "^19.2.8", "react-dom": "^19.2.8" diff --git a/frontend/package.json b/frontend/package.json index 06657d4..d45b7ad 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "contextcortex-frontend", "private": true, - "version": "2.14.0", + "version": "2.15.0", "type": "module", "scripts": { "dev": "vite --configLoader native", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9388767..e7e1ce5 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -42,7 +42,7 @@ function App() {

ContextCortex

- v2.14.0 + v2.15.0
+ + + + )} + + ); +} diff --git a/frontend/src/tests/App.test.tsx b/frontend/src/tests/App.test.tsx index 1be8229..4dfb0d3 100644 --- a/frontend/src/tests/App.test.tsx +++ b/frontend/src/tests/App.test.tsx @@ -91,7 +91,7 @@ describe('App Component', () => { ); expect(screen.getByText('ContextCortex')).toBeInTheDocument(); - expect(screen.getByText('v2.14.0')).toBeInTheDocument(); + expect(screen.getByText('v2.15.0')).toBeInTheDocument(); await waitFor(() => { diff --git a/frontend/src/tests/FileSettings.test.tsx b/frontend/src/tests/FileSettings.test.tsx new file mode 100644 index 0000000..ca9df30 --- /dev/null +++ b/frontend/src/tests/FileSettings.test.tsx @@ -0,0 +1,101 @@ +import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { FileSettings } from '../components/settings/FileSettings'; +import { ToastProvider } from '../ToastContext'; + +describe('FileSettings Component', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it('renders settings fields and loads data from api', async () => { + vi.spyOn(globalThis, 'fetch').mockImplementation(((url: any) => { + if (url === '/admin/api/settings/files') { + return Promise.resolve({ + ok: true, + json: () => + Promise.resolve({ + summary_enabled: true, + summary_threshold_kb: 500, + summary_max_file_size_mb: 10, + read_file_max_lines: 2000, + summary_chat_model: 'gemini-2.5-flash', + }), + } as Response); + } + return Promise.reject(new Error('Unknown url')); + }) as any); + + render( + + + + ); + + expect(screen.getByText(/Loading settings.../i)).toBeInTheDocument(); + + await waitFor(() => { + expect(screen.getByText('Files & Large File Summarization')).toBeInTheDocument(); + }); + + const toggle = screen.getByLabelText(/Enable Large File Summarization/i); + expect(toggle).toBeChecked(); + + const thresholdInput = screen.getByLabelText(/Auto-Summarize Threshold/i); + expect(thresholdInput).toHaveValue(500); + + const maxLinesInput = screen.getByLabelText(/Max Lines Per Read/i); + expect(maxLinesInput).toHaveValue(2000); + }); + + it('submits updated settings when Save button is clicked', async () => { + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockImplementation(((url: any, opts?: any) => { + if (url === '/admin/api/settings/files' && (!opts || opts.method === undefined)) { + return Promise.resolve({ + ok: true, + json: () => + Promise.resolve({ + summary_enabled: true, + summary_threshold_kb: 500, + summary_max_file_size_mb: 10, + read_file_max_lines: 2000, + summary_chat_model: 'gemini-2.5-flash', + }), + } as Response); + } + if (url === '/admin/api/settings/files' && opts?.method === 'POST') { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(JSON.parse(opts.body as string)), + } as Response); + } + return Promise.reject(new Error('Unknown url')); + }) as any); + + render( + + + + ); + + await waitFor(() => { + expect(screen.getByText('Files & Large File Summarization')).toBeInTheDocument(); + }); + + const thresholdInput = screen.getByLabelText(/Auto-Summarize Threshold/i); + fireEvent.change(thresholdInput, { target: { value: '750' } }); + + const saveBtn = screen.getByRole('button', { name: /Save File Settings/i }); + fireEvent.click(saveBtn); + + await waitFor(() => { + expect(fetchSpy).toHaveBeenCalledWith( + '/admin/api/settings/files', + expect.objectContaining({ + method: 'POST', + body: expect.stringContaining('"summary_threshold_kb":750'), + }) + ); + }); + }); +}); diff --git a/frontend/src/tests/Settings.test.tsx b/frontend/src/tests/Settings.test.tsx index e9713e2..3b07f57 100644 --- a/frontend/src/tests/Settings.test.tsx +++ b/frontend/src/tests/Settings.test.tsx @@ -418,7 +418,7 @@ describe('Settings Component', () => { // 1. Save empty (guard branch) fireEvent.click(saveBtns[0]); - expect(globalThis.fetch).toHaveBeenCalledTimes(4); // Initial loads for hosts, vector store, auto-sync & embedding + expect(globalThis.fetch).toHaveBeenCalledTimes(5); // Initial loads for hosts, vector store, auto-sync, embedding & files // 2. Save GitHub token const ghInput = screen.getByPlaceholderText(/ghp_xxxx/i); diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 395cbb0..2cae291 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -402,3 +402,12 @@ export interface PdfPreviewData { sample_chunks: PdfChunkPreview[]; } +export interface FileSettings { + summary_enabled: boolean; + summary_threshold_kb: number; + summary_max_file_size_mb: number; + read_file_max_lines: number; + summary_chat_model: string; +} + + diff --git a/main.py b/main.py index c03cbf4..67fadef 100644 --- a/main.py +++ b/main.py @@ -179,7 +179,7 @@ async def __call__(self, scope, receive, send): }) -app = FastAPI(title="ContextCortex", version="2.14.0", lifespan=lifespan) +app = FastAPI(title="ContextCortex", version="2.15.0", lifespan=lifespan) app.add_middleware(AuthMiddleware) # Include API routes diff --git a/package.json b/package.json index 11fc6ec..faf5f98 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "contextcortex", - "version": "2.14.0", + "version": "2.15.0", "description": "High-performance Model Context Protocol (MCP) server for syntax-aware code RAG and codebase navigation", "type": "module", "scripts": { diff --git a/scripts/generate_requirements.py b/scripts/generate_requirements.py index 95e50d0..ed5f501 100644 --- a/scripts/generate_requirements.py +++ b/scripts/generate_requirements.py @@ -110,7 +110,7 @@ def generate_markdown() -> str: total_all_tests = total_py_tests + total_fe_tests + total_e2e_tests lines = [ - "# Software Requirements Specification: ContextCortex (v2.14.0)", + "# Software Requirements Specification: ContextCortex (v2.15.0)", "", "> **Note:** This document is automatically generated and verified against the live test suite by `scripts/generate_requirements.py` and `tests/backend/test_requirements_sync.py`.", "", diff --git a/tests/test_database_engine.py b/tests/test_database_engine.py index dee43a3..155a827 100644 --- a/tests/test_database_engine.py +++ b/tests/test_database_engine.py @@ -72,7 +72,7 @@ def test_sqlite_engine_initialization_and_crud(tmp_path): with get_connection(engine) as conn: conn.execute( - TABLES["system_metadata"].insert().values(key="version", value="2.14.0") + TABLES["system_metadata"].insert().values(key="version", value="2.15.0") ) conn.commit() @@ -81,7 +81,7 @@ def test_sqlite_engine_initialization_and_crud(tmp_path): ).mappings().fetchone() assert row is not None - assert row["value"] == "2.14.0" + assert row["value"] == "2.15.0" def test_sqlite_engine_seeds_default_prompts_and_configs(tmp_path): diff --git a/tests/test_file_mcp_and_api.py b/tests/test_file_mcp_and_api.py new file mode 100644 index 0000000..329a21f --- /dev/null +++ b/tests/test_file_mcp_and_api.py @@ -0,0 +1,123 @@ +import os +import pytest +from unittest.mock import patch, MagicMock +from fastapi.testclient import TestClient + +from app.services.database.engine import get_db_engine, init_db +from app.services.database.connection import get_db_connection +from app.services.file_reader import get_file_reader_service, reset_file_reader_service +from app.services.summarizer import get_summarizer_service, reset_summarizer_service +from app.mcp.handlers.file_handlers import handle_read_file, handle_summarize_file +from main import app + +@pytest.fixture +def test_env(tmp_path, monkeypatch): + db_file = tmp_path / "test_mcp_api.db" + db_url = f"sqlite:///{db_file}" + monkeypatch.setenv("DATABASE_URL", db_url) + monkeypatch.setattr("app.services.database.connection.CACHE_DB_PATH", str(db_file)) + monkeypatch.setattr("app.services.database.CACHE_DB_PATH", str(db_file), raising=False) + + storage_dir = tmp_path / "storage" + storage_dir.mkdir(parents=True, exist_ok=True) + monkeypatch.setenv("LOCAL_STORAGE_PATH", str(storage_dir)) + + watched_dir = tmp_path / "watched" + watched_dir.mkdir(parents=True, exist_ok=True) + + engine = get_db_engine(db_url, reset=True) + init_db(engine=engine) + + # Register watched path + with get_db_connection() as conn: + conn.execute( + "INSERT INTO indexed_paths (path, type, recursive, enabled, category, repo) VALUES (?, ?, 1, 1, 'watched', 'watched_repo')", + (str(watched_dir), "directory") + ) + conn.commit() + + reset_file_reader_service() + reset_summarizer_service() + + client = TestClient(app) + return { + "storage_dir": storage_dir, + "watched_dir": watched_dir, + "client": client + } + + +@pytest.mark.asyncio +async def test_mcp_handle_read_file(test_env): + watched_dir = test_env["watched_dir"] + sample_file = watched_dir / "example.py" + sample_file.write_text("line 1\nline 2\nline 3\nline 4\nline 5\n", encoding="utf-8") + + # Read slice lines 2 to 4 + output = await handle_read_file("example.py", repo="watched_repo", start_line=2, end_line=4) + assert "lines 2-4 of 5" in output + assert "line 2\nline 3\nline 4" in output + + # Path traversal rejected + err_output = await handle_read_file("../../../etc/passwd") + assert "Forbidden" in err_output or "Error" in err_output + + +@pytest.mark.asyncio +async def test_mcp_handle_summarize_file(test_env): + watched_dir = test_env["watched_dir"] + sample_file = watched_dir / "large.py" + sample_file.write_text("def hello():\n return 'world'\n", encoding="utf-8") + + fake_resp = MagicMock() + fake_resp.choices = [MagicMock(message=MagicMock(content="## Executive Overview\nA test module."))] + + with patch("app.services.summarizer.OpenAI") as mock_openai_cls: + mock_client = MagicMock() + mock_client.chat.completions.create.return_value = fake_resp + mock_openai_cls.return_value = mock_client + reset_summarizer_service() + + output = await handle_summarize_file(str(sample_file)) + assert "## Executive Overview" in output + assert "A test module." in output + + +def test_api_read_file(test_env): + client = test_env["client"] + watched_dir = test_env["watched_dir"] + sample_file = watched_dir / "api_test.txt" + sample_file.write_text("alpha\nbeta\ngamma\ndelta\n", encoding="utf-8") + + resp = client.get(f"/admin/api/files/read?path={sample_file}&start_line=1&end_line=2") + assert resp.status_code == 200 + data = resp.json() + assert data["total_lines"] == 4 + assert data["content"] == "alpha\nbeta" + assert data["start_line"] == 1 + assert data["end_line"] == 2 + + +def test_api_summarize_file(test_env): + client = test_env["client"] + watched_dir = test_env["watched_dir"] + sample_file = watched_dir / "api_summary.txt" + sample_file.write_text("important content here", encoding="utf-8") + + fake_resp = MagicMock() + fake_resp.choices = [MagicMock(message=MagicMock(content="Mocked summary response"))] + + with patch("app.services.summarizer.OpenAI") as mock_openai_cls: + mock_client = MagicMock() + mock_client.chat.completions.create.return_value = fake_resp + mock_openai_cls.return_value = mock_client + reset_summarizer_service() + + resp = client.post("/admin/api/files/summarize", json={ + "path": str(sample_file), + "force_refresh": True + }) + assert resp.status_code == 200 + data = resp.json() + assert data["status"] == "success" + assert "Mocked summary response" in data["summary"] diff --git a/tests/test_file_reader.py b/tests/test_file_reader.py new file mode 100644 index 0000000..7c77a64 --- /dev/null +++ b/tests/test_file_reader.py @@ -0,0 +1,258 @@ +import os +import pytest +from app.services.database.engine import get_db_engine, init_db +from app.services.database.connection import ( + get_db_connection, + set_file_settings, + get_file_settings, +) +from app.services.file_reader import ( + FileReaderService, + get_file_reader_service, +) + + +def setup_test_env(tmp_path, monkeypatch): + """Sets up an isolated SQLite DB and storage directory for testing.""" + db_file = tmp_path / "test_file_reader.db" + db_url = f"sqlite:///{db_file}" + monkeypatch.setenv("DATABASE_URL", db_url) + monkeypatch.setattr("app.services.database.connection.CACHE_DB_PATH", str(db_file)) + monkeypatch.setattr("app.services.database.CACHE_DB_PATH", str(db_file), raising=False) + engine = get_db_engine(db_url, reset=True) + init_db(engine=engine) + + storage_dir = tmp_path / "storage" + storage_dir.mkdir(parents=True, exist_ok=True) + monkeypatch.setenv("LOCAL_STORAGE_PATH", str(storage_dir)) + monkeypatch.setattr("app.services.local_storage.LOCAL_STORAGE_PATH", str(storage_dir), raising=False) + + return storage_dir + + +def test_safe_path_resolution_local_storage(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + service = FileReaderService(storage_root=str(storage_dir)) + + # Create file in storage + sub_file = storage_dir / "docs" / "guide.md" + sub_file.parent.mkdir(parents=True, exist_ok=True) + sub_file.write_text("# Guide", encoding="utf-8") + + # Relative path without repo + abs_path, source = service.resolve_safe_path("docs/guide.md") + assert abs_path == str(sub_file.resolve()) + assert source == "local_storage" + + # Relative path with repo="local_storage" + abs_path2, source2 = service.resolve_safe_path("docs/guide.md", repo="local_storage") + assert abs_path2 == str(sub_file.resolve()) + assert source2 == "local_storage" + + # Absolute path inside storage root + abs_path3, source3 = service.resolve_safe_path(str(sub_file.resolve())) + assert abs_path3 == str(sub_file.resolve()) + assert source3 == "local_storage" + + +def test_safe_path_resolution_indexed_paths(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + watched_dir = tmp_path / "watched_repo" + watched_dir.mkdir(parents=True, exist_ok=True) + + # Register watched_dir in DB indexed_paths + with get_db_connection() as conn: + conn.execute( + "INSERT INTO indexed_paths (path, type, enabled, repo, category) VALUES (?, ?, 1, ?, ?)", + (str(watched_dir.resolve()), "directory", "my_repo", "code") + ) + conn.commit() + + test_file = watched_dir / "src" / "main.py" + test_file.parent.mkdir(parents=True, exist_ok=True) + test_file.write_text("print('hello')", encoding="utf-8") + + service = FileReaderService(storage_root=str(storage_dir)) + + # Relative path with repo + abs_path, source = service.resolve_safe_path("src/main.py", repo="my_repo") + assert abs_path == str(test_file.resolve()) + assert source == "indexed_path" + + # Relative path without repo (resolves against matching indexed path where file exists) + abs_path2, source2 = service.resolve_safe_path("src/main.py") + assert abs_path2 == str(test_file.resolve()) + assert source2 == "indexed_path" + + # Absolute path matching watched directory + abs_path3, source3 = service.resolve_safe_path(str(test_file.resolve())) + assert abs_path3 == str(test_file.resolve()) + assert source3 == "indexed_path" + + +def test_path_traversal_and_invalid_paths_rejected(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + watched_dir = tmp_path / "watched_repo" + watched_dir.mkdir(parents=True, exist_ok=True) + with get_db_connection() as conn: + conn.execute( + "INSERT INTO indexed_paths (path, type, enabled, repo) VALUES (?, ?, 1, ?)", + (str(watched_dir.resolve()), "directory", "my_repo") + ) + conn.commit() + + service = FileReaderService(storage_root=str(storage_dir)) + + # Path traversal with .. + with pytest.raises(ValueError, match="traversal|invalid"): + service.resolve_safe_path("../secret.txt") + + with pytest.raises(ValueError, match="traversal|invalid"): + service.resolve_safe_path("docs/../../etc/passwd") + + with pytest.raises(ValueError, match="traversal|invalid"): + service.resolve_safe_path("..\\windows\\traversal") + + # Null bytes + with pytest.raises(ValueError, match="traversal|invalid"): + service.resolve_safe_path("file\x00name.txt") + + # Empty path + with pytest.raises(ValueError, match="traversal|invalid"): + service.resolve_safe_path("") + + # Absolute path outside any authorized roots + with pytest.raises(ValueError, match="outside authorized|traversal|invalid"): + service.resolve_safe_path("/etc/shadow") + + # Outside root with repo specified + with pytest.raises(ValueError, match="outside authorized|traversal|invalid"): + service.resolve_safe_path("/etc/shadow", repo="my_repo") + + # Symlink pointing outside authorized root + outside_file = tmp_path / "outside.txt" + outside_file.write_text("secret", encoding="utf-8") + symlink_file = storage_dir / "escape_link.txt" + try: + symlink_file.symlink_to(outside_file) + with pytest.raises(ValueError, match="outside authorized|traversal|invalid"): + service.resolve_safe_path("escape_link.txt") + except (OSError, NotImplementedError): + # Symlinks may not be permitted on some filesystems + pass + + +def test_read_text_file_full_and_line_slicing(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + service = FileReaderService(storage_root=str(storage_dir)) + + # Create a 10-line text file + lines = [f"Line {i}" for i in range(1, 11)] + file_content = "\n".join(lines) + test_file = storage_dir / "sample.txt" + test_file.write_text(file_content, encoding="utf-8") + + # Full read + res = service.read_file("sample.txt") + assert res["filepath"] == "sample.txt" + assert res["content"] == file_content + assert res["start_line"] == 1 + assert res["end_line"] == 10 + assert res["total_lines"] == 10 + assert res["size_bytes"] == len(file_content.encode("utf-8")) + assert res["truncated"] is False + assert res["source"] == "local_storage" + + # Line slicing (start_line=3, end_line=6, inclusive) + res_slice = service.read_file("sample.txt", start_line=3, end_line=6) + expected_slice = "\n".join([f"Line {i}" for i in range(3, 7)]) + assert res_slice["content"] == expected_slice + assert res_slice["start_line"] == 3 + assert res_slice["end_line"] == 6 + assert res_slice["total_lines"] == 10 + assert res_slice["truncated"] is False + + # Single line slice (start_line=1, end_line=1) + res_single = service.read_file("sample.txt", start_line=1, end_line=1) + assert res_single["content"] == "Line 1" + assert res_single["start_line"] == 1 + assert res_single["end_line"] == 1 + assert res_single["truncated"] is False + + # Slice past EOF + res_eof = service.read_file("sample.txt", start_line=15, end_line=20) + assert res_eof["content"] == "" + assert res_eof["total_lines"] == 10 + assert res_eof["truncated"] is False + + # Invalid line range (start_line > end_line) + with pytest.raises(ValueError, match="start_line cannot be greater than end_line"): + service.read_file("sample.txt", start_line=5, end_line=2) + + +def test_read_file_capping_max_lines_and_truncation(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + service = FileReaderService(storage_root=str(storage_dir)) + + # Create a 50-line text file + lines = [f"Line {i}" for i in range(1, 51)] + test_file = storage_dir / "large.txt" + test_file.write_text("\n".join(lines), encoding="utf-8") + + # Explicit max_lines=5 + res = service.read_file("large.txt", max_lines=5) + assert res["content"] == "\n".join([f"Line {i}" for i in range(1, 6)]) + assert res["start_line"] == 1 + assert res["end_line"] == 5 + assert res["total_lines"] == 50 + assert res["truncated"] is True + + # Setting cap via get_file_settings() (note: set_file_settings has min 10 floor) + set_file_settings({"read_file_max_lines": 15}) + res_settings = service.read_file("large.txt", max_lines=None) + assert res_settings["content"] == "\n".join([f"Line {i}" for i in range(1, 16)]) + assert res_settings["start_line"] == 1 + assert res_settings["end_line"] == 15 + assert res_settings["total_lines"] == 50 + assert res_settings["truncated"] is True + + # Sliced read that exceeds max_lines cap + res_sliced_cap = service.read_file("large.txt", start_line=10, end_line=30, max_lines=5) + assert res_sliced_cap["content"] == "\n".join([f"Line {i}" for i in range(10, 15)]) + assert res_sliced_cap["start_line"] == 10 + assert res_sliced_cap["end_line"] == 14 + assert res_sliced_cap["total_lines"] == 50 + assert res_sliced_cap["truncated"] is True + + +def test_binary_file_detection_and_rejection(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + service = FileReaderService(storage_root=str(storage_dir)) + + bin_file = storage_dir / "image.png" + bin_file.write_bytes(b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR") + + txt_file = storage_dir / "text.txt" + txt_file.write_text("Plain text content", encoding="utf-8") + + assert service.is_binary_file(str(bin_file.resolve())) is True + assert service.is_binary_file(str(txt_file.resolve())) is False + + with pytest.raises(ValueError, match="[Bb]inary"): + service.read_file("image.png") + + +def test_read_nonexistent_file_raises_not_found(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + service = FileReaderService(storage_root=str(storage_dir)) + + with pytest.raises(FileNotFoundError): + service.read_file("does_not_exist.txt") + + +def test_get_file_reader_service_singleton(tmp_path, monkeypatch): + storage_dir = setup_test_env(tmp_path, monkeypatch) + service1 = get_file_reader_service() + service2 = get_file_reader_service() + assert service1 is service2 + assert isinstance(service1, FileReaderService) diff --git a/tests/test_file_settings.py b/tests/test_file_settings.py new file mode 100644 index 0000000..4dac5b2 --- /dev/null +++ b/tests/test_file_settings.py @@ -0,0 +1,87 @@ +import os +import pytest +from app.services.database.engine import get_db_engine, init_db +from app.services.database.connection import ( + get_file_settings, + set_file_settings, + get_db_connection, +) +from fastapi.testclient import TestClient + +def setup_test_db(tmp_path, monkeypatch): + db_file = tmp_path / "test_file_settings.db" + db_url = f"sqlite:///{db_file}" + monkeypatch.setenv("DATABASE_URL", db_url) + monkeypatch.setattr("app.services.database.connection.CACHE_DB_PATH", str(db_file)) + monkeypatch.setattr("app.services.database.CACHE_DB_PATH", str(db_file), raising=False) + engine = get_db_engine(db_url, reset=True) + init_db(engine=engine) + return engine + + +def test_file_summaries_table_has_summary_text_column(tmp_path, monkeypatch): + setup_test_db(tmp_path, monkeypatch) + with get_db_connection() as conn: + cursor = conn.cursor() + cols = [r["name"] for r in cursor.execute("PRAGMA table_info(file_summaries)").fetchall()] + assert "summary_text" in cols + +def test_file_settings_defaults(tmp_path, monkeypatch): + setup_test_db(tmp_path, monkeypatch) + settings = get_file_settings() + assert settings["summary_enabled"] is True + assert settings["summary_threshold_kb"] == 500 + assert settings["summary_max_file_size_mb"] == 10 + assert settings["read_file_max_lines"] == 2000 + assert isinstance(settings["summary_chat_model"], str) + +def test_set_file_settings_persists(tmp_path, monkeypatch): + setup_test_db(tmp_path, monkeypatch) + updated = set_file_settings({ + "summary_enabled": False, + "summary_threshold_kb": 250, + "summary_max_file_size_mb": 20, + "read_file_max_lines": 1000, + "summary_chat_model": "gpt-4o" + }) + assert updated["summary_enabled"] is False + assert updated["summary_threshold_kb"] == 250 + assert updated["summary_max_file_size_mb"] == 20 + assert updated["read_file_max_lines"] == 1000 + assert updated["summary_chat_model"] == "gpt-4o" + + loaded = get_file_settings() + assert loaded["summary_enabled"] is False + assert loaded["summary_threshold_kb"] == 250 + assert loaded["summary_max_file_size_mb"] == 20 + assert loaded["read_file_max_lines"] == 1000 + assert loaded["summary_chat_model"] == "gpt-4o" + +def test_file_settings_api_endpoints(tmp_path, monkeypatch): + setup_test_db(tmp_path, monkeypatch) + from main import app + client = TestClient(app) + + # GET /admin/api/settings/files + resp = client.get("/admin/api/settings/files") + assert resp.status_code == 200 + data = resp.json() + assert data["summary_enabled"] is True + assert data["summary_threshold_kb"] == 500 + + # POST /admin/api/settings/files + post_resp = client.post("/admin/api/settings/files", json={ + "summary_enabled": True, + "summary_threshold_kb": 750, + "summary_max_file_size_mb": 15, + "read_file_max_lines": 3000, + "summary_chat_model": "claude-3-5-sonnet" + }) + assert post_resp.status_code == 200 + assert post_resp.json()["summary_threshold_kb"] == 750 + + # Verify GET returns updated + get_again = client.get("/admin/api/settings/files") + assert get_again.status_code == 200 + assert get_again.json()["summary_threshold_kb"] == 750 + assert get_again.json()["summary_chat_model"] == "claude-3-5-sonnet" diff --git a/tests/test_processor_caching.py b/tests/test_processor_caching.py index d183298..b96709c 100644 --- a/tests/test_processor_caching.py +++ b/tests/test_processor_caching.py @@ -139,7 +139,8 @@ def test_process_file_content_file_size_guard(): ) mock_embed.assert_not_called() - assert points == [] + # Normal code chunks are skipped; any produced point is a summary document + assert all(p.doc_type == "summary" for p in points) assert symbols == [] assert rels == [] assert routes == [] diff --git a/tests/test_processor_summarization.py b/tests/test_processor_summarization.py new file mode 100644 index 0000000..6bfefaf --- /dev/null +++ b/tests/test_processor_summarization.py @@ -0,0 +1,85 @@ +import os +import json +import pytest +from unittest.mock import patch, MagicMock + +from app.services.database.engine import get_db_engine, init_db +from app.services.database.connection import get_db_connection, set_file_settings +from app.services.indexing.processor import process_file_content + +@pytest.fixture +def test_env(tmp_path, monkeypatch): + db_file = tmp_path / "test_proc_summary.db" + db_url = f"sqlite:///{db_file}" + monkeypatch.setenv("DATABASE_URL", db_url) + monkeypatch.setattr("app.services.database.connection.CACHE_DB_PATH", str(db_file)) + monkeypatch.setattr("app.services.database.CACHE_DB_PATH", str(db_file), raising=False) + + engine = get_db_engine(db_url, reset=True) + init_db(engine=engine) + + from app.services.summarizer import reset_summarizer_service + reset_summarizer_service() + + # Set threshold to 10 KB for easy testing + set_file_settings({ + "summary_enabled": True, + "summary_threshold_kb": 10, + "summary_max_file_size_mb": 5, + "read_file_max_lines": 2000 + }) + + return tmp_path + + +def test_large_file_auto_summarization(test_env): + # Create content larger than 10 KB (e.g. 15 KB) + large_content = "def calculate_data():\n return 42\n" * 500 + assert len(large_content.encode("utf-8")) > 10 * 1024 + + fake_resp = MagicMock() + fake_resp.choices = [MagicMock(message=MagicMock(content="## Executive Overview\nCalculates data."))] + + with patch("app.services.summarizer.OpenAI") as mock_openai_cls: + mock_client = MagicMock() + mock_client.chat.completions.create.return_value = fake_resp + mock_openai_cls.return_value = mock_client + + with patch("app.services.embeddings.get_hybrid_embeddings") as mock_embed: + mock_embed.return_value = {"dense": [0.1] * 384, "sparse": None} + + points, symbols, summary_tuple, rels, routes, calls = process_file_content( + filepath="/path/to/large_file.py", + rel_path="large_file.py", + content=large_content, + repo="test_repo", + doc_type="code" + ) + + # Should contain a summary vector document + assert len(points) == 1 + assert points[0].doc_type == "summary" + assert "Calculates data." in points[0].text + + # summary_tuple should contain the summary text + # summary_tuple: (filepath, repo, title, folder, category, tags, headings, keywords, summary_text, mtime) + assert len(summary_tuple) == 10 + summary_text = summary_tuple[8] + assert "Calculates data." in summary_text + + +def test_large_file_disabled_summarization(test_env): + set_file_settings({"summary_enabled": False}) + + large_content = "def calculate_data():\n return 42\n" * 500 + points, symbols, summary_tuple, rels, routes, calls = process_file_content( + filepath="/path/to/large_file.py", + rel_path="large_file.py", + content=large_content, + repo="test_repo", + doc_type="code" + ) + + assert len(points) == 0 + assert len(summary_tuple) == 10 + assert summary_tuple[8] is None diff --git a/tests/test_summarizer.py b/tests/test_summarizer.py new file mode 100644 index 0000000..2cadcd2 --- /dev/null +++ b/tests/test_summarizer.py @@ -0,0 +1,298 @@ +import os +import pytest +from unittest.mock import MagicMock, patch + +from app.services.database.engine import get_db_engine, init_db +from app.services.database.connection import ( + get_db_connection, + set_file_settings, + get_file_settings, +) +from app.services.vector_store.base import VectorDocument + + +@pytest.fixture +def test_db(tmp_path, monkeypatch): + """Sets up an isolated SQLite database for summarizer testing.""" + db_file = tmp_path / "test_summarizer.db" + db_url = f"sqlite:///{db_file}" + monkeypatch.setenv("DATABASE_URL", db_url) + monkeypatch.setattr("app.services.database.connection.CACHE_DB_PATH", str(db_file)) + monkeypatch.setattr("app.services.database.CACHE_DB_PATH", str(db_file), raising=False) + engine = get_db_engine(db_url, reset=True) + init_db(engine=engine) + return engine + + +@pytest.fixture +def mock_openai_client(): + """Mocks OpenAI / LiteLLM client for chat completion tests.""" + client = MagicMock() + mock_choice = MagicMock() + mock_choice.message.content = ( + "## Summary\n" + "- **Overview**: Core service handling user authentication and token issuance.\n" + "- **Key Components**: `AuthService`, `login`, `create_access_token`.\n" + "- **Dependencies**: Imports JWT validator and database connection." + ) + mock_response = MagicMock() + mock_response.choices = [mock_choice] + client.chat.completions.create.return_value = mock_response + return client + + +def test_generate_file_summary_success(test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + service = SummarizerService(client=mock_openai_client) + filepath = "app/services/auth.py" + content = "def login(user, pw):\n return 'token123'\n" + + summary_text, vector_doc = service.generate_file_summary( + filepath=filepath, + content=content, + repo="contextcortex", + category="auth", + ) + + assert summary_text != "" + assert "Core service handling user authentication" in summary_text + + # Verify client invocation parameters + assert mock_openai_client.chat.completions.create.called + call_kwargs = mock_openai_client.chat.completions.create.call_args.kwargs + assert "messages" in call_kwargs + messages = call_kwargs["messages"] + assert any(m["role"] == "system" for m in messages) + user_msg = next(m for m in messages if m["role"] == "user") + assert filepath in user_msg["content"] + assert "token123" in user_msg["content"] + + # Verify VectorDocument metadata + assert isinstance(vector_doc, VectorDocument) + assert vector_doc.doc_type == "summary" + assert vector_doc.text == summary_text + assert vector_doc.heading == "Summary" + assert vector_doc.repo == "contextcortex" + assert vector_doc.rel_path == filepath + assert vector_doc.category == "auth" + + payload = vector_doc.to_payload() + assert payload["doc_type"] == "summary" + assert payload["heading"] == "Summary" + assert payload["repo"] == "contextcortex" + assert payload["rel_path"] == filepath + assert payload["content"] == summary_text + + +def test_generate_file_summary_handles_litellm_exception(test_db): + from app.services.summarizer import SummarizerService + + failing_client = MagicMock() + failing_client.chat.completions.create.side_effect = RuntimeError("LiteLLM connection timed out") + + service = SummarizerService(client=failing_client) + summary_text, vector_doc = service.generate_file_summary( + filepath="app/services/error.py", + content="x = 1", + repo="contextcortex", + ) + + # Must not crash, returns empty string or error string, and None vector_doc + assert vector_doc is None + assert summary_text == "" or "Error" in summary_text or "failed" in summary_text.lower() + + +def test_get_or_create_summary_returns_cached_summary(test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + filepath = "src/cached_module.py" + cached_text = "## Cached Markdown Summary\nExisting summary in database." + + # Seed SQLite file_summaries table with cached entry + with get_db_connection() as conn: + conn.execute( + """INSERT INTO file_summaries (filepath, repo, title, folder, summary_text) + VALUES (?, ?, ?, ?, ?)""", + (filepath, "test-repo", "cached_module.py", "src", cached_text), + ) + conn.commit() + + service = SummarizerService(client=mock_openai_client) + res = service.get_or_create_summary(filepath=filepath, repo="test-repo", force_refresh=False) + + # Returns cached summary without invoking LiteLLM + assert res == cached_text + assert not mock_openai_client.chat.completions.create.called + + +def test_get_or_create_summary_cache_miss_reads_disk_and_persists(tmp_path, test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + test_file = tmp_path / "service_worker.py" + test_file.write_text("class ServiceWorker:\n def run(self): pass\n", encoding="utf-8") + filepath = str(test_file) + + mock_vector_store = MagicMock() + service = SummarizerService(client=mock_openai_client, vector_store=mock_vector_store) + + res = service.get_or_create_summary(filepath=filepath, repo="test-repo", force_refresh=False) + + # Client was called + assert mock_openai_client.chat.completions.create.called + assert "Core service handling user authentication" in res + + # Vector store upsert was triggered + assert mock_vector_store.upsert_documents.called + upserted_docs = mock_vector_store.upsert_documents.call_args[0][0] + assert len(upserted_docs) == 1 + assert upserted_docs[0].doc_type == "summary" + + # SQLite file_summaries was updated + with get_db_connection() as conn: + row = conn.execute( + "SELECT summary_text FROM file_summaries WHERE filepath = ?", (filepath,) + ).fetchone() + assert row is not None + assert row["summary_text"] == res + + +def test_get_or_create_summary_force_refresh_updates_existing_cache(tmp_path, test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + test_file = tmp_path / "refresh_target.py" + test_file.write_text("def refreshed(): pass", encoding="utf-8") + filepath = str(test_file) + + # Seed old summary + with get_db_connection() as conn: + conn.execute( + """INSERT INTO file_summaries (filepath, repo, title, folder, summary_text) + VALUES (?, ?, ?, ?, ?)""", + (filepath, "test-repo", "refresh_target.py", "", "Old Outdated Summary"), + ) + conn.commit() + + mock_vector_store = MagicMock() + service = SummarizerService(client=mock_openai_client, vector_store=mock_vector_store) + + # Calling with force_refresh=True + res = service.get_or_create_summary(filepath=filepath, repo="test-repo", force_refresh=True) + + assert mock_openai_client.chat.completions.create.called + assert res != "Old Outdated Summary" + assert "Core service handling user authentication" in res + + # SQLite was updated with new summary + with get_db_connection() as conn: + row = conn.execute( + "SELECT summary_text FROM file_summaries WHERE filepath = ?", (filepath,) + ).fetchone() + assert row["summary_text"] == res + + +def test_get_or_create_summary_litellm_failure_does_not_crash(tmp_path, test_db): + from app.services.summarizer import SummarizerService + + test_file = tmp_path / "broken_llm.py" + test_file.write_text("x = 42", encoding="utf-8") + + failing_client = MagicMock() + failing_client.chat.completions.create.side_effect = Exception("LiteLLM Rate Limit Reached") + + service = SummarizerService(client=failing_client) + res = service.get_or_create_summary(filepath=str(test_file), repo="test-repo", force_refresh=False) + + assert isinstance(res, str) + assert res == "" or "error" in res.lower() or "failed" in res.lower() + + +def test_get_summarizer_service_uses_settings_model(test_db, mock_openai_client): + from app.services.summarizer import get_summarizer_service, reset_summarizer_service + + reset_summarizer_service() + set_file_settings({"summary_chat_model": "custom-claude-3-5"}) + + service = get_summarizer_service() + service.client = mock_openai_client + + service.generate_file_summary(filepath="main.py", content="print('hello')", repo="local") + + call_kwargs = mock_openai_client.chat.completions.create.call_args.kwargs + assert call_kwargs["model"] == "custom-claude-3-5" + + reset_summarizer_service() + + +def test_get_or_create_summary_nonexistent_file_raises_not_found(test_db): + from app.services.summarizer import SummarizerService + + service = SummarizerService() + with pytest.raises(FileNotFoundError): + service.get_or_create_summary("/nonexistent/path/to/missing_file.py") + + +def test_get_or_create_summary_vector_store_failure_resilience(tmp_path, test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + test_file = tmp_path / "vs_failure.py" + test_file.write_text("def test(): pass", encoding="utf-8") + + failing_vs = MagicMock() + failing_vs.upsert_documents.side_effect = RuntimeError("Qdrant connection lost") + + service = SummarizerService(client=mock_openai_client, vector_store=failing_vs) + res = service.get_or_create_summary(filepath=str(test_file), repo="test-repo") + + # Summary is still returned and SQLite is updated despite vector store failure + assert res != "" + with get_db_connection() as conn: + row = conn.execute( + "SELECT summary_text FROM file_summaries WHERE filepath = ?", (str(test_file),) + ).fetchone() + assert row is not None + assert row["summary_text"] == res + + +def test_get_or_create_summary_reads_via_file_reader(monkeypatch, test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + mock_file_reader = MagicMock() + mock_file_reader.read_file.return_value = { + "filepath": "virtual/file.py", + "content": "class VirtualFile: pass\n", + "total_lines": 1, + } + + mock_get_reader = MagicMock(return_value=mock_file_reader) + import sys + import types + fake_fr_module = types.ModuleType("app.services.file_reader") + fake_fr_module.get_file_reader_service = mock_get_reader + monkeypatch.setitem(sys.modules, "app.services.file_reader", fake_fr_module) + + service = SummarizerService(client=mock_openai_client) + res = service.get_or_create_summary(filepath="virtual/file.py", repo="custom-repo") + + assert mock_file_reader.read_file.called + assert res != "" + + +def test_generate_file_summary_truncates_huge_content(test_db, mock_openai_client): + from app.services.summarizer import SummarizerService + + service = SummarizerService(client=mock_openai_client) + huge_content = "def func():\n pass\n" * 20000 # > 200k chars + + summary_text, vector_doc = service.generate_file_summary( + filepath="large_module.py", + content=huge_content, + repo="local", + ) + + assert mock_openai_client.chat.completions.create.called + call_kwargs = mock_openai_client.chat.completions.create.call_args.kwargs + user_msg = next(m for m in call_kwargs["messages"] if m["role"] == "user") + assert "truncated for LLM context ceiling" in user_msg["content"] + assert len(user_msg["content"]) < len(huge_content) +