ArshVerma commited on
Commit
9b07070
·
unverified ·
2 Parent(s): bff00f6b366f83

Merge pull request #31 from ArshVermaGit/main

Browse files

feat: Official CodeLens. Rebrand and Zero-Error Onboarding Suite

This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitignore +77 -10
  2. GET_STARTED.md +89 -0
  3. README.md +24 -18
  4. app.py +65 -16
  5. assets/codelens-brand-v2.svg +4 -0
  6. openenv.yaml → codelens.yaml +2 -2
  7. codelens_env/__init__.py +1 -0
  8. {codereview_env → codelens_env}/config.py +1 -1
  9. {codereview_env → codelens_env}/database.py +2 -2
  10. {codereview_env → codelens_env}/env.py +6 -6
  11. {codereview_env → codelens_env}/graders/__init__.py +0 -0
  12. {codereview_env → codelens_env}/graders/arch_grader.py +1 -1
  13. {codereview_env → codelens_env}/graders/bug_grader.py +1 -1
  14. {codereview_env → codelens_env}/graders/grader_utils.py +1 -1
  15. {codereview_env → codelens_env}/graders/security_grader.py +2 -2
  16. {codereview_env → codelens_env}/models.py +0 -0
  17. {codereview_env → codelens_env}/scenarios.py +1 -1
  18. codereview_env/__init__.py +0 -1
  19. dashboard/index.html +14 -0
  20. dashboard/package-lock.json +2558 -0
  21. dashboard/package.json +30 -0
  22. dashboard/public/favicon.svg +3 -0
  23. dashboard/public/logo.svg +4 -0
  24. dashboard/src/App.js +11 -0
  25. dashboard/src/App.tsx +29 -0
  26. dashboard/src/api.js +6 -0
  27. dashboard/src/api.ts +10 -0
  28. dashboard/src/components/EventFeed.js +9 -0
  29. dashboard/src/components/EventFeed.tsx +74 -0
  30. dashboard/src/components/EventRow.js +19 -0
  31. dashboard/src/components/EventRow.tsx +61 -0
  32. dashboard/src/components/Header.js +17 -0
  33. dashboard/src/components/Header.tsx +51 -0
  34. dashboard/src/components/Leaderboard.js +23 -0
  35. dashboard/src/components/Leaderboard.tsx +98 -0
  36. dashboard/src/components/LeaderboardTable.js +11 -0
  37. dashboard/src/components/LeaderboardTable.tsx +77 -0
  38. dashboard/src/components/ScoreBadge.js +11 -0
  39. dashboard/src/components/ScoreBadge.tsx +28 -0
  40. dashboard/src/components/StatCard.js +5 -0
  41. dashboard/src/components/StatCard.tsx +37 -0
  42. dashboard/src/components/StatsRow.js +19 -0
  43. dashboard/src/components/StatsRow.tsx +44 -0
  44. dashboard/src/hooks/useWebSocket.js +56 -0
  45. dashboard/src/hooks/useWebSocket.ts +61 -0
  46. dashboard/src/index.css +57 -0
  47. dashboard/src/main.js +18 -0
  48. dashboard/src/main.tsx +25 -0
  49. dashboard/src/stores/eventStore.js +8 -0
  50. dashboard/src/stores/eventStore.ts +18 -0
.gitignore CHANGED
@@ -1,18 +1,85 @@
 
1
  venv/
2
- __pycache__/
3
- *.pyc
4
  .env
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  .pytest_cache/
6
- Roadmap.html
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  .DS_Store
 
 
8
  **/.DS_Store
9
- *.egg-info/
10
- dist/
11
- build/
 
12
  .idea/
13
  .vscode/
 
 
 
 
 
 
14
 
15
- # Persistence
16
- data/*.db
17
- data/*.db-shm
18
- data/*.db-wal
 
1
+ # Environment/Virtual Environment
2
  venv/
3
+ .venv/
4
+ env/
5
  .env
6
+ .env.local
7
+ .env.*.local
8
+
9
+ # Python artifacts
10
+ __pycache__/
11
+ *.py[cod]
12
+ *$py.class
13
+ *.so
14
+ .Python
15
+ build/
16
+ develop-eggs/
17
+ dist/
18
+ downloads/
19
+ eggs/
20
+ .eggs/
21
+ lib/
22
+ lib64/
23
+ parts/
24
+ sdist/
25
+ var/
26
+ wheels/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+ .installed.cfg
30
+ *.egg
31
+ MANIFEST
32
+
33
+ # Testing
34
  .pytest_cache/
35
+ .coverage
36
+ htmlcov/
37
+ .noserc
38
+ nosetests.xml
39
+ coverage.xml
40
+ *.cover
41
+ *.py,cover
42
+ .hypothesis/
43
+ .nox/
44
+
45
+ # Node.js / Dashboard
46
+ node_modules/
47
+ npm-debug.log*
48
+ yarn-debug.log*
49
+ yarn-error.log*
50
+ .pnpm-debug.log*
51
+ dashboard/node_modules/
52
+ dashboard/dist/
53
+ dashboard/build/
54
+ dashboard/.env
55
+ dashboard/.env.local
56
+
57
+ # Databases & Persistence
58
+ data/*.db
59
+ data/*.db-shm
60
+ data/*.db-wal
61
+ codelens.db
62
+ *.sqlite3
63
+
64
+ # OS Specific
65
  .DS_Store
66
+ .DS_Store?
67
+ **/._*
68
  **/.DS_Store
69
+ Thumbs.db
70
+ ehthumbs.db
71
+
72
+ # IDEs
73
  .idea/
74
  .vscode/
75
+ *.swp
76
+ *.swo
77
+ .project
78
+ .pydevproject
79
+ .settings/
80
+ .history/
81
 
82
+ # Project Specific Reference Docs
83
+ # (Per user request to exclude from commits)
84
+ files/
85
+ Roadmap.html
GET_STARTED.md ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚀 Getting Started with CodeLens.
2
+
3
+ Welcome to **CodeLens.**, a production-grade AI agent evaluation environment. This guide will help you get up and running in less than 2 minutes.
4
+
5
+ ---
6
+
7
+ ## 1. Setup your Environment
8
+ First, create a virtual environment and install the required Python dependencies.
9
+
10
+ ```bash
11
+ # Create and activate virtual environment
12
+ python3 -m venv venv && source venv/bin/activate
13
+
14
+ # Install dependencies
15
+ pip install -r requirements.txt
16
+ ```
17
+
18
+ ---
19
+
20
+ ## 2. Initialize the Database
21
+ CodeLens uses SQLite for persistence. You must initialize the database before running the server for the first time.
22
+
23
+ ```bash
24
+ # Initialize the codelens.db with 30 baseline scenarios
25
+ python scripts/migrate.py init
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 3. Launch the System
31
+ Start the FastAPI server. This serves both the **Agent API** and the **Interactive Dashboard**.
32
+
33
+ ```bash
34
+ # Run the server
35
+ PYTHONPATH=. python app.py
36
+ ```
37
+
38
+ ---
39
+
40
+ ## 4. Open the Dashboard
41
+ Once the server is running, you can access the CodeLens Dashboard at:
42
+
43
+ 👉 **[http://localhost:7860/dashboard](http://localhost:7860/dashboard)**
44
+
45
+ From here, you can see the top-10 leaderboard and monitor live agent evaluations.
46
+
47
+ ---
48
+
49
+ ## 5. Run your First Evaluation
50
+ While keeping the server running in one terminal, open a **new terminal** and run the built-in Keyword agent to see results populated on the dashboard.
51
+
52
+ ```bash
53
+ # Activate venv in the new terminal first!
54
+ source venv/bin/activate
55
+
56
+ # Run evaluation
57
+ python scripts/evaluate.py --agent keyword
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🧪 Running Tests
63
+ To verify everything is working perfectly, you can run the full 155-test suite:
64
+
65
+ ```bash
66
+ PYTHONPATH=. pytest tests/ -v
67
+ ```
68
+
69
+ ---
70
+
71
+ ## \ud83d\udee0 Troubleshooting Common Errors
72
+
73
+ ### 1. `ModuleNotFoundError: No module named 'requests'`
74
+ This happens if you haven't activated the virtual environment in your current terminal tab.
75
+ - **Fix**: Run `source venv/bin/activate` in every new terminal window.
76
+
77
+ ### 2. `Usage: python3 scripts/migrate.py [init|reset]`
78
+ The migration script requires an argument to proceed.
79
+ - **Fix**: Run `python scripts/migrate.py init` specifically.
80
+
81
+ ### 3. Logo not appearing in Dashboard
82
+ If the logo shows a broken image placeholder:
83
+ - **Fix**: Re-run the server with `PYTHONPATH=. python app.py`. The backend now has optimized routing to serve the `logo.svg`.
84
+
85
+ ---
86
+
87
+ > [!TIP]
88
+ > If you ever want to reset the database and start fresh with original scenarios, run:
89
+ > `python scripts/migrate.py reset`
README.md CHANGED
@@ -1,10 +1,14 @@
1
- # AgentOrg CodeReview OpenEnv
 
 
 
 
2
 
3
  > **Can an AI agent catch the SQL injection that caused the $100M breach — before it ships?**
4
 
5
  This environment trains and evaluates agents on realistic Python code reviews grounded in real-world incident patterns. Unlike toy examples, every scenario is calibrated against actual production failure modes: payment mutations without idempotency keys, JWT verification bypassed for "dev convenience," pickle deserialization opening RCE vectors.
6
 
7
- [![OpenEnv](https://img.shields.io/badge/OpenEnv-1.0-blue)](https://huggingface.co/) [![Python 3.11](https://img.shields.io/badge/python-3.11-green)](https://python.org) [![FastAPI](https://img.shields.io/badge/FastAPI-0.109-red)](https://fastapi.tiangolo.com)
8
 
9
  ---
10
 
@@ -94,12 +98,12 @@ WS /ws/events → real-time step event stream
94
 
95
  ```
96
  .
97
- ├── inference.py # Root inference script (OpenEnv spec required)
98
  ├── app.py # FastAPI entry point
99
- ├── openenv.yaml # OpenEnv spec manifest
100
  ├── Dockerfile # HuggingFace Spaces deployment
101
  ├── requirements.txt
102
- ├── codereview_env/
103
  │ ├── env.py # Episode state machine with incremental rewards
104
  │ ├── models.py # Pydantic models (Observation, Action, StateResult...)
105
  │ ├── scenario_bank.py # 30 scenarios with service metadata
@@ -115,30 +119,32 @@ WS /ws/events → real-time step event stream
115
 
116
  ---
117
 
118
- ## Quick Start
119
-
120
- ### 1. Install
121
 
 
122
  ```bash
123
  python3 -m venv venv && source venv/bin/activate
124
  pip install -r requirements.txt
125
  ```
126
 
127
- ### 2. Start the Environment Server
 
 
 
 
128
 
 
129
  ```bash
130
  PYTHONPATH=. python app.py
131
- # Server runs on http://localhost:7860
132
  ```
133
 
134
- ### 3. Run Tests
135
-
136
  ```bash
137
- PYTHONPATH=. pytest tests/ -v
138
  ```
139
 
140
- ### 4. Run Inference Script (OpenEnv spec format)
141
-
142
  ```bash
143
  export API_BASE_URL="https://api.openai.com/v1"
144
  export MODEL_NAME="gpt-4o"
@@ -178,10 +184,10 @@ Output format:
178
  ## Docker / HuggingFace Spaces
179
 
180
  ```bash
181
- docker build -t codereview-openenv .
182
  docker run -p 7860:7860 \
183
  -e PYTHONPATH=/app \
184
- codereview-openenv
185
  ```
186
 
187
  The server starts automatically via `python app.py`.
@@ -197,4 +203,4 @@ The server starts automatically via `python app.py`.
197
  - **Blast Radius Context** — `affected_users`, `service_criticality`, `blast_radius` in every observation
198
  - **WebSocket Stream** — Real-time step event broadcasting on `/ws/events`
199
  - **Leaderboard** — In-memory top-10 tracking per task
200
- - **Full OpenEnv Spec** — `/reset`, `/step`, `/state`, `/result` + `[START]`/`[STEP]`/`[END]` stdout format
 
1
+ <p align="center">
2
+ <img src="assets/codelens-brand-v2.svg" width="400" alt="CodeLens." />
3
+ </p>
4
+
5
+ # CodeLens
6
 
7
  > **Can an AI agent catch the SQL injection that caused the $100M breach — before it ships?**
8
 
9
  This environment trains and evaluates agents on realistic Python code reviews grounded in real-world incident patterns. Unlike toy examples, every scenario is calibrated against actual production failure modes: payment mutations without idempotency keys, JWT verification bypassed for "dev convenience," pickle deserialization opening RCE vectors.
10
 
11
+ [![CodeLens](https://img.shields.io/badge/CodeLens-1.0-blue)](https://huggingface.co/) [![Python 3.11](https://img.shields.io/badge/python-3.11-green)](https://python.org) [![FastAPI](https://img.shields.io/badge/FastAPI-0.109-red)](https://fastapi.tiangolo.com)
12
 
13
  ---
14
 
 
98
 
99
  ```
100
  .
101
+ ├── inference.py # Root inference script (CodeLens spec required)
102
  ├── app.py # FastAPI entry point
103
+ ├── codelens.yaml # CodeLens spec manifest
104
  ├── Dockerfile # HuggingFace Spaces deployment
105
  ├── requirements.txt
106
+ ├── codelens_env/
107
  │ ├── env.py # Episode state machine with incremental rewards
108
  │ ├── models.py # Pydantic models (Observation, Action, StateResult...)
109
  │ ├── scenario_bank.py # 30 scenarios with service metadata
 
119
 
120
  ---
121
 
122
+ ## \ud83d\ude80 Quick Start
 
 
123
 
124
+ ### 1. Setup Environment
125
  ```bash
126
  python3 -m venv venv && source venv/bin/activate
127
  pip install -r requirements.txt
128
  ```
129
 
130
+ ### 2. Initialize Database
131
+ ```bash
132
+ # This creates the codelens.db with all standard scenarios
133
+ python scripts/migrate.py init
134
+ ```
135
 
136
+ ### 3. Launch CodeLens
137
  ```bash
138
  PYTHONPATH=. python app.py
139
+ # API and Dashboard are now live at http://localhost:7860/dashboard
140
  ```
141
 
142
+ ### 4. Run Evaluation (Baseline)
143
+ In a new terminal:
144
  ```bash
145
+ python scripts/evaluate.py --agent keyword
146
  ```
147
 
 
 
148
  ```bash
149
  export API_BASE_URL="https://api.openai.com/v1"
150
  export MODEL_NAME="gpt-4o"
 
184
  ## Docker / HuggingFace Spaces
185
 
186
  ```bash
187
+ docker build -t codelens-env .
188
  docker run -p 7860:7860 \
189
  -e PYTHONPATH=/app \
190
+ codelens-env
191
  ```
192
 
193
  The server starts automatically via `python app.py`.
 
203
  - **Blast Radius Context** — `affected_users`, `service_criticality`, `blast_radius` in every observation
204
  - **WebSocket Stream** — Real-time step event broadcasting on `/ws/events`
205
  - **Leaderboard** — In-memory top-10 tracking per task
206
+ - **Full CodeLens Spec** — `/reset`, `/step`, `/state`, `/result` + `[START]`/`[STEP]`/`[END]` stdout format
app.py CHANGED
@@ -2,25 +2,29 @@ import uuid
2
  import logging
3
  import asyncio
4
  import json
5
- from typing import Dict, List, Optional
6
  from datetime import datetime, timezone
 
7
 
8
  from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Depends, Security, Query, BackgroundTasks, Request
9
- from fastapi.responses import JSONResponse
10
  from fastapi.exceptions import RequestValidationError
11
  from fastapi.security.api_key import APIKeyHeader
 
 
12
  from pydantic import BaseModel
13
  from slowapi import Limiter, _rate_limit_exceeded_handler
14
  from slowapi.util import get_remote_address
15
  from slowapi.errors import RateLimitExceeded
16
  from sqlmodel import Session
 
17
 
18
- from codereview_env.models import (
19
  TaskId, Action, ResetResult, StepResult, EpisodeResult, ActionRecord
20
  )
21
- from codereview_env.env import CodeReviewEnv
22
- from codereview_env.config import get_settings
23
- from codereview_env.database import (
24
  create_db_and_tables, get_session, save_episode,
25
  get_episode, get_leaderboard_db, submit_leaderboard, get_stats,
26
  LeaderboardRecord
@@ -32,17 +36,45 @@ logging.basicConfig(
32
  level=getattr(logging, settings.log_level),
33
  format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
34
  )
35
- logger = logging.getLogger("codereview_env")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  # ── App Initialization ────────────────────────────────────────────────────────
38
  app = FastAPI(
39
- title="AgentOrg CodeReview OpenEnv API",
40
  description=(
41
  "AI Senior Code Reviewer evaluation environment. "
42
  "Trains agents to detect bugs, security vulnerabilities, and architectural issues "
43
  "in realistic Python PRs."
44
  ),
45
  version="1.0.0",
 
 
 
 
 
 
 
 
 
 
46
  )
47
 
48
  # ── Rate Limiting ─────────────────────────────────────────────────────────────
@@ -60,7 +92,7 @@ async def verify_api_key(api_key: str = Security(API_KEY_HEADER)):
60
  raise HTTPException(status_code=403, detail="Invalid or missing API key")
61
 
62
  # ── Storage & TTL ─────────────────────────────────────────────────────────────
63
- episodes: Dict[str, CodeReviewEnv] = {}
64
  episode_timestamps: Dict[str, datetime] = {}
65
 
66
  async def cleanup_expired_episodes():
@@ -78,11 +110,6 @@ async def cleanup_expired_episodes():
78
  if expired:
79
  logger.info(f"Cleaned up {len(expired)} expired episodes")
80
 
81
- @app.on_event("startup")
82
- async def startup_event():
83
- create_db_and_tables()
84
- asyncio.create_task(cleanup_expired_episodes())
85
- logger.info(f"CodeReview API started \u2014 DB at {settings.db_path}")
86
 
87
  # ── Models ────────────────────────────────────────────────────────────────────
88
  class ResetRequest(BaseModel):
@@ -146,14 +173,15 @@ def health_check():
146
  "env_ready": True,
147
  "env": settings.app_env,
148
  "active_episodes": len(episodes),
149
- "auth_enabled": settings.api_key_enabled
 
150
  }
151
 
152
  @app.post("/reset", response_model=ResetResponse)
153
  @limiter.limit(f"{settings.rate_limit_per_minute}/minute")
154
  def reset_env(request: Request, req: ResetRequest, _: None = Depends(verify_api_key)):
155
  episode_id = str(uuid.uuid4())
156
- env = CodeReviewEnv()
157
  result = env.reset(req.task_id, req.seed)
158
  episodes[episode_id] = env
159
  episode_timestamps[episode_id] = datetime.now(timezone.utc)
@@ -297,6 +325,27 @@ async def websocket_endpoint(websocket: WebSocket):
297
  finally:
298
  clients.discard(websocket)
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  if __name__ == "__main__":
301
  import uvicorn
302
  uvicorn.run(app, host=settings.app_host, port=settings.app_port)
 
2
  import logging
3
  import asyncio
4
  import json
5
+ from typing import Dict, List, Optional, AsyncGenerator
6
  from datetime import datetime, timezone
7
+ from contextlib import asynccontextmanager
8
 
9
  from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, Depends, Security, Query, BackgroundTasks, Request
10
+ from fastapi.responses import JSONResponse, FileResponse
11
  from fastapi.exceptions import RequestValidationError
12
  from fastapi.security.api_key import APIKeyHeader
13
+ from fastapi.staticfiles import StaticFiles
14
+ from fastapi.middleware.cors import CORSMiddleware
15
  from pydantic import BaseModel
16
  from slowapi import Limiter, _rate_limit_exceeded_handler
17
  from slowapi.util import get_remote_address
18
  from slowapi.errors import RateLimitExceeded
19
  from sqlmodel import Session
20
+ import os
21
 
22
+ from codelens_env.models import (
23
  TaskId, Action, ResetResult, StepResult, EpisodeResult, ActionRecord
24
  )
25
+ from codelens_env.env import CodeLensEnv
26
+ from codelens_env.config import get_settings
27
+ from codelens_env.database import (
28
  create_db_and_tables, get_session, save_episode,
29
  get_episode, get_leaderboard_db, submit_leaderboard, get_stats,
30
  LeaderboardRecord
 
36
  level=getattr(logging, settings.log_level),
37
  format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
38
  )
39
+ logger = logging.getLogger("codelens_env")
40
+
41
+ # ── Lifespan ──────────────────────────────────────────────────────────────────
42
+ @asynccontextmanager
43
+ async def lifespan(app: FastAPI):
44
+ # Startup
45
+ create_db_and_tables()
46
+ cleanup_task = asyncio.create_task(cleanup_expired_episodes())
47
+ logger.info(f"CodeLens API started — DB at {settings.db_path}")
48
+
49
+ yield
50
+
51
+ # Shutdown
52
+ cleanup_task.cancel()
53
+ try:
54
+ await cleanup_task
55
+ except asyncio.CancelledError:
56
+ pass
57
+ logger.info("CodeLens API shutting down")
58
 
59
  # ── App Initialization ────────────────────────────────────────────────────────
60
  app = FastAPI(
61
+ title="CodeLens API",
62
  description=(
63
  "AI Senior Code Reviewer evaluation environment. "
64
  "Trains agents to detect bugs, security vulnerabilities, and architectural issues "
65
  "in realistic Python PRs."
66
  ),
67
  version="1.0.0",
68
+ lifespan=lifespan,
69
+ )
70
+
71
+ # ── CORS Middleware ───────────────────────────────────────────────────────────
72
+ app.add_middleware(
73
+ CORSMiddleware,
74
+ allow_origins=["*"] if settings.app_env == "development" else [f"http://localhost:{settings.app_port}"],
75
+ allow_credentials=True,
76
+ allow_methods=["*"],
77
+ allow_headers=["*"],
78
  )
79
 
80
  # ── Rate Limiting ─────────────────────────────────────────────────────────────
 
92
  raise HTTPException(status_code=403, detail="Invalid or missing API key")
93
 
94
  # ── Storage & TTL ─────────────────────────────────────────────────────────────
95
+ episodes: Dict[str, CodeLensEnv] = {}
96
  episode_timestamps: Dict[str, datetime] = {}
97
 
98
  async def cleanup_expired_episodes():
 
110
  if expired:
111
  logger.info(f"Cleaned up {len(expired)} expired episodes")
112
 
 
 
 
 
 
113
 
114
  # ── Models ────────────────────────────────────────────────────────────────────
115
  class ResetRequest(BaseModel):
 
173
  "env_ready": True,
174
  "env": settings.app_env,
175
  "active_episodes": len(episodes),
176
+ "auth_enabled": settings.api_key_enabled,
177
+ "dashboard_url": "/dashboard"
178
  }
179
 
180
  @app.post("/reset", response_model=ResetResponse)
181
  @limiter.limit(f"{settings.rate_limit_per_minute}/minute")
182
  def reset_env(request: Request, req: ResetRequest, _: None = Depends(verify_api_key)):
183
  episode_id = str(uuid.uuid4())
184
+ env = CodeLensEnv()
185
  result = env.reset(req.task_id, req.seed)
186
  episodes[episode_id] = env
187
  episode_timestamps[episode_id] = datetime.now(timezone.utc)
 
325
  finally:
326
  clients.discard(websocket)
327
 
328
+ # ── Dashboard ─────────────────────────────────────────────────────────────────
329
+ static_dir = os.path.join(os.path.dirname(__file__), "static", "dashboard")
330
+ if os.path.exists(static_dir):
331
+ app.mount("/dashboard/assets", StaticFiles(directory=os.path.join(static_dir, "assets")), name="dashboard-assets")
332
+
333
+ @app.get("/dashboard", include_in_schema=False)
334
+ @app.get("/dashboard/{full_path:path}", include_in_schema=False)
335
+ def dashboard(full_path: str = ""):
336
+ """Serve the React dashboard SPA (index.html for all sub-paths)."""
337
+ # 1. Check if the requested full_path is a specific static file (e.g. logo.svg)
338
+ if full_path:
339
+ static_file = os.path.join(os.path.dirname(__file__), "static", "dashboard", full_path)
340
+ if os.path.exists(static_file) and os.path.isfile(static_file):
341
+ return FileResponse(static_file)
342
+
343
+ # 2. Fallback to index.html for SPA routing
344
+ html_path = os.path.join(os.path.dirname(__file__), "static", "dashboard", "index.html")
345
+ if not os.path.exists(html_path):
346
+ raise HTTPException(status_code=404, detail="Dashboard not found. Run: cd dashboard && npm run build")
347
+ return FileResponse(html_path)
348
+
349
  if __name__ == "__main__":
350
  import uvicorn
351
  uvicorn.run(app, host=settings.app_host, port=settings.app_port)
assets/codelens-brand-v2.svg ADDED
openenv.yaml → codelens.yaml RENAMED
@@ -1,5 +1,5 @@
1
  version: "1.0"
2
- name: "agentorg-codereview"
3
  description: >
4
  AI Senior Code Reviewer evaluation environment — trains agents to detect bugs,
5
  security vulnerabilities, and architectural issues in realistic Python PRs.
@@ -9,7 +9,7 @@ base_url: "http://localhost:7860"
9
  api_version: "v1"
10
 
11
  tags:
12
- - openenv
13
  - code-review
14
  - security
15
  - software-engineering
 
1
  version: "1.0"
2
+ name: "codelens-codelens"
3
  description: >
4
  AI Senior Code Reviewer evaluation environment — trains agents to detect bugs,
5
  security vulnerabilities, and architectural issues in realistic Python PRs.
 
9
  api_version: "v1"
10
 
11
  tags:
12
+ - codelens
13
  - code-review
14
  - security
15
  - software-engineering
codelens_env/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ """CodeLens Environment package."""
{codereview_env → codelens_env}/config.py RENAMED
@@ -19,7 +19,7 @@ class Settings(BaseSettings):
19
  rate_limit_per_minute: int = 60 # requests per minute per IP
20
 
21
  # Persistence
22
- db_path: str = "./data/codereview.db"
23
  db_echo: bool = False # Set True to log all SQL queries
24
 
25
  @lru_cache
 
19
  rate_limit_per_minute: int = 60 # requests per minute per IP
20
 
21
  # Persistence
22
+ db_path: str = "./data/codelens.db"
23
  db_echo: bool = False # Set True to log all SQL queries
24
 
25
  @lru_cache
{codereview_env → codelens_env}/database.py RENAMED
@@ -2,8 +2,8 @@ from pathlib import Path
2
  from sqlmodel import SQLModel, Field, Session, create_engine, select
3
  from typing import Optional, List, Tuple
4
  import json
5
- from codereview_env.config import get_settings
6
- from codereview_env.models import EpisodeResult, TaskId
7
 
8
  def get_engine():
9
  settings = get_settings()
 
2
  from sqlmodel import SQLModel, Field, Session, create_engine, select
3
  from typing import Optional, List, Tuple
4
  import json
5
+ from codelens_env.config import get_settings
6
+ from codelens_env.models import EpisodeResult, TaskId
7
 
8
  def get_engine():
9
  settings = get_settings()
{codereview_env → codelens_env}/env.py RENAMED
@@ -1,15 +1,15 @@
1
  from datetime import datetime, timezone
2
  from typing import List, Optional, Set
3
- from codereview_env.models import (
4
  TaskId, Action, Observation, StepResult, ResetResult,
5
  ActionType, ActionRecord, EpisodeResult, Severity, GroundTruthIssue
6
  )
7
- from codereview_env.scenarios import get_scenario
8
- from codereview_env.graders.bug_grader import grade_bug_detection
9
- from codereview_env.graders.security_grader import grade_security_audit
10
- from codereview_env.graders.arch_grader import grade_architectural_review
11
 
12
- class CodeReviewEnv:
13
  MAX_NOISE_BUDGET = 5
14
  TASK_MAX_STEPS = {
15
  TaskId.BUG_DETECTION: 10,
 
1
  from datetime import datetime, timezone
2
  from typing import List, Optional, Set
3
+ from codelens_env.models import (
4
  TaskId, Action, Observation, StepResult, ResetResult,
5
  ActionType, ActionRecord, EpisodeResult, Severity, GroundTruthIssue
6
  )
7
+ from codelens_env.scenarios import get_scenario
8
+ from codelens_env.graders.bug_grader import grade_bug_detection
9
+ from codelens_env.graders.security_grader import grade_security_audit
10
+ from codelens_env.graders.arch_grader import grade_architectural_review
11
 
12
+ class CodeLensEnv:
13
  MAX_NOISE_BUDGET = 5
14
  TASK_MAX_STEPS = {
15
  TaskId.BUG_DETECTION: 10,
{codereview_env → codelens_env}/graders/__init__.py RENAMED
File without changes
{codereview_env → codelens_env}/graders/arch_grader.py RENAMED
@@ -1,5 +1,5 @@
1
  from typing import List
2
- from codereview_env.models import Scenario, ActionRecord, Category, ActionType, Verdict
3
 
4
  def grade_architectural_review(scenario: Scenario, history: List[ActionRecord]) -> float:
5
  if not history:
 
1
  from typing import List
2
+ from codelens_env.models import Scenario, ActionRecord, Category, ActionType, Verdict
3
 
4
  def grade_architectural_review(scenario: Scenario, history: List[ActionRecord]) -> float:
5
  if not history:
{codereview_env → codelens_env}/graders/bug_grader.py RENAMED
@@ -1,5 +1,5 @@
1
  from typing import List
2
- from codereview_env.models import Scenario, ActionRecord, Category, Severity, ActionType
3
 
4
  def grade_bug_detection(scenario: Scenario, history: List[ActionRecord]) -> float:
5
  if not history:
 
1
  from typing import List
2
+ from codelens_env.models import Scenario, ActionRecord, Category, Severity, ActionType
3
 
4
  def grade_bug_detection(scenario: Scenario, history: List[ActionRecord]) -> float:
5
  if not history:
{codereview_env → codelens_env}/graders/grader_utils.py RENAMED
@@ -1,5 +1,5 @@
1
  from typing import List, Optional
2
- from codereview_env.models import GroundTruthIssue, Action
3
 
4
  def keyword_overlap(body: str, keywords: List[str]) -> float:
5
  """Returns 0.0–1.0 confidence score based on keyword coverage."""
 
1
  from typing import List, Optional
2
+ from codelens_env.models import GroundTruthIssue, Action
3
 
4
  def keyword_overlap(body: str, keywords: List[str]) -> float:
5
  """Returns 0.0–1.0 confidence score based on keyword coverage."""
{codereview_env → codelens_env}/graders/security_grader.py RENAMED
@@ -1,5 +1,5 @@
1
  from typing import List
2
- from codereview_env.models import Scenario, ActionRecord, Category, Severity, ActionType
3
 
4
  def grade_security_audit(scenario: Scenario, history: List[ActionRecord]) -> float:
5
  if not history:
@@ -42,7 +42,7 @@ def grade_security_audit(scenario: Scenario, history: List[ActionRecord]) -> flo
42
 
43
  body_lower = (action.body or "").lower()
44
  match_count = sum(1 for kw in truth.keywords if kw.lower() in body_lower)
45
- kw_threshold = max(4, len(truth.keywords))
46
  kw_score = match_count / kw_threshold
47
 
48
  issue_score = 0.7 * sev_score + 0.3 * kw_score
 
1
  from typing import List
2
+ from codelens_env.models import Scenario, ActionRecord, Category, Severity, ActionType
3
 
4
  def grade_security_audit(scenario: Scenario, history: List[ActionRecord]) -> float:
5
  if not history:
 
42
 
43
  body_lower = (action.body or "").lower()
44
  match_count = sum(1 for kw in truth.keywords if kw.lower() in body_lower)
45
+ kw_threshold = len(truth.keywords) if truth.keywords else 1
46
  kw_score = match_count / kw_threshold
47
 
48
  issue_score = 0.7 * sev_score + 0.3 * kw_score
{codereview_env → codelens_env}/models.py RENAMED
File without changes
{codereview_env → codelens_env}/scenarios.py RENAMED
@@ -1,4 +1,4 @@
1
- from codereview_env.models import Scenario, FileChanged, GroundTruthIssue, Category, Severity, TaskId, Verdict
2
 
3
  def get_scenario(task_id: TaskId, seed: int) -> Scenario:
4
  scenarios = [s for s in ALL_SCENARIOS if s.task_id == task_id]
 
1
+ from codelens_env.models import Scenario, FileChanged, GroundTruthIssue, Category, Severity, TaskId, Verdict
2
 
3
  def get_scenario(task_id: TaskId, seed: int) -> Scenario:
4
  scenarios = [s for s in ALL_SCENARIOS if s.task_id == task_id]
codereview_env/__init__.py DELETED
@@ -1 +0,0 @@
1
- """AgentOrg CodeReview Environment package."""
 
 
dashboard/index.html ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>CodeLens Dashboard</title>
7
+ <meta name="description" content="CodeLens Evaluation Dashboard — Live leaderboard, stats, and real-time event feed." />
8
+ <link rel="icon" type="image/svg+xml" href="/dashboard/favicon.svg" />
9
+ </head>
10
+ <body>
11
+ <div id="root"></div>
12
+ <script type="module" src="/src/main.tsx"></script>
13
+ </body>
14
+ </html>
dashboard/package-lock.json ADDED
@@ -0,0 +1,2558 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "codelens-dashboard",
3
+ "version": "0.1.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "codelens-dashboard",
9
+ "version": "0.1.0",
10
+ "dependencies": {
11
+ "@fontsource/inter": "^5.1.0",
12
+ "@tanstack/react-query": "^5.0.0",
13
+ "clsx": "^2.1.0",
14
+ "lucide-react": "^0.475.0",
15
+ "react": "^18.3.0",
16
+ "react-dom": "^18.3.0",
17
+ "zustand": "^5.0.0"
18
+ },
19
+ "devDependencies": {
20
+ "@tailwindcss/vite": "^4.1.0",
21
+ "@types/node": "^25.5.2",
22
+ "@types/react": "^18.3.0",
23
+ "@types/react-dom": "^18.3.0",
24
+ "@vitejs/plugin-react": "^4.3.0",
25
+ "tailwindcss": "^4.1.0",
26
+ "typescript": "^5.7.0",
27
+ "vite": "^6.2.0"
28
+ }
29
+ },
30
+ "node_modules/@babel/code-frame": {
31
+ "version": "7.29.0",
32
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
33
+ "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
34
+ "dev": true,
35
+ "license": "MIT",
36
+ "dependencies": {
37
+ "@babel/helper-validator-identifier": "^7.28.5",
38
+ "js-tokens": "^4.0.0",
39
+ "picocolors": "^1.1.1"
40
+ },
41
+ "engines": {
42
+ "node": ">=6.9.0"
43
+ }
44
+ },
45
+ "node_modules/@babel/compat-data": {
46
+ "version": "7.29.0",
47
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
48
+ "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
49
+ "dev": true,
50
+ "license": "MIT",
51
+ "engines": {
52
+ "node": ">=6.9.0"
53
+ }
54
+ },
55
+ "node_modules/@babel/core": {
56
+ "version": "7.29.0",
57
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
58
+ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
59
+ "dev": true,
60
+ "license": "MIT",
61
+ "dependencies": {
62
+ "@babel/code-frame": "^7.29.0",
63
+ "@babel/generator": "^7.29.0",
64
+ "@babel/helper-compilation-targets": "^7.28.6",
65
+ "@babel/helper-module-transforms": "^7.28.6",
66
+ "@babel/helpers": "^7.28.6",
67
+ "@babel/parser": "^7.29.0",
68
+ "@babel/template": "^7.28.6",
69
+ "@babel/traverse": "^7.29.0",
70
+ "@babel/types": "^7.29.0",
71
+ "@jridgewell/remapping": "^2.3.5",
72
+ "convert-source-map": "^2.0.0",
73
+ "debug": "^4.1.0",
74
+ "gensync": "^1.0.0-beta.2",
75
+ "json5": "^2.2.3",
76
+ "semver": "^6.3.1"
77
+ },
78
+ "engines": {
79
+ "node": ">=6.9.0"
80
+ },
81
+ "funding": {
82
+ "type": "opencollective",
83
+ "url": "https://opencollective.com/babel"
84
+ }
85
+ },
86
+ "node_modules/@babel/generator": {
87
+ "version": "7.29.1",
88
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
89
+ "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
90
+ "dev": true,
91
+ "license": "MIT",
92
+ "dependencies": {
93
+ "@babel/parser": "^7.29.0",
94
+ "@babel/types": "^7.29.0",
95
+ "@jridgewell/gen-mapping": "^0.3.12",
96
+ "@jridgewell/trace-mapping": "^0.3.28",
97
+ "jsesc": "^3.0.2"
98
+ },
99
+ "engines": {
100
+ "node": ">=6.9.0"
101
+ }
102
+ },
103
+ "node_modules/@babel/helper-compilation-targets": {
104
+ "version": "7.28.6",
105
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
106
+ "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
107
+ "dev": true,
108
+ "license": "MIT",
109
+ "dependencies": {
110
+ "@babel/compat-data": "^7.28.6",
111
+ "@babel/helper-validator-option": "^7.27.1",
112
+ "browserslist": "^4.24.0",
113
+ "lru-cache": "^5.1.1",
114
+ "semver": "^6.3.1"
115
+ },
116
+ "engines": {
117
+ "node": ">=6.9.0"
118
+ }
119
+ },
120
+ "node_modules/@babel/helper-globals": {
121
+ "version": "7.28.0",
122
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
123
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
124
+ "dev": true,
125
+ "license": "MIT",
126
+ "engines": {
127
+ "node": ">=6.9.0"
128
+ }
129
+ },
130
+ "node_modules/@babel/helper-module-imports": {
131
+ "version": "7.28.6",
132
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
133
+ "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
134
+ "dev": true,
135
+ "license": "MIT",
136
+ "dependencies": {
137
+ "@babel/traverse": "^7.28.6",
138
+ "@babel/types": "^7.28.6"
139
+ },
140
+ "engines": {
141
+ "node": ">=6.9.0"
142
+ }
143
+ },
144
+ "node_modules/@babel/helper-module-transforms": {
145
+ "version": "7.28.6",
146
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
147
+ "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
148
+ "dev": true,
149
+ "license": "MIT",
150
+ "dependencies": {
151
+ "@babel/helper-module-imports": "^7.28.6",
152
+ "@babel/helper-validator-identifier": "^7.28.5",
153
+ "@babel/traverse": "^7.28.6"
154
+ },
155
+ "engines": {
156
+ "node": ">=6.9.0"
157
+ },
158
+ "peerDependencies": {
159
+ "@babel/core": "^7.0.0"
160
+ }
161
+ },
162
+ "node_modules/@babel/helper-plugin-utils": {
163
+ "version": "7.28.6",
164
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
165
+ "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
166
+ "dev": true,
167
+ "license": "MIT",
168
+ "engines": {
169
+ "node": ">=6.9.0"
170
+ }
171
+ },
172
+ "node_modules/@babel/helper-string-parser": {
173
+ "version": "7.27.1",
174
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
175
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
176
+ "dev": true,
177
+ "license": "MIT",
178
+ "engines": {
179
+ "node": ">=6.9.0"
180
+ }
181
+ },
182
+ "node_modules/@babel/helper-validator-identifier": {
183
+ "version": "7.28.5",
184
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
185
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
186
+ "dev": true,
187
+ "license": "MIT",
188
+ "engines": {
189
+ "node": ">=6.9.0"
190
+ }
191
+ },
192
+ "node_modules/@babel/helper-validator-option": {
193
+ "version": "7.27.1",
194
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
195
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
196
+ "dev": true,
197
+ "license": "MIT",
198
+ "engines": {
199
+ "node": ">=6.9.0"
200
+ }
201
+ },
202
+ "node_modules/@babel/helpers": {
203
+ "version": "7.29.2",
204
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz",
205
+ "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==",
206
+ "dev": true,
207
+ "license": "MIT",
208
+ "dependencies": {
209
+ "@babel/template": "^7.28.6",
210
+ "@babel/types": "^7.29.0"
211
+ },
212
+ "engines": {
213
+ "node": ">=6.9.0"
214
+ }
215
+ },
216
+ "node_modules/@babel/parser": {
217
+ "version": "7.29.2",
218
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz",
219
+ "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==",
220
+ "dev": true,
221
+ "license": "MIT",
222
+ "dependencies": {
223
+ "@babel/types": "^7.29.0"
224
+ },
225
+ "bin": {
226
+ "parser": "bin/babel-parser.js"
227
+ },
228
+ "engines": {
229
+ "node": ">=6.0.0"
230
+ }
231
+ },
232
+ "node_modules/@babel/plugin-transform-react-jsx-self": {
233
+ "version": "7.27.1",
234
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
235
+ "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
236
+ "dev": true,
237
+ "license": "MIT",
238
+ "dependencies": {
239
+ "@babel/helper-plugin-utils": "^7.27.1"
240
+ },
241
+ "engines": {
242
+ "node": ">=6.9.0"
243
+ },
244
+ "peerDependencies": {
245
+ "@babel/core": "^7.0.0-0"
246
+ }
247
+ },
248
+ "node_modules/@babel/plugin-transform-react-jsx-source": {
249
+ "version": "7.27.1",
250
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
251
+ "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
252
+ "dev": true,
253
+ "license": "MIT",
254
+ "dependencies": {
255
+ "@babel/helper-plugin-utils": "^7.27.1"
256
+ },
257
+ "engines": {
258
+ "node": ">=6.9.0"
259
+ },
260
+ "peerDependencies": {
261
+ "@babel/core": "^7.0.0-0"
262
+ }
263
+ },
264
+ "node_modules/@babel/template": {
265
+ "version": "7.28.6",
266
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
267
+ "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
268
+ "dev": true,
269
+ "license": "MIT",
270
+ "dependencies": {
271
+ "@babel/code-frame": "^7.28.6",
272
+ "@babel/parser": "^7.28.6",
273
+ "@babel/types": "^7.28.6"
274
+ },
275
+ "engines": {
276
+ "node": ">=6.9.0"
277
+ }
278
+ },
279
+ "node_modules/@babel/traverse": {
280
+ "version": "7.29.0",
281
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
282
+ "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
283
+ "dev": true,
284
+ "license": "MIT",
285
+ "dependencies": {
286
+ "@babel/code-frame": "^7.29.0",
287
+ "@babel/generator": "^7.29.0",
288
+ "@babel/helper-globals": "^7.28.0",
289
+ "@babel/parser": "^7.29.0",
290
+ "@babel/template": "^7.28.6",
291
+ "@babel/types": "^7.29.0",
292
+ "debug": "^4.3.1"
293
+ },
294
+ "engines": {
295
+ "node": ">=6.9.0"
296
+ }
297
+ },
298
+ "node_modules/@babel/types": {
299
+ "version": "7.29.0",
300
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
301
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
302
+ "dev": true,
303
+ "license": "MIT",
304
+ "dependencies": {
305
+ "@babel/helper-string-parser": "^7.27.1",
306
+ "@babel/helper-validator-identifier": "^7.28.5"
307
+ },
308
+ "engines": {
309
+ "node": ">=6.9.0"
310
+ }
311
+ },
312
+ "node_modules/@esbuild/aix-ppc64": {
313
+ "version": "0.25.12",
314
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
315
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
316
+ "cpu": [
317
+ "ppc64"
318
+ ],
319
+ "dev": true,
320
+ "license": "MIT",
321
+ "optional": true,
322
+ "os": [
323
+ "aix"
324
+ ],
325
+ "engines": {
326
+ "node": ">=18"
327
+ }
328
+ },
329
+ "node_modules/@esbuild/android-arm": {
330
+ "version": "0.25.12",
331
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
332
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
333
+ "cpu": [
334
+ "arm"
335
+ ],
336
+ "dev": true,
337
+ "license": "MIT",
338
+ "optional": true,
339
+ "os": [
340
+ "android"
341
+ ],
342
+ "engines": {
343
+ "node": ">=18"
344
+ }
345
+ },
346
+ "node_modules/@esbuild/android-arm64": {
347
+ "version": "0.25.12",
348
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
349
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
350
+ "cpu": [
351
+ "arm64"
352
+ ],
353
+ "dev": true,
354
+ "license": "MIT",
355
+ "optional": true,
356
+ "os": [
357
+ "android"
358
+ ],
359
+ "engines": {
360
+ "node": ">=18"
361
+ }
362
+ },
363
+ "node_modules/@esbuild/android-x64": {
364
+ "version": "0.25.12",
365
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
366
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
367
+ "cpu": [
368
+ "x64"
369
+ ],
370
+ "dev": true,
371
+ "license": "MIT",
372
+ "optional": true,
373
+ "os": [
374
+ "android"
375
+ ],
376
+ "engines": {
377
+ "node": ">=18"
378
+ }
379
+ },
380
+ "node_modules/@esbuild/darwin-arm64": {
381
+ "version": "0.25.12",
382
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
383
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
384
+ "cpu": [
385
+ "arm64"
386
+ ],
387
+ "dev": true,
388
+ "license": "MIT",
389
+ "optional": true,
390
+ "os": [
391
+ "darwin"
392
+ ],
393
+ "engines": {
394
+ "node": ">=18"
395
+ }
396
+ },
397
+ "node_modules/@esbuild/darwin-x64": {
398
+ "version": "0.25.12",
399
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
400
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
401
+ "cpu": [
402
+ "x64"
403
+ ],
404
+ "dev": true,
405
+ "license": "MIT",
406
+ "optional": true,
407
+ "os": [
408
+ "darwin"
409
+ ],
410
+ "engines": {
411
+ "node": ">=18"
412
+ }
413
+ },
414
+ "node_modules/@esbuild/freebsd-arm64": {
415
+ "version": "0.25.12",
416
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
417
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
418
+ "cpu": [
419
+ "arm64"
420
+ ],
421
+ "dev": true,
422
+ "license": "MIT",
423
+ "optional": true,
424
+ "os": [
425
+ "freebsd"
426
+ ],
427
+ "engines": {
428
+ "node": ">=18"
429
+ }
430
+ },
431
+ "node_modules/@esbuild/freebsd-x64": {
432
+ "version": "0.25.12",
433
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
434
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
435
+ "cpu": [
436
+ "x64"
437
+ ],
438
+ "dev": true,
439
+ "license": "MIT",
440
+ "optional": true,
441
+ "os": [
442
+ "freebsd"
443
+ ],
444
+ "engines": {
445
+ "node": ">=18"
446
+ }
447
+ },
448
+ "node_modules/@esbuild/linux-arm": {
449
+ "version": "0.25.12",
450
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
451
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
452
+ "cpu": [
453
+ "arm"
454
+ ],
455
+ "dev": true,
456
+ "license": "MIT",
457
+ "optional": true,
458
+ "os": [
459
+ "linux"
460
+ ],
461
+ "engines": {
462
+ "node": ">=18"
463
+ }
464
+ },
465
+ "node_modules/@esbuild/linux-arm64": {
466
+ "version": "0.25.12",
467
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
468
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
469
+ "cpu": [
470
+ "arm64"
471
+ ],
472
+ "dev": true,
473
+ "license": "MIT",
474
+ "optional": true,
475
+ "os": [
476
+ "linux"
477
+ ],
478
+ "engines": {
479
+ "node": ">=18"
480
+ }
481
+ },
482
+ "node_modules/@esbuild/linux-ia32": {
483
+ "version": "0.25.12",
484
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
485
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
486
+ "cpu": [
487
+ "ia32"
488
+ ],
489
+ "dev": true,
490
+ "license": "MIT",
491
+ "optional": true,
492
+ "os": [
493
+ "linux"
494
+ ],
495
+ "engines": {
496
+ "node": ">=18"
497
+ }
498
+ },
499
+ "node_modules/@esbuild/linux-loong64": {
500
+ "version": "0.25.12",
501
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
502
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
503
+ "cpu": [
504
+ "loong64"
505
+ ],
506
+ "dev": true,
507
+ "license": "MIT",
508
+ "optional": true,
509
+ "os": [
510
+ "linux"
511
+ ],
512
+ "engines": {
513
+ "node": ">=18"
514
+ }
515
+ },
516
+ "node_modules/@esbuild/linux-mips64el": {
517
+ "version": "0.25.12",
518
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
519
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
520
+ "cpu": [
521
+ "mips64el"
522
+ ],
523
+ "dev": true,
524
+ "license": "MIT",
525
+ "optional": true,
526
+ "os": [
527
+ "linux"
528
+ ],
529
+ "engines": {
530
+ "node": ">=18"
531
+ }
532
+ },
533
+ "node_modules/@esbuild/linux-ppc64": {
534
+ "version": "0.25.12",
535
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
536
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
537
+ "cpu": [
538
+ "ppc64"
539
+ ],
540
+ "dev": true,
541
+ "license": "MIT",
542
+ "optional": true,
543
+ "os": [
544
+ "linux"
545
+ ],
546
+ "engines": {
547
+ "node": ">=18"
548
+ }
549
+ },
550
+ "node_modules/@esbuild/linux-riscv64": {
551
+ "version": "0.25.12",
552
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
553
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
554
+ "cpu": [
555
+ "riscv64"
556
+ ],
557
+ "dev": true,
558
+ "license": "MIT",
559
+ "optional": true,
560
+ "os": [
561
+ "linux"
562
+ ],
563
+ "engines": {
564
+ "node": ">=18"
565
+ }
566
+ },
567
+ "node_modules/@esbuild/linux-s390x": {
568
+ "version": "0.25.12",
569
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
570
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
571
+ "cpu": [
572
+ "s390x"
573
+ ],
574
+ "dev": true,
575
+ "license": "MIT",
576
+ "optional": true,
577
+ "os": [
578
+ "linux"
579
+ ],
580
+ "engines": {
581
+ "node": ">=18"
582
+ }
583
+ },
584
+ "node_modules/@esbuild/linux-x64": {
585
+ "version": "0.25.12",
586
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
587
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
588
+ "cpu": [
589
+ "x64"
590
+ ],
591
+ "dev": true,
592
+ "license": "MIT",
593
+ "optional": true,
594
+ "os": [
595
+ "linux"
596
+ ],
597
+ "engines": {
598
+ "node": ">=18"
599
+ }
600
+ },
601
+ "node_modules/@esbuild/netbsd-arm64": {
602
+ "version": "0.25.12",
603
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
604
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
605
+ "cpu": [
606
+ "arm64"
607
+ ],
608
+ "dev": true,
609
+ "license": "MIT",
610
+ "optional": true,
611
+ "os": [
612
+ "netbsd"
613
+ ],
614
+ "engines": {
615
+ "node": ">=18"
616
+ }
617
+ },
618
+ "node_modules/@esbuild/netbsd-x64": {
619
+ "version": "0.25.12",
620
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
621
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
622
+ "cpu": [
623
+ "x64"
624
+ ],
625
+ "dev": true,
626
+ "license": "MIT",
627
+ "optional": true,
628
+ "os": [
629
+ "netbsd"
630
+ ],
631
+ "engines": {
632
+ "node": ">=18"
633
+ }
634
+ },
635
+ "node_modules/@esbuild/openbsd-arm64": {
636
+ "version": "0.25.12",
637
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
638
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
639
+ "cpu": [
640
+ "arm64"
641
+ ],
642
+ "dev": true,
643
+ "license": "MIT",
644
+ "optional": true,
645
+ "os": [
646
+ "openbsd"
647
+ ],
648
+ "engines": {
649
+ "node": ">=18"
650
+ }
651
+ },
652
+ "node_modules/@esbuild/openbsd-x64": {
653
+ "version": "0.25.12",
654
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
655
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
656
+ "cpu": [
657
+ "x64"
658
+ ],
659
+ "dev": true,
660
+ "license": "MIT",
661
+ "optional": true,
662
+ "os": [
663
+ "openbsd"
664
+ ],
665
+ "engines": {
666
+ "node": ">=18"
667
+ }
668
+ },
669
+ "node_modules/@esbuild/openharmony-arm64": {
670
+ "version": "0.25.12",
671
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
672
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
673
+ "cpu": [
674
+ "arm64"
675
+ ],
676
+ "dev": true,
677
+ "license": "MIT",
678
+ "optional": true,
679
+ "os": [
680
+ "openharmony"
681
+ ],
682
+ "engines": {
683
+ "node": ">=18"
684
+ }
685
+ },
686
+ "node_modules/@esbuild/sunos-x64": {
687
+ "version": "0.25.12",
688
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
689
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
690
+ "cpu": [
691
+ "x64"
692
+ ],
693
+ "dev": true,
694
+ "license": "MIT",
695
+ "optional": true,
696
+ "os": [
697
+ "sunos"
698
+ ],
699
+ "engines": {
700
+ "node": ">=18"
701
+ }
702
+ },
703
+ "node_modules/@esbuild/win32-arm64": {
704
+ "version": "0.25.12",
705
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
706
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
707
+ "cpu": [
708
+ "arm64"
709
+ ],
710
+ "dev": true,
711
+ "license": "MIT",
712
+ "optional": true,
713
+ "os": [
714
+ "win32"
715
+ ],
716
+ "engines": {
717
+ "node": ">=18"
718
+ }
719
+ },
720
+ "node_modules/@esbuild/win32-ia32": {
721
+ "version": "0.25.12",
722
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
723
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
724
+ "cpu": [
725
+ "ia32"
726
+ ],
727
+ "dev": true,
728
+ "license": "MIT",
729
+ "optional": true,
730
+ "os": [
731
+ "win32"
732
+ ],
733
+ "engines": {
734
+ "node": ">=18"
735
+ }
736
+ },
737
+ "node_modules/@esbuild/win32-x64": {
738
+ "version": "0.25.12",
739
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
740
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
741
+ "cpu": [
742
+ "x64"
743
+ ],
744
+ "dev": true,
745
+ "license": "MIT",
746
+ "optional": true,
747
+ "os": [
748
+ "win32"
749
+ ],
750
+ "engines": {
751
+ "node": ">=18"
752
+ }
753
+ },
754
+ "node_modules/@fontsource/inter": {
755
+ "version": "5.2.8",
756
+ "resolved": "https://registry.npmjs.org/@fontsource/inter/-/inter-5.2.8.tgz",
757
+ "integrity": "sha512-P6r5WnJoKiNVV+zvW2xM13gNdFhAEpQ9dQJHt3naLvfg+LkF2ldgSLiF4T41lf1SQCM9QmkqPTn4TH568IRagg==",
758
+ "license": "OFL-1.1",
759
+ "funding": {
760
+ "url": "https://github.com/sponsors/ayuhito"
761
+ }
762
+ },
763
+ "node_modules/@jridgewell/gen-mapping": {
764
+ "version": "0.3.13",
765
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
766
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
767
+ "dev": true,
768
+ "license": "MIT",
769
+ "dependencies": {
770
+ "@jridgewell/sourcemap-codec": "^1.5.0",
771
+ "@jridgewell/trace-mapping": "^0.3.24"
772
+ }
773
+ },
774
+ "node_modules/@jridgewell/remapping": {
775
+ "version": "2.3.5",
776
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
777
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
778
+ "dev": true,
779
+ "license": "MIT",
780
+ "dependencies": {
781
+ "@jridgewell/gen-mapping": "^0.3.5",
782
+ "@jridgewell/trace-mapping": "^0.3.24"
783
+ }
784
+ },
785
+ "node_modules/@jridgewell/resolve-uri": {
786
+ "version": "3.1.2",
787
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
788
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
789
+ "dev": true,
790
+ "license": "MIT",
791
+ "engines": {
792
+ "node": ">=6.0.0"
793
+ }
794
+ },
795
+ "node_modules/@jridgewell/sourcemap-codec": {
796
+ "version": "1.5.5",
797
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
798
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
799
+ "dev": true,
800
+ "license": "MIT"
801
+ },
802
+ "node_modules/@jridgewell/trace-mapping": {
803
+ "version": "0.3.31",
804
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
805
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
806
+ "dev": true,
807
+ "license": "MIT",
808
+ "dependencies": {
809
+ "@jridgewell/resolve-uri": "^3.1.0",
810
+ "@jridgewell/sourcemap-codec": "^1.4.14"
811
+ }
812
+ },
813
+ "node_modules/@rolldown/pluginutils": {
814
+ "version": "1.0.0-beta.27",
815
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
816
+ "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==",
817
+ "dev": true,
818
+ "license": "MIT"
819
+ },
820
+ "node_modules/@rollup/rollup-android-arm-eabi": {
821
+ "version": "4.60.1",
822
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
823
+ "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==",
824
+ "cpu": [
825
+ "arm"
826
+ ],
827
+ "dev": true,
828
+ "license": "MIT",
829
+ "optional": true,
830
+ "os": [
831
+ "android"
832
+ ]
833
+ },
834
+ "node_modules/@rollup/rollup-android-arm64": {
835
+ "version": "4.60.1",
836
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz",
837
+ "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==",
838
+ "cpu": [
839
+ "arm64"
840
+ ],
841
+ "dev": true,
842
+ "license": "MIT",
843
+ "optional": true,
844
+ "os": [
845
+ "android"
846
+ ]
847
+ },
848
+ "node_modules/@rollup/rollup-darwin-arm64": {
849
+ "version": "4.60.1",
850
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
851
+ "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
852
+ "cpu": [
853
+ "arm64"
854
+ ],
855
+ "dev": true,
856
+ "license": "MIT",
857
+ "optional": true,
858
+ "os": [
859
+ "darwin"
860
+ ]
861
+ },
862
+ "node_modules/@rollup/rollup-darwin-x64": {
863
+ "version": "4.60.1",
864
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz",
865
+ "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==",
866
+ "cpu": [
867
+ "x64"
868
+ ],
869
+ "dev": true,
870
+ "license": "MIT",
871
+ "optional": true,
872
+ "os": [
873
+ "darwin"
874
+ ]
875
+ },
876
+ "node_modules/@rollup/rollup-freebsd-arm64": {
877
+ "version": "4.60.1",
878
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz",
879
+ "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==",
880
+ "cpu": [
881
+ "arm64"
882
+ ],
883
+ "dev": true,
884
+ "license": "MIT",
885
+ "optional": true,
886
+ "os": [
887
+ "freebsd"
888
+ ]
889
+ },
890
+ "node_modules/@rollup/rollup-freebsd-x64": {
891
+ "version": "4.60.1",
892
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz",
893
+ "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==",
894
+ "cpu": [
895
+ "x64"
896
+ ],
897
+ "dev": true,
898
+ "license": "MIT",
899
+ "optional": true,
900
+ "os": [
901
+ "freebsd"
902
+ ]
903
+ },
904
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
905
+ "version": "4.60.1",
906
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz",
907
+ "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==",
908
+ "cpu": [
909
+ "arm"
910
+ ],
911
+ "dev": true,
912
+ "license": "MIT",
913
+ "optional": true,
914
+ "os": [
915
+ "linux"
916
+ ]
917
+ },
918
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
919
+ "version": "4.60.1",
920
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz",
921
+ "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==",
922
+ "cpu": [
923
+ "arm"
924
+ ],
925
+ "dev": true,
926
+ "license": "MIT",
927
+ "optional": true,
928
+ "os": [
929
+ "linux"
930
+ ]
931
+ },
932
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
933
+ "version": "4.60.1",
934
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz",
935
+ "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==",
936
+ "cpu": [
937
+ "arm64"
938
+ ],
939
+ "dev": true,
940
+ "license": "MIT",
941
+ "optional": true,
942
+ "os": [
943
+ "linux"
944
+ ]
945
+ },
946
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
947
+ "version": "4.60.1",
948
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz",
949
+ "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==",
950
+ "cpu": [
951
+ "arm64"
952
+ ],
953
+ "dev": true,
954
+ "license": "MIT",
955
+ "optional": true,
956
+ "os": [
957
+ "linux"
958
+ ]
959
+ },
960
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
961
+ "version": "4.60.1",
962
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz",
963
+ "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==",
964
+ "cpu": [
965
+ "loong64"
966
+ ],
967
+ "dev": true,
968
+ "license": "MIT",
969
+ "optional": true,
970
+ "os": [
971
+ "linux"
972
+ ]
973
+ },
974
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
975
+ "version": "4.60.1",
976
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz",
977
+ "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==",
978
+ "cpu": [
979
+ "loong64"
980
+ ],
981
+ "dev": true,
982
+ "license": "MIT",
983
+ "optional": true,
984
+ "os": [
985
+ "linux"
986
+ ]
987
+ },
988
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
989
+ "version": "4.60.1",
990
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz",
991
+ "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==",
992
+ "cpu": [
993
+ "ppc64"
994
+ ],
995
+ "dev": true,
996
+ "license": "MIT",
997
+ "optional": true,
998
+ "os": [
999
+ "linux"
1000
+ ]
1001
+ },
1002
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
1003
+ "version": "4.60.1",
1004
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz",
1005
+ "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==",
1006
+ "cpu": [
1007
+ "ppc64"
1008
+ ],
1009
+ "dev": true,
1010
+ "license": "MIT",
1011
+ "optional": true,
1012
+ "os": [
1013
+ "linux"
1014
+ ]
1015
+ },
1016
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1017
+ "version": "4.60.1",
1018
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz",
1019
+ "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==",
1020
+ "cpu": [
1021
+ "riscv64"
1022
+ ],
1023
+ "dev": true,
1024
+ "license": "MIT",
1025
+ "optional": true,
1026
+ "os": [
1027
+ "linux"
1028
+ ]
1029
+ },
1030
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
1031
+ "version": "4.60.1",
1032
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz",
1033
+ "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==",
1034
+ "cpu": [
1035
+ "riscv64"
1036
+ ],
1037
+ "dev": true,
1038
+ "license": "MIT",
1039
+ "optional": true,
1040
+ "os": [
1041
+ "linux"
1042
+ ]
1043
+ },
1044
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
1045
+ "version": "4.60.1",
1046
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz",
1047
+ "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==",
1048
+ "cpu": [
1049
+ "s390x"
1050
+ ],
1051
+ "dev": true,
1052
+ "license": "MIT",
1053
+ "optional": true,
1054
+ "os": [
1055
+ "linux"
1056
+ ]
1057
+ },
1058
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
1059
+ "version": "4.60.1",
1060
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz",
1061
+ "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==",
1062
+ "cpu": [
1063
+ "x64"
1064
+ ],
1065
+ "dev": true,
1066
+ "license": "MIT",
1067
+ "optional": true,
1068
+ "os": [
1069
+ "linux"
1070
+ ]
1071
+ },
1072
+ "node_modules/@rollup/rollup-linux-x64-musl": {
1073
+ "version": "4.60.1",
1074
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz",
1075
+ "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==",
1076
+ "cpu": [
1077
+ "x64"
1078
+ ],
1079
+ "dev": true,
1080
+ "license": "MIT",
1081
+ "optional": true,
1082
+ "os": [
1083
+ "linux"
1084
+ ]
1085
+ },
1086
+ "node_modules/@rollup/rollup-openbsd-x64": {
1087
+ "version": "4.60.1",
1088
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz",
1089
+ "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==",
1090
+ "cpu": [
1091
+ "x64"
1092
+ ],
1093
+ "dev": true,
1094
+ "license": "MIT",
1095
+ "optional": true,
1096
+ "os": [
1097
+ "openbsd"
1098
+ ]
1099
+ },
1100
+ "node_modules/@rollup/rollup-openharmony-arm64": {
1101
+ "version": "4.60.1",
1102
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz",
1103
+ "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==",
1104
+ "cpu": [
1105
+ "arm64"
1106
+ ],
1107
+ "dev": true,
1108
+ "license": "MIT",
1109
+ "optional": true,
1110
+ "os": [
1111
+ "openharmony"
1112
+ ]
1113
+ },
1114
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
1115
+ "version": "4.60.1",
1116
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz",
1117
+ "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==",
1118
+ "cpu": [
1119
+ "arm64"
1120
+ ],
1121
+ "dev": true,
1122
+ "license": "MIT",
1123
+ "optional": true,
1124
+ "os": [
1125
+ "win32"
1126
+ ]
1127
+ },
1128
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
1129
+ "version": "4.60.1",
1130
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz",
1131
+ "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==",
1132
+ "cpu": [
1133
+ "ia32"
1134
+ ],
1135
+ "dev": true,
1136
+ "license": "MIT",
1137
+ "optional": true,
1138
+ "os": [
1139
+ "win32"
1140
+ ]
1141
+ },
1142
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
1143
+ "version": "4.60.1",
1144
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
1145
+ "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
1146
+ "cpu": [
1147
+ "x64"
1148
+ ],
1149
+ "dev": true,
1150
+ "license": "MIT",
1151
+ "optional": true,
1152
+ "os": [
1153
+ "win32"
1154
+ ]
1155
+ },
1156
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
1157
+ "version": "4.60.1",
1158
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
1159
+ "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
1160
+ "cpu": [
1161
+ "x64"
1162
+ ],
1163
+ "dev": true,
1164
+ "license": "MIT",
1165
+ "optional": true,
1166
+ "os": [
1167
+ "win32"
1168
+ ]
1169
+ },
1170
+ "node_modules/@tailwindcss/node": {
1171
+ "version": "4.2.2",
1172
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz",
1173
+ "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==",
1174
+ "dev": true,
1175
+ "license": "MIT",
1176
+ "dependencies": {
1177
+ "@jridgewell/remapping": "^2.3.5",
1178
+ "enhanced-resolve": "^5.19.0",
1179
+ "jiti": "^2.6.1",
1180
+ "lightningcss": "1.32.0",
1181
+ "magic-string": "^0.30.21",
1182
+ "source-map-js": "^1.2.1",
1183
+ "tailwindcss": "4.2.2"
1184
+ }
1185
+ },
1186
+ "node_modules/@tailwindcss/oxide": {
1187
+ "version": "4.2.2",
1188
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz",
1189
+ "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==",
1190
+ "dev": true,
1191
+ "license": "MIT",
1192
+ "engines": {
1193
+ "node": ">= 20"
1194
+ },
1195
+ "optionalDependencies": {
1196
+ "@tailwindcss/oxide-android-arm64": "4.2.2",
1197
+ "@tailwindcss/oxide-darwin-arm64": "4.2.2",
1198
+ "@tailwindcss/oxide-darwin-x64": "4.2.2",
1199
+ "@tailwindcss/oxide-freebsd-x64": "4.2.2",
1200
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2",
1201
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2",
1202
+ "@tailwindcss/oxide-linux-arm64-musl": "4.2.2",
1203
+ "@tailwindcss/oxide-linux-x64-gnu": "4.2.2",
1204
+ "@tailwindcss/oxide-linux-x64-musl": "4.2.2",
1205
+ "@tailwindcss/oxide-wasm32-wasi": "4.2.2",
1206
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2",
1207
+ "@tailwindcss/oxide-win32-x64-msvc": "4.2.2"
1208
+ }
1209
+ },
1210
+ "node_modules/@tailwindcss/oxide-android-arm64": {
1211
+ "version": "4.2.2",
1212
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz",
1213
+ "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==",
1214
+ "cpu": [
1215
+ "arm64"
1216
+ ],
1217
+ "dev": true,
1218
+ "license": "MIT",
1219
+ "optional": true,
1220
+ "os": [
1221
+ "android"
1222
+ ],
1223
+ "engines": {
1224
+ "node": ">= 20"
1225
+ }
1226
+ },
1227
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
1228
+ "version": "4.2.2",
1229
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz",
1230
+ "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==",
1231
+ "cpu": [
1232
+ "arm64"
1233
+ ],
1234
+ "dev": true,
1235
+ "license": "MIT",
1236
+ "optional": true,
1237
+ "os": [
1238
+ "darwin"
1239
+ ],
1240
+ "engines": {
1241
+ "node": ">= 20"
1242
+ }
1243
+ },
1244
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
1245
+ "version": "4.2.2",
1246
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz",
1247
+ "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==",
1248
+ "cpu": [
1249
+ "x64"
1250
+ ],
1251
+ "dev": true,
1252
+ "license": "MIT",
1253
+ "optional": true,
1254
+ "os": [
1255
+ "darwin"
1256
+ ],
1257
+ "engines": {
1258
+ "node": ">= 20"
1259
+ }
1260
+ },
1261
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
1262
+ "version": "4.2.2",
1263
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz",
1264
+ "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==",
1265
+ "cpu": [
1266
+ "x64"
1267
+ ],
1268
+ "dev": true,
1269
+ "license": "MIT",
1270
+ "optional": true,
1271
+ "os": [
1272
+ "freebsd"
1273
+ ],
1274
+ "engines": {
1275
+ "node": ">= 20"
1276
+ }
1277
+ },
1278
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
1279
+ "version": "4.2.2",
1280
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz",
1281
+ "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==",
1282
+ "cpu": [
1283
+ "arm"
1284
+ ],
1285
+ "dev": true,
1286
+ "license": "MIT",
1287
+ "optional": true,
1288
+ "os": [
1289
+ "linux"
1290
+ ],
1291
+ "engines": {
1292
+ "node": ">= 20"
1293
+ }
1294
+ },
1295
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
1296
+ "version": "4.2.2",
1297
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz",
1298
+ "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==",
1299
+ "cpu": [
1300
+ "arm64"
1301
+ ],
1302
+ "dev": true,
1303
+ "license": "MIT",
1304
+ "optional": true,
1305
+ "os": [
1306
+ "linux"
1307
+ ],
1308
+ "engines": {
1309
+ "node": ">= 20"
1310
+ }
1311
+ },
1312
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
1313
+ "version": "4.2.2",
1314
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz",
1315
+ "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==",
1316
+ "cpu": [
1317
+ "arm64"
1318
+ ],
1319
+ "dev": true,
1320
+ "license": "MIT",
1321
+ "optional": true,
1322
+ "os": [
1323
+ "linux"
1324
+ ],
1325
+ "engines": {
1326
+ "node": ">= 20"
1327
+ }
1328
+ },
1329
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
1330
+ "version": "4.2.2",
1331
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz",
1332
+ "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==",
1333
+ "cpu": [
1334
+ "x64"
1335
+ ],
1336
+ "dev": true,
1337
+ "license": "MIT",
1338
+ "optional": true,
1339
+ "os": [
1340
+ "linux"
1341
+ ],
1342
+ "engines": {
1343
+ "node": ">= 20"
1344
+ }
1345
+ },
1346
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
1347
+ "version": "4.2.2",
1348
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz",
1349
+ "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==",
1350
+ "cpu": [
1351
+ "x64"
1352
+ ],
1353
+ "dev": true,
1354
+ "license": "MIT",
1355
+ "optional": true,
1356
+ "os": [
1357
+ "linux"
1358
+ ],
1359
+ "engines": {
1360
+ "node": ">= 20"
1361
+ }
1362
+ },
1363
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
1364
+ "version": "4.2.2",
1365
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz",
1366
+ "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==",
1367
+ "bundleDependencies": [
1368
+ "@napi-rs/wasm-runtime",
1369
+ "@emnapi/core",
1370
+ "@emnapi/runtime",
1371
+ "@tybys/wasm-util",
1372
+ "@emnapi/wasi-threads",
1373
+ "tslib"
1374
+ ],
1375
+ "cpu": [
1376
+ "wasm32"
1377
+ ],
1378
+ "dev": true,
1379
+ "license": "MIT",
1380
+ "optional": true,
1381
+ "dependencies": {
1382
+ "@emnapi/core": "^1.8.1",
1383
+ "@emnapi/runtime": "^1.8.1",
1384
+ "@emnapi/wasi-threads": "^1.1.0",
1385
+ "@napi-rs/wasm-runtime": "^1.1.1",
1386
+ "@tybys/wasm-util": "^0.10.1",
1387
+ "tslib": "^2.8.1"
1388
+ },
1389
+ "engines": {
1390
+ "node": ">=14.0.0"
1391
+ }
1392
+ },
1393
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
1394
+ "version": "4.2.2",
1395
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz",
1396
+ "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==",
1397
+ "cpu": [
1398
+ "arm64"
1399
+ ],
1400
+ "dev": true,
1401
+ "license": "MIT",
1402
+ "optional": true,
1403
+ "os": [
1404
+ "win32"
1405
+ ],
1406
+ "engines": {
1407
+ "node": ">= 20"
1408
+ }
1409
+ },
1410
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
1411
+ "version": "4.2.2",
1412
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz",
1413
+ "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==",
1414
+ "cpu": [
1415
+ "x64"
1416
+ ],
1417
+ "dev": true,
1418
+ "license": "MIT",
1419
+ "optional": true,
1420
+ "os": [
1421
+ "win32"
1422
+ ],
1423
+ "engines": {
1424
+ "node": ">= 20"
1425
+ }
1426
+ },
1427
+ "node_modules/@tailwindcss/vite": {
1428
+ "version": "4.2.2",
1429
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.2.tgz",
1430
+ "integrity": "sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==",
1431
+ "dev": true,
1432
+ "license": "MIT",
1433
+ "dependencies": {
1434
+ "@tailwindcss/node": "4.2.2",
1435
+ "@tailwindcss/oxide": "4.2.2",
1436
+ "tailwindcss": "4.2.2"
1437
+ },
1438
+ "peerDependencies": {
1439
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
1440
+ }
1441
+ },
1442
+ "node_modules/@tanstack/query-core": {
1443
+ "version": "5.96.2",
1444
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.96.2.tgz",
1445
+ "integrity": "sha512-hzI6cTVh4KNRk8UtoIBS7Lv9g6BnJPXvBKsvYH1aGWvv0347jT3BnSvztOE+kD76XGvZnRC/t6qdW1CaIfwCeA==",
1446
+ "license": "MIT",
1447
+ "funding": {
1448
+ "type": "github",
1449
+ "url": "https://github.com/sponsors/tannerlinsley"
1450
+ }
1451
+ },
1452
+ "node_modules/@tanstack/react-query": {
1453
+ "version": "5.96.2",
1454
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.96.2.tgz",
1455
+ "integrity": "sha512-sYyzzJT4G0g02azzJ8o55VFFV31XvFpdUpG+unxS0vSaYsJnSPKGoI6WdPwUucJL1wpgGfwfmntNX/Ub1uOViA==",
1456
+ "license": "MIT",
1457
+ "dependencies": {
1458
+ "@tanstack/query-core": "5.96.2"
1459
+ },
1460
+ "funding": {
1461
+ "type": "github",
1462
+ "url": "https://github.com/sponsors/tannerlinsley"
1463
+ },
1464
+ "peerDependencies": {
1465
+ "react": "^18 || ^19"
1466
+ }
1467
+ },
1468
+ "node_modules/@types/babel__core": {
1469
+ "version": "7.20.5",
1470
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
1471
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
1472
+ "dev": true,
1473
+ "license": "MIT",
1474
+ "dependencies": {
1475
+ "@babel/parser": "^7.20.7",
1476
+ "@babel/types": "^7.20.7",
1477
+ "@types/babel__generator": "*",
1478
+ "@types/babel__template": "*",
1479
+ "@types/babel__traverse": "*"
1480
+ }
1481
+ },
1482
+ "node_modules/@types/babel__generator": {
1483
+ "version": "7.27.0",
1484
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz",
1485
+ "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==",
1486
+ "dev": true,
1487
+ "license": "MIT",
1488
+ "dependencies": {
1489
+ "@babel/types": "^7.0.0"
1490
+ }
1491
+ },
1492
+ "node_modules/@types/babel__template": {
1493
+ "version": "7.4.4",
1494
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
1495
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
1496
+ "dev": true,
1497
+ "license": "MIT",
1498
+ "dependencies": {
1499
+ "@babel/parser": "^7.1.0",
1500
+ "@babel/types": "^7.0.0"
1501
+ }
1502
+ },
1503
+ "node_modules/@types/babel__traverse": {
1504
+ "version": "7.28.0",
1505
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz",
1506
+ "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==",
1507
+ "dev": true,
1508
+ "license": "MIT",
1509
+ "dependencies": {
1510
+ "@babel/types": "^7.28.2"
1511
+ }
1512
+ },
1513
+ "node_modules/@types/estree": {
1514
+ "version": "1.0.8",
1515
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1516
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1517
+ "dev": true,
1518
+ "license": "MIT"
1519
+ },
1520
+ "node_modules/@types/node": {
1521
+ "version": "25.5.2",
1522
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz",
1523
+ "integrity": "sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==",
1524
+ "dev": true,
1525
+ "license": "MIT",
1526
+ "dependencies": {
1527
+ "undici-types": "~7.18.0"
1528
+ }
1529
+ },
1530
+ "node_modules/@types/prop-types": {
1531
+ "version": "15.7.15",
1532
+ "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
1533
+ "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
1534
+ "devOptional": true,
1535
+ "license": "MIT"
1536
+ },
1537
+ "node_modules/@types/react": {
1538
+ "version": "18.3.28",
1539
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
1540
+ "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
1541
+ "devOptional": true,
1542
+ "license": "MIT",
1543
+ "dependencies": {
1544
+ "@types/prop-types": "*",
1545
+ "csstype": "^3.2.2"
1546
+ }
1547
+ },
1548
+ "node_modules/@types/react-dom": {
1549
+ "version": "18.3.7",
1550
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
1551
+ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
1552
+ "dev": true,
1553
+ "license": "MIT",
1554
+ "peerDependencies": {
1555
+ "@types/react": "^18.0.0"
1556
+ }
1557
+ },
1558
+ "node_modules/@vitejs/plugin-react": {
1559
+ "version": "4.7.0",
1560
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
1561
+ "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==",
1562
+ "dev": true,
1563
+ "license": "MIT",
1564
+ "dependencies": {
1565
+ "@babel/core": "^7.28.0",
1566
+ "@babel/plugin-transform-react-jsx-self": "^7.27.1",
1567
+ "@babel/plugin-transform-react-jsx-source": "^7.27.1",
1568
+ "@rolldown/pluginutils": "1.0.0-beta.27",
1569
+ "@types/babel__core": "^7.20.5",
1570
+ "react-refresh": "^0.17.0"
1571
+ },
1572
+ "engines": {
1573
+ "node": "^14.18.0 || >=16.0.0"
1574
+ },
1575
+ "peerDependencies": {
1576
+ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
1577
+ }
1578
+ },
1579
+ "node_modules/baseline-browser-mapping": {
1580
+ "version": "2.10.14",
1581
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.14.tgz",
1582
+ "integrity": "sha512-fOVLPAsFTsQfuCkvahZkzq6nf8KvGWanlYoTh0SVA0A/PIUxQGU2AOZAoD95n2gFLVDW/jP6sbGLny95nmEuHA==",
1583
+ "dev": true,
1584
+ "license": "Apache-2.0",
1585
+ "bin": {
1586
+ "baseline-browser-mapping": "dist/cli.cjs"
1587
+ },
1588
+ "engines": {
1589
+ "node": ">=6.0.0"
1590
+ }
1591
+ },
1592
+ "node_modules/browserslist": {
1593
+ "version": "4.28.2",
1594
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz",
1595
+ "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==",
1596
+ "dev": true,
1597
+ "funding": [
1598
+ {
1599
+ "type": "opencollective",
1600
+ "url": "https://opencollective.com/browserslist"
1601
+ },
1602
+ {
1603
+ "type": "tidelift",
1604
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
1605
+ },
1606
+ {
1607
+ "type": "github",
1608
+ "url": "https://github.com/sponsors/ai"
1609
+ }
1610
+ ],
1611
+ "license": "MIT",
1612
+ "dependencies": {
1613
+ "baseline-browser-mapping": "^2.10.12",
1614
+ "caniuse-lite": "^1.0.30001782",
1615
+ "electron-to-chromium": "^1.5.328",
1616
+ "node-releases": "^2.0.36",
1617
+ "update-browserslist-db": "^1.2.3"
1618
+ },
1619
+ "bin": {
1620
+ "browserslist": "cli.js"
1621
+ },
1622
+ "engines": {
1623
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
1624
+ }
1625
+ },
1626
+ "node_modules/caniuse-lite": {
1627
+ "version": "1.0.30001785",
1628
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001785.tgz",
1629
+ "integrity": "sha512-blhOL/WNR+Km1RI/LCVAvA73xplXA7ZbjzI4YkMK9pa6T/P3F2GxjNpEkyw5repTw9IvkyrjyHpwjnhZ5FOvYQ==",
1630
+ "dev": true,
1631
+ "funding": [
1632
+ {
1633
+ "type": "opencollective",
1634
+ "url": "https://opencollective.com/browserslist"
1635
+ },
1636
+ {
1637
+ "type": "tidelift",
1638
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
1639
+ },
1640
+ {
1641
+ "type": "github",
1642
+ "url": "https://github.com/sponsors/ai"
1643
+ }
1644
+ ],
1645
+ "license": "CC-BY-4.0"
1646
+ },
1647
+ "node_modules/clsx": {
1648
+ "version": "2.1.1",
1649
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
1650
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
1651
+ "license": "MIT",
1652
+ "engines": {
1653
+ "node": ">=6"
1654
+ }
1655
+ },
1656
+ "node_modules/convert-source-map": {
1657
+ "version": "2.0.0",
1658
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
1659
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
1660
+ "dev": true,
1661
+ "license": "MIT"
1662
+ },
1663
+ "node_modules/csstype": {
1664
+ "version": "3.2.3",
1665
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
1666
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
1667
+ "devOptional": true,
1668
+ "license": "MIT"
1669
+ },
1670
+ "node_modules/debug": {
1671
+ "version": "4.4.3",
1672
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1673
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1674
+ "dev": true,
1675
+ "license": "MIT",
1676
+ "dependencies": {
1677
+ "ms": "^2.1.3"
1678
+ },
1679
+ "engines": {
1680
+ "node": ">=6.0"
1681
+ },
1682
+ "peerDependenciesMeta": {
1683
+ "supports-color": {
1684
+ "optional": true
1685
+ }
1686
+ }
1687
+ },
1688
+ "node_modules/detect-libc": {
1689
+ "version": "2.1.2",
1690
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
1691
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
1692
+ "dev": true,
1693
+ "license": "Apache-2.0",
1694
+ "engines": {
1695
+ "node": ">=8"
1696
+ }
1697
+ },
1698
+ "node_modules/electron-to-chromium": {
1699
+ "version": "1.5.331",
1700
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.331.tgz",
1701
+ "integrity": "sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==",
1702
+ "dev": true,
1703
+ "license": "ISC"
1704
+ },
1705
+ "node_modules/enhanced-resolve": {
1706
+ "version": "5.20.1",
1707
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
1708
+ "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==",
1709
+ "dev": true,
1710
+ "license": "MIT",
1711
+ "dependencies": {
1712
+ "graceful-fs": "^4.2.4",
1713
+ "tapable": "^2.3.0"
1714
+ },
1715
+ "engines": {
1716
+ "node": ">=10.13.0"
1717
+ }
1718
+ },
1719
+ "node_modules/esbuild": {
1720
+ "version": "0.25.12",
1721
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
1722
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
1723
+ "dev": true,
1724
+ "hasInstallScript": true,
1725
+ "license": "MIT",
1726
+ "bin": {
1727
+ "esbuild": "bin/esbuild"
1728
+ },
1729
+ "engines": {
1730
+ "node": ">=18"
1731
+ },
1732
+ "optionalDependencies": {
1733
+ "@esbuild/aix-ppc64": "0.25.12",
1734
+ "@esbuild/android-arm": "0.25.12",
1735
+ "@esbuild/android-arm64": "0.25.12",
1736
+ "@esbuild/android-x64": "0.25.12",
1737
+ "@esbuild/darwin-arm64": "0.25.12",
1738
+ "@esbuild/darwin-x64": "0.25.12",
1739
+ "@esbuild/freebsd-arm64": "0.25.12",
1740
+ "@esbuild/freebsd-x64": "0.25.12",
1741
+ "@esbuild/linux-arm": "0.25.12",
1742
+ "@esbuild/linux-arm64": "0.25.12",
1743
+ "@esbuild/linux-ia32": "0.25.12",
1744
+ "@esbuild/linux-loong64": "0.25.12",
1745
+ "@esbuild/linux-mips64el": "0.25.12",
1746
+ "@esbuild/linux-ppc64": "0.25.12",
1747
+ "@esbuild/linux-riscv64": "0.25.12",
1748
+ "@esbuild/linux-s390x": "0.25.12",
1749
+ "@esbuild/linux-x64": "0.25.12",
1750
+ "@esbuild/netbsd-arm64": "0.25.12",
1751
+ "@esbuild/netbsd-x64": "0.25.12",
1752
+ "@esbuild/openbsd-arm64": "0.25.12",
1753
+ "@esbuild/openbsd-x64": "0.25.12",
1754
+ "@esbuild/openharmony-arm64": "0.25.12",
1755
+ "@esbuild/sunos-x64": "0.25.12",
1756
+ "@esbuild/win32-arm64": "0.25.12",
1757
+ "@esbuild/win32-ia32": "0.25.12",
1758
+ "@esbuild/win32-x64": "0.25.12"
1759
+ }
1760
+ },
1761
+ "node_modules/escalade": {
1762
+ "version": "3.2.0",
1763
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
1764
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
1765
+ "dev": true,
1766
+ "license": "MIT",
1767
+ "engines": {
1768
+ "node": ">=6"
1769
+ }
1770
+ },
1771
+ "node_modules/fdir": {
1772
+ "version": "6.5.0",
1773
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
1774
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
1775
+ "dev": true,
1776
+ "license": "MIT",
1777
+ "engines": {
1778
+ "node": ">=12.0.0"
1779
+ },
1780
+ "peerDependencies": {
1781
+ "picomatch": "^3 || ^4"
1782
+ },
1783
+ "peerDependenciesMeta": {
1784
+ "picomatch": {
1785
+ "optional": true
1786
+ }
1787
+ }
1788
+ },
1789
+ "node_modules/fsevents": {
1790
+ "version": "2.3.3",
1791
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1792
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1793
+ "dev": true,
1794
+ "hasInstallScript": true,
1795
+ "license": "MIT",
1796
+ "optional": true,
1797
+ "os": [
1798
+ "darwin"
1799
+ ],
1800
+ "engines": {
1801
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1802
+ }
1803
+ },
1804
+ "node_modules/gensync": {
1805
+ "version": "1.0.0-beta.2",
1806
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
1807
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
1808
+ "dev": true,
1809
+ "license": "MIT",
1810
+ "engines": {
1811
+ "node": ">=6.9.0"
1812
+ }
1813
+ },
1814
+ "node_modules/graceful-fs": {
1815
+ "version": "4.2.11",
1816
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
1817
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
1818
+ "dev": true,
1819
+ "license": "ISC"
1820
+ },
1821
+ "node_modules/jiti": {
1822
+ "version": "2.6.1",
1823
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
1824
+ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
1825
+ "dev": true,
1826
+ "license": "MIT",
1827
+ "bin": {
1828
+ "jiti": "lib/jiti-cli.mjs"
1829
+ }
1830
+ },
1831
+ "node_modules/js-tokens": {
1832
+ "version": "4.0.0",
1833
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1834
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1835
+ "license": "MIT"
1836
+ },
1837
+ "node_modules/jsesc": {
1838
+ "version": "3.1.0",
1839
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
1840
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
1841
+ "dev": true,
1842
+ "license": "MIT",
1843
+ "bin": {
1844
+ "jsesc": "bin/jsesc"
1845
+ },
1846
+ "engines": {
1847
+ "node": ">=6"
1848
+ }
1849
+ },
1850
+ "node_modules/json5": {
1851
+ "version": "2.2.3",
1852
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
1853
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
1854
+ "dev": true,
1855
+ "license": "MIT",
1856
+ "bin": {
1857
+ "json5": "lib/cli.js"
1858
+ },
1859
+ "engines": {
1860
+ "node": ">=6"
1861
+ }
1862
+ },
1863
+ "node_modules/lightningcss": {
1864
+ "version": "1.32.0",
1865
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
1866
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
1867
+ "dev": true,
1868
+ "license": "MPL-2.0",
1869
+ "dependencies": {
1870
+ "detect-libc": "^2.0.3"
1871
+ },
1872
+ "engines": {
1873
+ "node": ">= 12.0.0"
1874
+ },
1875
+ "funding": {
1876
+ "type": "opencollective",
1877
+ "url": "https://opencollective.com/parcel"
1878
+ },
1879
+ "optionalDependencies": {
1880
+ "lightningcss-android-arm64": "1.32.0",
1881
+ "lightningcss-darwin-arm64": "1.32.0",
1882
+ "lightningcss-darwin-x64": "1.32.0",
1883
+ "lightningcss-freebsd-x64": "1.32.0",
1884
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
1885
+ "lightningcss-linux-arm64-gnu": "1.32.0",
1886
+ "lightningcss-linux-arm64-musl": "1.32.0",
1887
+ "lightningcss-linux-x64-gnu": "1.32.0",
1888
+ "lightningcss-linux-x64-musl": "1.32.0",
1889
+ "lightningcss-win32-arm64-msvc": "1.32.0",
1890
+ "lightningcss-win32-x64-msvc": "1.32.0"
1891
+ }
1892
+ },
1893
+ "node_modules/lightningcss-android-arm64": {
1894
+ "version": "1.32.0",
1895
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
1896
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
1897
+ "cpu": [
1898
+ "arm64"
1899
+ ],
1900
+ "dev": true,
1901
+ "license": "MPL-2.0",
1902
+ "optional": true,
1903
+ "os": [
1904
+ "android"
1905
+ ],
1906
+ "engines": {
1907
+ "node": ">= 12.0.0"
1908
+ },
1909
+ "funding": {
1910
+ "type": "opencollective",
1911
+ "url": "https://opencollective.com/parcel"
1912
+ }
1913
+ },
1914
+ "node_modules/lightningcss-darwin-arm64": {
1915
+ "version": "1.32.0",
1916
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
1917
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
1918
+ "cpu": [
1919
+ "arm64"
1920
+ ],
1921
+ "dev": true,
1922
+ "license": "MPL-2.0",
1923
+ "optional": true,
1924
+ "os": [
1925
+ "darwin"
1926
+ ],
1927
+ "engines": {
1928
+ "node": ">= 12.0.0"
1929
+ },
1930
+ "funding": {
1931
+ "type": "opencollective",
1932
+ "url": "https://opencollective.com/parcel"
1933
+ }
1934
+ },
1935
+ "node_modules/lightningcss-darwin-x64": {
1936
+ "version": "1.32.0",
1937
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
1938
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
1939
+ "cpu": [
1940
+ "x64"
1941
+ ],
1942
+ "dev": true,
1943
+ "license": "MPL-2.0",
1944
+ "optional": true,
1945
+ "os": [
1946
+ "darwin"
1947
+ ],
1948
+ "engines": {
1949
+ "node": ">= 12.0.0"
1950
+ },
1951
+ "funding": {
1952
+ "type": "opencollective",
1953
+ "url": "https://opencollective.com/parcel"
1954
+ }
1955
+ },
1956
+ "node_modules/lightningcss-freebsd-x64": {
1957
+ "version": "1.32.0",
1958
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
1959
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
1960
+ "cpu": [
1961
+ "x64"
1962
+ ],
1963
+ "dev": true,
1964
+ "license": "MPL-2.0",
1965
+ "optional": true,
1966
+ "os": [
1967
+ "freebsd"
1968
+ ],
1969
+ "engines": {
1970
+ "node": ">= 12.0.0"
1971
+ },
1972
+ "funding": {
1973
+ "type": "opencollective",
1974
+ "url": "https://opencollective.com/parcel"
1975
+ }
1976
+ },
1977
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
1978
+ "version": "1.32.0",
1979
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
1980
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
1981
+ "cpu": [
1982
+ "arm"
1983
+ ],
1984
+ "dev": true,
1985
+ "license": "MPL-2.0",
1986
+ "optional": true,
1987
+ "os": [
1988
+ "linux"
1989
+ ],
1990
+ "engines": {
1991
+ "node": ">= 12.0.0"
1992
+ },
1993
+ "funding": {
1994
+ "type": "opencollective",
1995
+ "url": "https://opencollective.com/parcel"
1996
+ }
1997
+ },
1998
+ "node_modules/lightningcss-linux-arm64-gnu": {
1999
+ "version": "1.32.0",
2000
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
2001
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
2002
+ "cpu": [
2003
+ "arm64"
2004
+ ],
2005
+ "dev": true,
2006
+ "license": "MPL-2.0",
2007
+ "optional": true,
2008
+ "os": [
2009
+ "linux"
2010
+ ],
2011
+ "engines": {
2012
+ "node": ">= 12.0.0"
2013
+ },
2014
+ "funding": {
2015
+ "type": "opencollective",
2016
+ "url": "https://opencollective.com/parcel"
2017
+ }
2018
+ },
2019
+ "node_modules/lightningcss-linux-arm64-musl": {
2020
+ "version": "1.32.0",
2021
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
2022
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
2023
+ "cpu": [
2024
+ "arm64"
2025
+ ],
2026
+ "dev": true,
2027
+ "license": "MPL-2.0",
2028
+ "optional": true,
2029
+ "os": [
2030
+ "linux"
2031
+ ],
2032
+ "engines": {
2033
+ "node": ">= 12.0.0"
2034
+ },
2035
+ "funding": {
2036
+ "type": "opencollective",
2037
+ "url": "https://opencollective.com/parcel"
2038
+ }
2039
+ },
2040
+ "node_modules/lightningcss-linux-x64-gnu": {
2041
+ "version": "1.32.0",
2042
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
2043
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
2044
+ "cpu": [
2045
+ "x64"
2046
+ ],
2047
+ "dev": true,
2048
+ "license": "MPL-2.0",
2049
+ "optional": true,
2050
+ "os": [
2051
+ "linux"
2052
+ ],
2053
+ "engines": {
2054
+ "node": ">= 12.0.0"
2055
+ },
2056
+ "funding": {
2057
+ "type": "opencollective",
2058
+ "url": "https://opencollective.com/parcel"
2059
+ }
2060
+ },
2061
+ "node_modules/lightningcss-linux-x64-musl": {
2062
+ "version": "1.32.0",
2063
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
2064
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
2065
+ "cpu": [
2066
+ "x64"
2067
+ ],
2068
+ "dev": true,
2069
+ "license": "MPL-2.0",
2070
+ "optional": true,
2071
+ "os": [
2072
+ "linux"
2073
+ ],
2074
+ "engines": {
2075
+ "node": ">= 12.0.0"
2076
+ },
2077
+ "funding": {
2078
+ "type": "opencollective",
2079
+ "url": "https://opencollective.com/parcel"
2080
+ }
2081
+ },
2082
+ "node_modules/lightningcss-win32-arm64-msvc": {
2083
+ "version": "1.32.0",
2084
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
2085
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
2086
+ "cpu": [
2087
+ "arm64"
2088
+ ],
2089
+ "dev": true,
2090
+ "license": "MPL-2.0",
2091
+ "optional": true,
2092
+ "os": [
2093
+ "win32"
2094
+ ],
2095
+ "engines": {
2096
+ "node": ">= 12.0.0"
2097
+ },
2098
+ "funding": {
2099
+ "type": "opencollective",
2100
+ "url": "https://opencollective.com/parcel"
2101
+ }
2102
+ },
2103
+ "node_modules/lightningcss-win32-x64-msvc": {
2104
+ "version": "1.32.0",
2105
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
2106
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
2107
+ "cpu": [
2108
+ "x64"
2109
+ ],
2110
+ "dev": true,
2111
+ "license": "MPL-2.0",
2112
+ "optional": true,
2113
+ "os": [
2114
+ "win32"
2115
+ ],
2116
+ "engines": {
2117
+ "node": ">= 12.0.0"
2118
+ },
2119
+ "funding": {
2120
+ "type": "opencollective",
2121
+ "url": "https://opencollective.com/parcel"
2122
+ }
2123
+ },
2124
+ "node_modules/loose-envify": {
2125
+ "version": "1.4.0",
2126
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
2127
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
2128
+ "license": "MIT",
2129
+ "dependencies": {
2130
+ "js-tokens": "^3.0.0 || ^4.0.0"
2131
+ },
2132
+ "bin": {
2133
+ "loose-envify": "cli.js"
2134
+ }
2135
+ },
2136
+ "node_modules/lru-cache": {
2137
+ "version": "5.1.1",
2138
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
2139
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
2140
+ "dev": true,
2141
+ "license": "ISC",
2142
+ "dependencies": {
2143
+ "yallist": "^3.0.2"
2144
+ }
2145
+ },
2146
+ "node_modules/lucide-react": {
2147
+ "version": "0.475.0",
2148
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.475.0.tgz",
2149
+ "integrity": "sha512-NJzvVu1HwFVeZ+Gwq2q00KygM1aBhy/ZrhY9FsAgJtpB+E4R7uxRk9M2iKvHa6/vNxZydIB59htha4c2vvwvVg==",
2150
+ "license": "ISC",
2151
+ "peerDependencies": {
2152
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
2153
+ }
2154
+ },
2155
+ "node_modules/magic-string": {
2156
+ "version": "0.30.21",
2157
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
2158
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
2159
+ "dev": true,
2160
+ "license": "MIT",
2161
+ "dependencies": {
2162
+ "@jridgewell/sourcemap-codec": "^1.5.5"
2163
+ }
2164
+ },
2165
+ "node_modules/ms": {
2166
+ "version": "2.1.3",
2167
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
2168
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
2169
+ "dev": true,
2170
+ "license": "MIT"
2171
+ },
2172
+ "node_modules/nanoid": {
2173
+ "version": "3.3.11",
2174
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
2175
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
2176
+ "dev": true,
2177
+ "funding": [
2178
+ {
2179
+ "type": "github",
2180
+ "url": "https://github.com/sponsors/ai"
2181
+ }
2182
+ ],
2183
+ "license": "MIT",
2184
+ "bin": {
2185
+ "nanoid": "bin/nanoid.cjs"
2186
+ },
2187
+ "engines": {
2188
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2189
+ }
2190
+ },
2191
+ "node_modules/node-releases": {
2192
+ "version": "2.0.37",
2193
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.37.tgz",
2194
+ "integrity": "sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==",
2195
+ "dev": true,
2196
+ "license": "MIT"
2197
+ },
2198
+ "node_modules/picocolors": {
2199
+ "version": "1.1.1",
2200
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
2201
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
2202
+ "dev": true,
2203
+ "license": "ISC"
2204
+ },
2205
+ "node_modules/picomatch": {
2206
+ "version": "4.0.4",
2207
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
2208
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
2209
+ "dev": true,
2210
+ "license": "MIT",
2211
+ "engines": {
2212
+ "node": ">=12"
2213
+ },
2214
+ "funding": {
2215
+ "url": "https://github.com/sponsors/jonschlinkert"
2216
+ }
2217
+ },
2218
+ "node_modules/postcss": {
2219
+ "version": "8.5.8",
2220
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
2221
+ "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
2222
+ "dev": true,
2223
+ "funding": [
2224
+ {
2225
+ "type": "opencollective",
2226
+ "url": "https://opencollective.com/postcss/"
2227
+ },
2228
+ {
2229
+ "type": "tidelift",
2230
+ "url": "https://tidelift.com/funding/github/npm/postcss"
2231
+ },
2232
+ {
2233
+ "type": "github",
2234
+ "url": "https://github.com/sponsors/ai"
2235
+ }
2236
+ ],
2237
+ "license": "MIT",
2238
+ "dependencies": {
2239
+ "nanoid": "^3.3.11",
2240
+ "picocolors": "^1.1.1",
2241
+ "source-map-js": "^1.2.1"
2242
+ },
2243
+ "engines": {
2244
+ "node": "^10 || ^12 || >=14"
2245
+ }
2246
+ },
2247
+ "node_modules/react": {
2248
+ "version": "18.3.1",
2249
+ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
2250
+ "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
2251
+ "license": "MIT",
2252
+ "dependencies": {
2253
+ "loose-envify": "^1.1.0"
2254
+ },
2255
+ "engines": {
2256
+ "node": ">=0.10.0"
2257
+ }
2258
+ },
2259
+ "node_modules/react-dom": {
2260
+ "version": "18.3.1",
2261
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
2262
+ "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
2263
+ "license": "MIT",
2264
+ "dependencies": {
2265
+ "loose-envify": "^1.1.0",
2266
+ "scheduler": "^0.23.2"
2267
+ },
2268
+ "peerDependencies": {
2269
+ "react": "^18.3.1"
2270
+ }
2271
+ },
2272
+ "node_modules/react-refresh": {
2273
+ "version": "0.17.0",
2274
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz",
2275
+ "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==",
2276
+ "dev": true,
2277
+ "license": "MIT",
2278
+ "engines": {
2279
+ "node": ">=0.10.0"
2280
+ }
2281
+ },
2282
+ "node_modules/rollup": {
2283
+ "version": "4.60.1",
2284
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz",
2285
+ "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
2286
+ "dev": true,
2287
+ "license": "MIT",
2288
+ "dependencies": {
2289
+ "@types/estree": "1.0.8"
2290
+ },
2291
+ "bin": {
2292
+ "rollup": "dist/bin/rollup"
2293
+ },
2294
+ "engines": {
2295
+ "node": ">=18.0.0",
2296
+ "npm": ">=8.0.0"
2297
+ },
2298
+ "optionalDependencies": {
2299
+ "@rollup/rollup-android-arm-eabi": "4.60.1",
2300
+ "@rollup/rollup-android-arm64": "4.60.1",
2301
+ "@rollup/rollup-darwin-arm64": "4.60.1",
2302
+ "@rollup/rollup-darwin-x64": "4.60.1",
2303
+ "@rollup/rollup-freebsd-arm64": "4.60.1",
2304
+ "@rollup/rollup-freebsd-x64": "4.60.1",
2305
+ "@rollup/rollup-linux-arm-gnueabihf": "4.60.1",
2306
+ "@rollup/rollup-linux-arm-musleabihf": "4.60.1",
2307
+ "@rollup/rollup-linux-arm64-gnu": "4.60.1",
2308
+ "@rollup/rollup-linux-arm64-musl": "4.60.1",
2309
+ "@rollup/rollup-linux-loong64-gnu": "4.60.1",
2310
+ "@rollup/rollup-linux-loong64-musl": "4.60.1",
2311
+ "@rollup/rollup-linux-ppc64-gnu": "4.60.1",
2312
+ "@rollup/rollup-linux-ppc64-musl": "4.60.1",
2313
+ "@rollup/rollup-linux-riscv64-gnu": "4.60.1",
2314
+ "@rollup/rollup-linux-riscv64-musl": "4.60.1",
2315
+ "@rollup/rollup-linux-s390x-gnu": "4.60.1",
2316
+ "@rollup/rollup-linux-x64-gnu": "4.60.1",
2317
+ "@rollup/rollup-linux-x64-musl": "4.60.1",
2318
+ "@rollup/rollup-openbsd-x64": "4.60.1",
2319
+ "@rollup/rollup-openharmony-arm64": "4.60.1",
2320
+ "@rollup/rollup-win32-arm64-msvc": "4.60.1",
2321
+ "@rollup/rollup-win32-ia32-msvc": "4.60.1",
2322
+ "@rollup/rollup-win32-x64-gnu": "4.60.1",
2323
+ "@rollup/rollup-win32-x64-msvc": "4.60.1",
2324
+ "fsevents": "~2.3.2"
2325
+ }
2326
+ },
2327
+ "node_modules/scheduler": {
2328
+ "version": "0.23.2",
2329
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
2330
+ "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
2331
+ "license": "MIT",
2332
+ "dependencies": {
2333
+ "loose-envify": "^1.1.0"
2334
+ }
2335
+ },
2336
+ "node_modules/semver": {
2337
+ "version": "6.3.1",
2338
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
2339
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
2340
+ "dev": true,
2341
+ "license": "ISC",
2342
+ "bin": {
2343
+ "semver": "bin/semver.js"
2344
+ }
2345
+ },
2346
+ "node_modules/source-map-js": {
2347
+ "version": "1.2.1",
2348
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
2349
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
2350
+ "dev": true,
2351
+ "license": "BSD-3-Clause",
2352
+ "engines": {
2353
+ "node": ">=0.10.0"
2354
+ }
2355
+ },
2356
+ "node_modules/tailwindcss": {
2357
+ "version": "4.2.2",
2358
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
2359
+ "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
2360
+ "dev": true,
2361
+ "license": "MIT"
2362
+ },
2363
+ "node_modules/tapable": {
2364
+ "version": "2.3.2",
2365
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.2.tgz",
2366
+ "integrity": "sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==",
2367
+ "dev": true,
2368
+ "license": "MIT",
2369
+ "engines": {
2370
+ "node": ">=6"
2371
+ },
2372
+ "funding": {
2373
+ "type": "opencollective",
2374
+ "url": "https://opencollective.com/webpack"
2375
+ }
2376
+ },
2377
+ "node_modules/tinyglobby": {
2378
+ "version": "0.2.15",
2379
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
2380
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
2381
+ "dev": true,
2382
+ "license": "MIT",
2383
+ "dependencies": {
2384
+ "fdir": "^6.5.0",
2385
+ "picomatch": "^4.0.3"
2386
+ },
2387
+ "engines": {
2388
+ "node": ">=12.0.0"
2389
+ },
2390
+ "funding": {
2391
+ "url": "https://github.com/sponsors/SuperchupuDev"
2392
+ }
2393
+ },
2394
+ "node_modules/typescript": {
2395
+ "version": "5.9.3",
2396
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
2397
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
2398
+ "dev": true,
2399
+ "license": "Apache-2.0",
2400
+ "bin": {
2401
+ "tsc": "bin/tsc",
2402
+ "tsserver": "bin/tsserver"
2403
+ },
2404
+ "engines": {
2405
+ "node": ">=14.17"
2406
+ }
2407
+ },
2408
+ "node_modules/undici-types": {
2409
+ "version": "7.18.2",
2410
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
2411
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
2412
+ "dev": true,
2413
+ "license": "MIT"
2414
+ },
2415
+ "node_modules/update-browserslist-db": {
2416
+ "version": "1.2.3",
2417
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
2418
+ "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==",
2419
+ "dev": true,
2420
+ "funding": [
2421
+ {
2422
+ "type": "opencollective",
2423
+ "url": "https://opencollective.com/browserslist"
2424
+ },
2425
+ {
2426
+ "type": "tidelift",
2427
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
2428
+ },
2429
+ {
2430
+ "type": "github",
2431
+ "url": "https://github.com/sponsors/ai"
2432
+ }
2433
+ ],
2434
+ "license": "MIT",
2435
+ "dependencies": {
2436
+ "escalade": "^3.2.0",
2437
+ "picocolors": "^1.1.1"
2438
+ },
2439
+ "bin": {
2440
+ "update-browserslist-db": "cli.js"
2441
+ },
2442
+ "peerDependencies": {
2443
+ "browserslist": ">= 4.21.0"
2444
+ }
2445
+ },
2446
+ "node_modules/vite": {
2447
+ "version": "6.4.1",
2448
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
2449
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
2450
+ "dev": true,
2451
+ "license": "MIT",
2452
+ "dependencies": {
2453
+ "esbuild": "^0.25.0",
2454
+ "fdir": "^6.4.4",
2455
+ "picomatch": "^4.0.2",
2456
+ "postcss": "^8.5.3",
2457
+ "rollup": "^4.34.9",
2458
+ "tinyglobby": "^0.2.13"
2459
+ },
2460
+ "bin": {
2461
+ "vite": "bin/vite.js"
2462
+ },
2463
+ "engines": {
2464
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
2465
+ },
2466
+ "funding": {
2467
+ "url": "https://github.com/vitejs/vite?sponsor=1"
2468
+ },
2469
+ "optionalDependencies": {
2470
+ "fsevents": "~2.3.3"
2471
+ },
2472
+ "peerDependencies": {
2473
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
2474
+ "jiti": ">=1.21.0",
2475
+ "less": "*",
2476
+ "lightningcss": "^1.21.0",
2477
+ "sass": "*",
2478
+ "sass-embedded": "*",
2479
+ "stylus": "*",
2480
+ "sugarss": "*",
2481
+ "terser": "^5.16.0",
2482
+ "tsx": "^4.8.1",
2483
+ "yaml": "^2.4.2"
2484
+ },
2485
+ "peerDependenciesMeta": {
2486
+ "@types/node": {
2487
+ "optional": true
2488
+ },
2489
+ "jiti": {
2490
+ "optional": true
2491
+ },
2492
+ "less": {
2493
+ "optional": true
2494
+ },
2495
+ "lightningcss": {
2496
+ "optional": true
2497
+ },
2498
+ "sass": {
2499
+ "optional": true
2500
+ },
2501
+ "sass-embedded": {
2502
+ "optional": true
2503
+ },
2504
+ "stylus": {
2505
+ "optional": true
2506
+ },
2507
+ "sugarss": {
2508
+ "optional": true
2509
+ },
2510
+ "terser": {
2511
+ "optional": true
2512
+ },
2513
+ "tsx": {
2514
+ "optional": true
2515
+ },
2516
+ "yaml": {
2517
+ "optional": true
2518
+ }
2519
+ }
2520
+ },
2521
+ "node_modules/yallist": {
2522
+ "version": "3.1.1",
2523
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
2524
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
2525
+ "dev": true,
2526
+ "license": "ISC"
2527
+ },
2528
+ "node_modules/zustand": {
2529
+ "version": "5.0.12",
2530
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.12.tgz",
2531
+ "integrity": "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==",
2532
+ "license": "MIT",
2533
+ "engines": {
2534
+ "node": ">=12.20.0"
2535
+ },
2536
+ "peerDependencies": {
2537
+ "@types/react": ">=18.0.0",
2538
+ "immer": ">=9.0.6",
2539
+ "react": ">=18.0.0",
2540
+ "use-sync-external-store": ">=1.2.0"
2541
+ },
2542
+ "peerDependenciesMeta": {
2543
+ "@types/react": {
2544
+ "optional": true
2545
+ },
2546
+ "immer": {
2547
+ "optional": true
2548
+ },
2549
+ "react": {
2550
+ "optional": true
2551
+ },
2552
+ "use-sync-external-store": {
2553
+ "optional": true
2554
+ }
2555
+ }
2556
+ }
2557
+ }
2558
+ }
dashboard/package.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "codelens-dashboard",
3
+ "private": true,
4
+ "version": "0.1.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@fontsource/inter": "^5.1.0",
13
+ "@tanstack/react-query": "^5.0.0",
14
+ "clsx": "^2.1.0",
15
+ "lucide-react": "^0.475.0",
16
+ "react": "^18.3.0",
17
+ "react-dom": "^18.3.0",
18
+ "zustand": "^5.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@tailwindcss/vite": "^4.1.0",
22
+ "@types/node": "^25.5.2",
23
+ "@types/react": "^18.3.0",
24
+ "@types/react-dom": "^18.3.0",
25
+ "@vitejs/plugin-react": "^4.3.0",
26
+ "tailwindcss": "^4.1.0",
27
+ "typescript": "^5.7.0",
28
+ "vite": "^6.2.0"
29
+ }
30
+ }
dashboard/public/favicon.svg ADDED
dashboard/public/logo.svg ADDED
dashboard/src/App.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Header from "./components/Header";
3
+ import StatsRow from "./components/StatsRow";
4
+ import Leaderboard from "./components/Leaderboard";
5
+ import EventFeed from "./components/EventFeed";
6
+ import { useWebSocket } from "./hooks/useWebSocket";
7
+ const App = () => {
8
+ useWebSocket();
9
+ return (_jsx("div", { className: "min-h-screen", style: { backgroundColor: "var(--color-bg)" }, children: _jsxs("div", { className: "max-w-7xl mx-auto px-6 py-10 space-y-10", children: [_jsx(Header, {}), _jsx(StatsRow, {}), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-3 gap-8", children: [_jsx("div", { className: "lg:col-span-2", children: _jsx(Leaderboard, {}) }), _jsx("div", { className: "lg:col-span-1", children: _jsx(EventFeed, {}) })] })] }) }));
10
+ };
11
+ export default App;
dashboard/src/App.tsx ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import Header from "./components/Header";
3
+ import StatsRow from "./components/StatsRow";
4
+ import Leaderboard from "./components/Leaderboard";
5
+ import EventFeed from "./components/EventFeed";
6
+ import { useWebSocket } from "./hooks/useWebSocket";
7
+
8
+ const App: React.FC = () => {
9
+ useWebSocket();
10
+
11
+ return (
12
+ <div className="min-h-screen" style={{ backgroundColor: "var(--color-bg)" }}>
13
+ <div className="max-w-7xl mx-auto px-6 py-10 space-y-10">
14
+ <Header />
15
+ <StatsRow />
16
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
17
+ <div className="lg:col-span-2">
18
+ <Leaderboard />
19
+ </div>
20
+ <div className="lg:col-span-1">
21
+ <EventFeed />
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ );
27
+ };
28
+
29
+ export default App;
dashboard/src/api.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ const BASE = import.meta.env.DEV ? "/api" : "";
2
+ export const fetchHealth = () => fetch(`${BASE}/health`).then(r => r.json());
3
+ export const fetchStats = () => fetch(`${BASE}/stats`).then(r => r.json());
4
+ export const fetchLeaderboard = (taskId, limit = 10) => fetch(`${BASE}/leaderboard?task_id=${taskId}&limit=${limit}`)
5
+ .then(r => r.json())
6
+ .then(data => data.entries || []);
dashboard/src/api.ts ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import { HealthResponse, StatsResponse, LeaderboardEntry, TaskId } from "./types";
2
+
3
+ const BASE = import.meta.env.DEV ? "/api" : "";
4
+
5
+ export const fetchHealth = (): Promise<HealthResponse> => fetch(`${BASE}/health`).then(r => r.json());
6
+ export const fetchStats = (): Promise<StatsResponse> => fetch(`${BASE}/stats`).then(r => r.json());
7
+ export const fetchLeaderboard = (taskId: TaskId, limit = 10): Promise<LeaderboardEntry[]> =>
8
+ fetch(`${BASE}/leaderboard?task_id=${taskId}&limit=${limit}`)
9
+ .then(r => r.json())
10
+ .then(data => data.entries || []);
dashboard/src/components/EventFeed.js ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Zap, Trash2 } from "lucide-react";
3
+ import { useEventStore } from "../stores/eventStore";
4
+ import EventRow from "./EventRow";
5
+ const EventFeed = () => {
6
+ const { events, clear, connected } = useEventStore();
7
+ return (_jsxs("div", { className: "bg-white rounded-3xl overflow-hidden flex flex-col h-[600px]", style: { border: "1px solid var(--color-border)" }, children: [_jsxs("div", { className: "px-7 py-5 flex items-center justify-between", style: { borderBottom: "1px solid var(--color-border)" }, children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: `p-2 rounded-xl ${connected ? "bg-amber-50" : "bg-zinc-100"}`, children: _jsx(Zap, { className: `w-5 h-5 ${connected ? "text-amber-600" : "text-zinc-400"}` }) }), _jsx("h2", { className: "text-lg font-extrabold tracking-tight", style: { color: "var(--color-heading)" }, children: "Live Feed" })] }), _jsx("button", { onClick: clear, className: "p-2.5 hover:bg-zinc-100 rounded-xl transition-colors", style: { color: "var(--color-muted)" }, title: "Clear Feed", children: _jsx(Trash2, { className: "w-4 h-4" }) })] }), _jsxs("div", { className: "flex-1 overflow-auto p-5 space-y-3", children: [!connected && (_jsxs("div", { className: "flex flex-col items-center justify-center h-full space-y-4 text-center", children: [_jsx("div", { className: "p-5 bg-zinc-50 rounded-2xl", children: _jsx(Zap, { className: "w-10 h-10 text-zinc-200 animate-pulse" }) }), _jsx("p", { className: "text-[11px] uppercase tracking-[0.15em] font-bold", style: { color: "var(--color-muted)" }, children: "Connecting to live stream..." })] })), connected && events.length === 0 && (_jsxs("div", { className: "flex flex-col items-center justify-center h-full space-y-4 text-center", children: [_jsx("div", { className: "p-5 bg-zinc-50 rounded-2xl", children: _jsx(Zap, { className: "w-10 h-10 text-zinc-200" }) }), _jsxs("div", { className: "space-y-1.5", children: [_jsx("p", { className: "text-[11px] font-bold uppercase tracking-[0.15em]", style: { color: "var(--color-muted)" }, children: "Monitoring activity" }), _jsx("p", { className: "text-[11px] max-w-[180px] leading-relaxed", style: { color: "var(--color-muted)" }, children: "Evaluation events will appear here in real-time." })] })] })), events.map((event, idx) => (_jsx(EventRow, { event: event }, idx)))] })] }));
8
+ };
9
+ export default EventFeed;
dashboard/src/components/EventFeed.tsx ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { Zap, Trash2 } from "lucide-react";
3
+ import { useEventStore } from "../stores/eventStore";
4
+ import EventRow from "./EventRow";
5
+
6
+ const EventFeed: React.FC = () => {
7
+ const { events, clear, connected } = useEventStore();
8
+
9
+ return (
10
+ <div
11
+ className="bg-white rounded-3xl overflow-hidden flex flex-col h-[600px]"
12
+ style={{ border: "1px solid var(--color-border)" }}
13
+ >
14
+ {/* Header */}
15
+ <div
16
+ className="px-7 py-5 flex items-center justify-between"
17
+ style={{ borderBottom: "1px solid var(--color-border)" }}
18
+ >
19
+ <div className="flex items-center gap-3">
20
+ <div className={`p-2 rounded-xl ${connected ? "bg-amber-50" : "bg-zinc-100"}`}>
21
+ <Zap className={`w-5 h-5 ${connected ? "text-amber-600" : "text-zinc-400"}`} />
22
+ </div>
23
+ <h2 className="text-lg font-extrabold tracking-tight" style={{ color: "var(--color-heading)" }}>
24
+ Live Feed
25
+ </h2>
26
+ </div>
27
+ <button
28
+ onClick={clear}
29
+ className="p-2.5 hover:bg-zinc-100 rounded-xl transition-colors"
30
+ style={{ color: "var(--color-muted)" }}
31
+ title="Clear Feed"
32
+ >
33
+ <Trash2 className="w-4 h-4" />
34
+ </button>
35
+ </div>
36
+
37
+ {/* Content */}
38
+ <div className="flex-1 overflow-auto p-5 space-y-3">
39
+ {!connected && (
40
+ <div className="flex flex-col items-center justify-center h-full space-y-4 text-center">
41
+ <div className="p-5 bg-zinc-50 rounded-2xl">
42
+ <Zap className="w-10 h-10 text-zinc-200 animate-pulse" />
43
+ </div>
44
+ <p className="text-[11px] uppercase tracking-[0.15em] font-bold" style={{ color: "var(--color-muted)" }}>
45
+ Connecting to live stream...
46
+ </p>
47
+ </div>
48
+ )}
49
+
50
+ {connected && events.length === 0 && (
51
+ <div className="flex flex-col items-center justify-center h-full space-y-4 text-center">
52
+ <div className="p-5 bg-zinc-50 rounded-2xl">
53
+ <Zap className="w-10 h-10 text-zinc-200" />
54
+ </div>
55
+ <div className="space-y-1.5">
56
+ <p className="text-[11px] font-bold uppercase tracking-[0.15em]" style={{ color: "var(--color-muted)" }}>
57
+ Monitoring activity
58
+ </p>
59
+ <p className="text-[11px] max-w-[180px] leading-relaxed" style={{ color: "var(--color-muted)" }}>
60
+ Evaluation events will appear here in real-time.
61
+ </p>
62
+ </div>
63
+ </div>
64
+ )}
65
+
66
+ {events.map((event, idx) => (
67
+ <EventRow key={idx} event={event} />
68
+ ))}
69
+ </div>
70
+ </div>
71
+ );
72
+ };
73
+
74
+ export default EventFeed;
dashboard/src/components/EventRow.js ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { clsx } from "clsx";
3
+ const EventRow = ({ event }) => {
4
+ const time = new Date(event.timestamp).toLocaleTimeString([], {
5
+ hour12: false,
6
+ hour: "2-digit",
7
+ minute: "2-digit",
8
+ second: "2-digit",
9
+ });
10
+ return (_jsxs("div", { className: "rounded-2xl p-4 transition-all duration-200 hover:shadow-sm animate-fade-slide-in", style: {
11
+ backgroundColor: "#fafafa",
12
+ border: "1px solid var(--color-border)",
13
+ }, children: [_jsxs("div", { className: "flex items-center justify-between mb-2", children: [_jsx("span", { className: "text-[10px] tabular-nums font-bold uppercase tracking-wider", style: { color: "var(--color-muted)" }, children: time }), _jsx("span", { className: "text-[10px] font-mono font-bold bg-indigo-50 text-indigo-600 px-2 py-0.5 rounded-md", children: event.episode_id.slice(0, 8) })] }), _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("span", { className: "text-sm font-semibold capitalize truncate max-w-[140px]", style: { color: "var(--color-heading)" }, children: event.type }), _jsxs("span", { className: clsx("text-xs font-bold font-mono px-2.5 py-1 rounded-full", event.reward > 0
14
+ ? "text-emerald-700 bg-emerald-50"
15
+ : event.reward < 0
16
+ ? "text-red-600 bg-red-50"
17
+ : "text-zinc-500 bg-zinc-100"), children: [event.reward > 0 ? "+" : "", event.reward.toFixed(2)] })] })] }));
18
+ };
19
+ export default EventRow;
dashboard/src/components/EventRow.tsx ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { WsEvent } from "../types";
3
+ import { clsx } from "clsx";
4
+
5
+ interface EventRowProps {
6
+ event: WsEvent;
7
+ }
8
+
9
+ const EventRow: React.FC<EventRowProps> = ({ event }) => {
10
+ const time = new Date(event.timestamp).toLocaleTimeString([], {
11
+ hour12: false,
12
+ hour: "2-digit",
13
+ minute: "2-digit",
14
+ second: "2-digit",
15
+ });
16
+
17
+ return (
18
+ <div
19
+ className="rounded-2xl p-4 transition-all duration-200 hover:shadow-sm animate-fade-slide-in"
20
+ style={{
21
+ backgroundColor: "#fafafa",
22
+ border: "1px solid var(--color-border)",
23
+ }}
24
+ >
25
+ <div className="flex items-center justify-between mb-2">
26
+ <span
27
+ className="text-[10px] tabular-nums font-bold uppercase tracking-wider"
28
+ style={{ color: "var(--color-muted)" }}
29
+ >
30
+ {time}
31
+ </span>
32
+ <span className="text-[10px] font-mono font-bold bg-indigo-50 text-indigo-600 px-2 py-0.5 rounded-md">
33
+ {event.episode_id.slice(0, 8)}
34
+ </span>
35
+ </div>
36
+ <div className="flex items-center justify-between">
37
+ <span
38
+ className="text-sm font-semibold capitalize truncate max-w-[140px]"
39
+ style={{ color: "var(--color-heading)" }}
40
+ >
41
+ {event.type}
42
+ </span>
43
+ <span
44
+ className={clsx(
45
+ "text-xs font-bold font-mono px-2.5 py-1 rounded-full",
46
+ event.reward > 0
47
+ ? "text-emerald-700 bg-emerald-50"
48
+ : event.reward < 0
49
+ ? "text-red-600 bg-red-50"
50
+ : "text-zinc-500 bg-zinc-100"
51
+ )}
52
+ >
53
+ {event.reward > 0 ? "+" : ""}
54
+ {event.reward.toFixed(2)}
55
+ </span>
56
+ </div>
57
+ </div>
58
+ );
59
+ };
60
+
61
+ export default EventRow;
dashboard/src/components/Header.js ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { Wifi, WifiOff } from "lucide-react";
4
+ import { fetchHealth } from "../api";
5
+ import { clsx } from "clsx";
6
+ const Header = () => {
7
+ const { data: health } = useQuery({
8
+ queryKey: ["health"],
9
+ queryFn: fetchHealth,
10
+ refetchInterval: 10_000,
11
+ });
12
+ const isConnected = health?.status === "ok";
13
+ return (_jsxs("header", { className: "flex items-center justify-between pb-2", children: [_jsx("div", { className: "flex items-center gap-6", children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("img", { src: "/dashboard/logo.svg", className: "h-[38px] w-auto", alt: "CodeLens." }), _jsx("div", { className: "h-5 w-px bg-zinc-200 hidden sm:block mx-2" }), _jsx("p", { className: "text-[10px] font-mono font-bold uppercase tracking-[0.3em] hidden sm:block pt-1 opacity-40 group-hover:opacity-60 transition-opacity", style: { color: "var(--color-heading)" }, children: "Evaluation" })] }) }), _jsx("div", { className: clsx("flex items-center gap-2 px-4 py-2 rounded-full text-xs font-semibold tracking-wide uppercase transition-all", isConnected
14
+ ? "bg-emerald-50 text-emerald-600 ring-1 ring-emerald-200"
15
+ : "bg-red-50 text-red-500 ring-1 ring-red-200"), children: isConnected ? (_jsxs(_Fragment, { children: [_jsx(Wifi, { className: "w-3.5 h-3.5" }), _jsx("span", { children: "Connected" })] })) : (_jsxs(_Fragment, { children: [_jsx(WifiOff, { className: "w-3.5 h-3.5" }), _jsx("span", { children: "Offline" })] })) })] }));
16
+ };
17
+ export default Header;
dashboard/src/components/Header.tsx ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { Wifi, WifiOff } from "lucide-react";
4
+ import { fetchHealth } from "../api";
5
+ import { clsx } from "clsx";
6
+
7
+ const Header: React.FC = () => {
8
+ const { data: health } = useQuery({
9
+ queryKey: ["health"],
10
+ queryFn: fetchHealth,
11
+ refetchInterval: 10_000,
12
+ });
13
+
14
+ const isConnected = health?.status === "ok";
15
+
16
+ return (
17
+ <header className="flex items-center justify-between pb-2">
18
+ <div className="flex items-center gap-6">
19
+ <div className="flex items-center gap-2">
20
+ {/* Logo Replacement */}
21
+ <img src="/dashboard/logo.svg" className="h-[38px] w-auto" alt="CodeLens." />
22
+ <div className="h-5 w-px bg-zinc-200 hidden sm:block mx-2" />
23
+ <p className="text-[10px] font-mono font-bold uppercase tracking-[0.3em] hidden sm:block pt-1 opacity-40 group-hover:opacity-60 transition-opacity" style={{ color: "var(--color-heading)" }}>
24
+ Evaluation
25
+ </p>
26
+ </div>
27
+ </div>
28
+
29
+ <div className={clsx(
30
+ "flex items-center gap-2 px-4 py-2 rounded-full text-xs font-semibold tracking-wide uppercase transition-all",
31
+ isConnected
32
+ ? "bg-emerald-50 text-emerald-600 ring-1 ring-emerald-200"
33
+ : "bg-red-50 text-red-500 ring-1 ring-red-200"
34
+ )}>
35
+ {isConnected ? (
36
+ <>
37
+ <Wifi className="w-3.5 h-3.5" />
38
+ <span>Connected</span>
39
+ </>
40
+ ) : (
41
+ <>
42
+ <WifiOff className="w-3.5 h-3.5" />
43
+ <span>Offline</span>
44
+ </>
45
+ )}
46
+ </div>
47
+ </header>
48
+ );
49
+ };
50
+
51
+ export default Header;
dashboard/src/components/Leaderboard.js ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { useQuery } from "@tanstack/react-query";
4
+ import { Trophy, RefreshCw } from "lucide-react";
5
+ import { fetchLeaderboard } from "../api";
6
+ import LeaderboardTable from "./LeaderboardTable";
7
+ import { clsx } from "clsx";
8
+ const Leaderboard = () => {
9
+ const [activeTab, setActiveTab] = useState("bug_detection");
10
+ const { data: entries, isLoading, refetch, isRefetching } = useQuery({
11
+ queryKey: ["leaderboard", activeTab],
12
+ queryFn: () => fetchLeaderboard(activeTab),
13
+ });
14
+ const tabs = [
15
+ { id: "bug_detection", label: "Bug Detection" },
16
+ { id: "security_audit", label: "Security Audit" },
17
+ { id: "architectural_review", label: "Arch. Review" },
18
+ ];
19
+ return (_jsxs("div", { className: "bg-white rounded-3xl overflow-hidden flex flex-col h-[600px]", style: { border: "1px solid var(--color-border)" }, children: [_jsxs("div", { className: "px-7 py-5 flex items-center justify-between", style: { borderBottom: "1px solid var(--color-border)" }, children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("div", { className: "p-2 bg-amber-50 rounded-xl", children: _jsx(Trophy, { className: "w-5 h-5 text-amber-600" }) }), _jsx("h2", { className: "text-lg font-extrabold tracking-tight", style: { color: "var(--color-heading)" }, children: "Leaderboard" })] }), _jsx("button", { onClick: () => refetch(), disabled: isLoading || isRefetching, className: "p-2.5 hover:bg-zinc-100 rounded-xl transition-colors disabled:opacity-40", style: { color: "var(--color-muted)" }, children: _jsx(RefreshCw, { className: clsx("w-4 h-4", (isLoading || isRefetching) && "animate-spin") }) })] }), _jsx("div", { className: "px-7", style: { borderBottom: "1px solid var(--color-border)" }, children: _jsx("div", { className: "flex gap-6 overflow-x-auto", children: tabs.map((tab) => (_jsxs("button", { onClick: () => setActiveTab(tab.id), className: clsx("py-3.5 text-sm font-semibold transition-all relative whitespace-nowrap", activeTab === tab.id
20
+ ? "text-zinc-900"
21
+ : "text-zinc-400 hover:text-zinc-600"), children: [tab.label, activeTab === tab.id && (_jsx("div", { className: "absolute bottom-0 left-0 right-0 h-[2px] bg-zinc-900 rounded-full" }))] }, tab.id))) }) }), _jsx("div", { className: "flex-1 overflow-auto", children: isLoading ? (_jsxs("div", { className: "flex items-center justify-center h-full gap-3", style: { color: "var(--color-muted)" }, children: [_jsx(RefreshCw, { className: "w-5 h-5 animate-spin" }), _jsx("span", { className: "text-sm font-medium", children: "Loading entries..." })] })) : entries && entries.length > 0 ? (_jsx(LeaderboardTable, { entries: entries })) : (_jsxs("div", { className: "flex flex-col items-center justify-center h-full space-y-4", children: [_jsx("div", { className: "p-5 bg-zinc-50 rounded-2xl", children: _jsx(Trophy, { className: "w-10 h-10 text-zinc-200" }) }), _jsx("p", { className: "text-xs font-bold uppercase tracking-[0.15em]", style: { color: "var(--color-muted)" }, children: "No rankings yet" })] })) })] }));
22
+ };
23
+ export default Leaderboard;
dashboard/src/components/Leaderboard.tsx ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useState } from "react";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { Trophy, RefreshCw } from "lucide-react";
4
+ import { TaskId } from "../types";
5
+ import { fetchLeaderboard } from "../api";
6
+ import LeaderboardTable from "./LeaderboardTable";
7
+ import { clsx } from "clsx";
8
+
9
+ const Leaderboard: React.FC = () => {
10
+ const [activeTab, setActiveTab] = useState<TaskId>("bug_detection");
11
+
12
+ const { data: entries, isLoading, refetch, isRefetching } = useQuery({
13
+ queryKey: ["leaderboard", activeTab],
14
+ queryFn: () => fetchLeaderboard(activeTab),
15
+ });
16
+
17
+ const tabs: { id: TaskId; label: string }[] = [
18
+ { id: "bug_detection", label: "Bug Detection" },
19
+ { id: "security_audit", label: "Security Audit" },
20
+ { id: "architectural_review", label: "Arch. Review" },
21
+ ];
22
+
23
+ return (
24
+ <div
25
+ className="bg-white rounded-3xl overflow-hidden flex flex-col h-[600px]"
26
+ style={{ border: "1px solid var(--color-border)" }}
27
+ >
28
+ {/* Header */}
29
+ <div
30
+ className="px-7 py-5 flex items-center justify-between"
31
+ style={{ borderBottom: "1px solid var(--color-border)" }}
32
+ >
33
+ <div className="flex items-center gap-3">
34
+ <div className="p-2 bg-amber-50 rounded-xl">
35
+ <Trophy className="w-5 h-5 text-amber-600" />
36
+ </div>
37
+ <h2 className="text-lg font-extrabold tracking-tight" style={{ color: "var(--color-heading)" }}>
38
+ Leaderboard
39
+ </h2>
40
+ </div>
41
+ <button
42
+ onClick={() => refetch()}
43
+ disabled={isLoading || isRefetching}
44
+ className="p-2.5 hover:bg-zinc-100 rounded-xl transition-colors disabled:opacity-40"
45
+ style={{ color: "var(--color-muted)" }}
46
+ >
47
+ <RefreshCw className={clsx("w-4 h-4", (isLoading || isRefetching) && "animate-spin")} />
48
+ </button>
49
+ </div>
50
+
51
+ {/* Tabs */}
52
+ <div className="px-7" style={{ borderBottom: "1px solid var(--color-border)" }}>
53
+ <div className="flex gap-6 overflow-x-auto">
54
+ {tabs.map((tab) => (
55
+ <button
56
+ key={tab.id}
57
+ onClick={() => setActiveTab(tab.id)}
58
+ className={clsx(
59
+ "py-3.5 text-sm font-semibold transition-all relative whitespace-nowrap",
60
+ activeTab === tab.id
61
+ ? "text-zinc-900"
62
+ : "text-zinc-400 hover:text-zinc-600"
63
+ )}
64
+ >
65
+ {tab.label}
66
+ {activeTab === tab.id && (
67
+ <div className="absolute bottom-0 left-0 right-0 h-[2px] bg-zinc-900 rounded-full" />
68
+ )}
69
+ </button>
70
+ ))}
71
+ </div>
72
+ </div>
73
+
74
+ {/* Content */}
75
+ <div className="flex-1 overflow-auto">
76
+ {isLoading ? (
77
+ <div className="flex items-center justify-center h-full gap-3" style={{ color: "var(--color-muted)" }}>
78
+ <RefreshCw className="w-5 h-5 animate-spin" />
79
+ <span className="text-sm font-medium">Loading entries...</span>
80
+ </div>
81
+ ) : entries && entries.length > 0 ? (
82
+ <LeaderboardTable entries={entries} />
83
+ ) : (
84
+ <div className="flex flex-col items-center justify-center h-full space-y-4">
85
+ <div className="p-5 bg-zinc-50 rounded-2xl">
86
+ <Trophy className="w-10 h-10 text-zinc-200" />
87
+ </div>
88
+ <p className="text-xs font-bold uppercase tracking-[0.15em]" style={{ color: "var(--color-muted)" }}>
89
+ No rankings yet
90
+ </p>
91
+ </div>
92
+ )}
93
+ </div>
94
+ </div>
95
+ );
96
+ };
97
+
98
+ export default Leaderboard;
dashboard/src/components/LeaderboardTable.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import ScoreBadge from "./ScoreBadge";
3
+ const LeaderboardTable = ({ entries }) => {
4
+ return (_jsxs("table", { className: "w-full text-left border-collapse", children: [_jsx("thead", { children: _jsxs("tr", { style: { borderBottom: "1px solid var(--color-border)" }, children: [_jsx("th", { className: "px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em]", style: { color: "var(--color-muted)" }, children: "Rank" }), _jsx("th", { className: "px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em]", style: { color: "var(--color-muted)" }, children: "Agent" }), _jsx("th", { className: "px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em] text-center", style: { color: "var(--color-muted)" }, children: "Score" }), _jsx("th", { className: "px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em] text-right", style: { color: "var(--color-muted)" }, children: "Seed" }), _jsx("th", { className: "px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em] text-right", style: { color: "var(--color-muted)" }, children: "Submitted" })] }) }), _jsx("tbody", { children: entries.map((entry, idx) => (_jsxs("tr", { className: "group hover:bg-zinc-50/80 transition-colors tabular-nums", style: { borderBottom: "1px solid var(--color-border)" }, children: [_jsx("td", { className: "px-7 py-5", children: idx < 3 ? (_jsx("span", { className: `
5
+ inline-flex items-center justify-center w-7 h-7 rounded-lg text-xs font-extrabold
6
+ ${idx === 0 ? "bg-amber-50 text-amber-600" : ""}
7
+ ${idx === 1 ? "bg-zinc-100 text-zinc-500" : ""}
8
+ ${idx === 2 ? "bg-orange-50 text-orange-500" : ""}
9
+ `, children: entry.rank })) : (_jsx("span", { className: "text-sm font-semibold pl-2", style: { color: "var(--color-muted)" }, children: entry.rank })) }), _jsx("td", { className: "px-7 py-5", children: _jsx("span", { className: "font-semibold group-hover:text-zinc-900 transition-colors", style: { color: "var(--color-heading)" }, children: entry.agent_name }) }), _jsx("td", { className: "px-7 py-5 text-center", children: _jsx(ScoreBadge, { score: entry.score }) }), _jsx("td", { className: "px-7 py-5 text-right text-sm font-mono", style: { color: "var(--color-muted)" }, children: entry.seed }), _jsx("td", { className: "px-7 py-5 text-right text-xs", style: { color: "var(--color-muted)" }, children: new Date(entry.submitted_at).toLocaleDateString() })] }, idx))) })] }));
10
+ };
11
+ export default LeaderboardTable;
dashboard/src/components/LeaderboardTable.tsx ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { LeaderboardEntry } from "../types";
3
+ import ScoreBadge from "./ScoreBadge";
4
+
5
+ interface LeaderboardTableProps {
6
+ entries: LeaderboardEntry[];
7
+ }
8
+
9
+ const LeaderboardTable: React.FC<LeaderboardTableProps> = ({ entries }) => {
10
+ return (
11
+ <table className="w-full text-left border-collapse">
12
+ <thead>
13
+ <tr style={{ borderBottom: "1px solid var(--color-border)" }}>
14
+ <th className="px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em]" style={{ color: "var(--color-muted)" }}>
15
+ Rank
16
+ </th>
17
+ <th className="px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em]" style={{ color: "var(--color-muted)" }}>
18
+ Agent
19
+ </th>
20
+ <th className="px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em] text-center" style={{ color: "var(--color-muted)" }}>
21
+ Score
22
+ </th>
23
+ <th className="px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em] text-right" style={{ color: "var(--color-muted)" }}>
24
+ Seed
25
+ </th>
26
+ <th className="px-7 py-4 text-[10px] font-bold uppercase tracking-[0.12em] text-right" style={{ color: "var(--color-muted)" }}>
27
+ Submitted
28
+ </th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ {entries.map((entry, idx) => (
33
+ <tr
34
+ key={idx}
35
+ className="group hover:bg-zinc-50/80 transition-colors tabular-nums"
36
+ style={{ borderBottom: "1px solid var(--color-border)" }}
37
+ >
38
+ <td className="px-7 py-5">
39
+ {idx < 3 ? (
40
+ <span
41
+ className={`
42
+ inline-flex items-center justify-center w-7 h-7 rounded-lg text-xs font-extrabold
43
+ ${idx === 0 ? "bg-amber-50 text-amber-600" : ""}
44
+ ${idx === 1 ? "bg-zinc-100 text-zinc-500" : ""}
45
+ ${idx === 2 ? "bg-orange-50 text-orange-500" : ""}
46
+ `}
47
+ >
48
+ {entry.rank}
49
+ </span>
50
+ ) : (
51
+ <span className="text-sm font-semibold pl-2" style={{ color: "var(--color-muted)" }}>
52
+ {entry.rank}
53
+ </span>
54
+ )}
55
+ </td>
56
+ <td className="px-7 py-5">
57
+ <span className="font-semibold group-hover:text-zinc-900 transition-colors" style={{ color: "var(--color-heading)" }}>
58
+ {entry.agent_name}
59
+ </span>
60
+ </td>
61
+ <td className="px-7 py-5 text-center">
62
+ <ScoreBadge score={entry.score} />
63
+ </td>
64
+ <td className="px-7 py-5 text-right text-sm font-mono" style={{ color: "var(--color-muted)" }}>
65
+ {entry.seed}
66
+ </td>
67
+ <td className="px-7 py-5 text-right text-xs" style={{ color: "var(--color-muted)" }}>
68
+ {new Date(entry.submitted_at).toLocaleDateString()}
69
+ </td>
70
+ </tr>
71
+ ))}
72
+ </tbody>
73
+ </table>
74
+ );
75
+ };
76
+
77
+ export default LeaderboardTable;
dashboard/src/components/ScoreBadge.js ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { clsx } from "clsx";
3
+ const ScoreBadge = ({ score }) => {
4
+ const colorClass = score >= 0.8
5
+ ? "text-emerald-700 bg-emerald-50 ring-1 ring-emerald-200"
6
+ : score >= 0.5
7
+ ? "text-amber-700 bg-amber-50 ring-1 ring-amber-200"
8
+ : "text-red-600 bg-red-50 ring-1 ring-red-200";
9
+ return (_jsx("span", { className: clsx("inline-flex items-center px-3 py-1 rounded-full text-xs font-bold tabular-nums", colorClass), children: score.toFixed(2) }));
10
+ };
11
+ export default ScoreBadge;
dashboard/src/components/ScoreBadge.tsx ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { clsx } from "clsx";
3
+
4
+ interface ScoreBadgeProps {
5
+ score: number;
6
+ }
7
+
8
+ const ScoreBadge: React.FC<ScoreBadgeProps> = ({ score }) => {
9
+ const colorClass =
10
+ score >= 0.8
11
+ ? "text-emerald-700 bg-emerald-50 ring-1 ring-emerald-200"
12
+ : score >= 0.5
13
+ ? "text-amber-700 bg-amber-50 ring-1 ring-amber-200"
14
+ : "text-red-600 bg-red-50 ring-1 ring-red-200";
15
+
16
+ return (
17
+ <span
18
+ className={clsx(
19
+ "inline-flex items-center px-3 py-1 rounded-full text-xs font-bold tabular-nums",
20
+ colorClass
21
+ )}
22
+ >
23
+ {score.toFixed(2)}
24
+ </span>
25
+ );
26
+ };
27
+
28
+ export default ScoreBadge;
dashboard/src/components/StatCard.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ const StatCard = ({ label, value, icon, iconBg }) => {
3
+ return (_jsxs("div", { className: "bg-white rounded-3xl p-7 transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5 group", style: { border: "1px solid var(--color-border)" }, children: [_jsxs("div", { className: "flex items-start justify-between mb-5", children: [_jsx("p", { className: "text-[11px] font-bold uppercase tracking-[0.12em]", style: { color: "var(--color-muted)" }, children: label }), _jsx("div", { className: `p-2.5 rounded-xl transition-transform group-hover:scale-110 ${iconBg}`, children: icon })] }), _jsx("h3", { className: "text-4xl font-extrabold tracking-tight tabular-nums", style: { color: "var(--color-heading)" }, children: value })] }));
4
+ };
5
+ export default StatCard;
dashboard/src/components/StatCard.tsx ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+
3
+ interface StatCardProps {
4
+ label: string;
5
+ value: string | number;
6
+ icon: React.ReactNode;
7
+ iconBg: string;
8
+ }
9
+
10
+ const StatCard: React.FC<StatCardProps> = ({ label, value, icon, iconBg }) => {
11
+ return (
12
+ <div
13
+ className="bg-white rounded-3xl p-7 transition-all duration-200 hover:shadow-lg hover:-translate-y-0.5 group"
14
+ style={{ border: "1px solid var(--color-border)" }}
15
+ >
16
+ <div className="flex items-start justify-between mb-5">
17
+ <p
18
+ className="text-[11px] font-bold uppercase tracking-[0.12em]"
19
+ style={{ color: "var(--color-muted)" }}
20
+ >
21
+ {label}
22
+ </p>
23
+ <div className={`p-2.5 rounded-xl transition-transform group-hover:scale-110 ${iconBg}`}>
24
+ {icon}
25
+ </div>
26
+ </div>
27
+ <h3
28
+ className="text-4xl font-extrabold tracking-tight tabular-nums"
29
+ style={{ color: "var(--color-heading)" }}
30
+ >
31
+ {value}
32
+ </h3>
33
+ </div>
34
+ );
35
+ };
36
+
37
+ export default StatCard;
dashboard/src/components/StatsRow.js ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { Trophy, Zap, Activity } from "lucide-react";
4
+ import { fetchStats, fetchHealth } from "../api";
5
+ import StatCard from "./StatCard";
6
+ const StatsRow = () => {
7
+ const { data: stats } = useQuery({
8
+ queryKey: ["stats"],
9
+ queryFn: fetchStats,
10
+ refetchInterval: 30_000,
11
+ });
12
+ const { data: health } = useQuery({
13
+ queryKey: ["health"],
14
+ queryFn: fetchHealth,
15
+ refetchInterval: 10_000,
16
+ });
17
+ return (_jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: [_jsx(StatCard, { label: "Total Episodes", value: stats?.total_episodes ?? 0, icon: _jsx(Trophy, { className: "w-5 h-5 text-amber-600" }), iconBg: "bg-amber-50" }), _jsx(StatCard, { label: "Avg. Score", value: stats?.avg_score?.toFixed(2) ?? "0.00", icon: _jsx(Zap, { className: "w-5 h-5 text-blue-600" }), iconBg: "bg-blue-50" }), _jsx(StatCard, { label: "Active Episodes", value: health?.active_episodes ?? 0, icon: _jsx(Activity, { className: "w-5 h-5 text-emerald-600" }), iconBg: "bg-emerald-50" })] }));
18
+ };
19
+ export default StatsRow;
dashboard/src/components/StatsRow.tsx ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import { useQuery } from "@tanstack/react-query";
3
+ import { Trophy, Zap, Activity } from "lucide-react";
4
+ import { fetchStats, fetchHealth } from "../api";
5
+ import StatCard from "./StatCard";
6
+
7
+ const StatsRow: React.FC = () => {
8
+ const { data: stats } = useQuery({
9
+ queryKey: ["stats"],
10
+ queryFn: fetchStats,
11
+ refetchInterval: 30_000,
12
+ });
13
+
14
+ const { data: health } = useQuery({
15
+ queryKey: ["health"],
16
+ queryFn: fetchHealth,
17
+ refetchInterval: 10_000,
18
+ });
19
+
20
+ return (
21
+ <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
22
+ <StatCard
23
+ label="Total Episodes"
24
+ value={stats?.total_episodes ?? 0}
25
+ icon={<Trophy className="w-5 h-5 text-amber-600" />}
26
+ iconBg="bg-amber-50"
27
+ />
28
+ <StatCard
29
+ label="Avg. Score"
30
+ value={stats?.avg_score?.toFixed(2) ?? "0.00"}
31
+ icon={<Zap className="w-5 h-5 text-blue-600" />}
32
+ iconBg="bg-blue-50"
33
+ />
34
+ <StatCard
35
+ label="Active Episodes"
36
+ value={health?.active_episodes ?? 0}
37
+ icon={<Activity className="w-5 h-5 text-emerald-600" />}
38
+ iconBg="bg-emerald-50"
39
+ />
40
+ </div>
41
+ );
42
+ };
43
+
44
+ export default StatsRow;
dashboard/src/hooks/useWebSocket.js ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useRef } from "react";
2
+ import { useEventStore } from "../stores/eventStore";
3
+ export function useWebSocket() {
4
+ const { push, setConnected } = useEventStore();
5
+ const reconnectTimeout = useRef(null);
6
+ useEffect(() => {
7
+ let socket = null;
8
+ let isMounted = true;
9
+ function connect() {
10
+ if (reconnectTimeout.current)
11
+ clearTimeout(reconnectTimeout.current);
12
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
13
+ const host = import.meta.env.DEV ? "localhost:7860" : window.location.host;
14
+ const url = `${protocol}//${host}/ws/events`;
15
+ socket = new WebSocket(url);
16
+ socket.onopen = () => {
17
+ if (!isMounted)
18
+ return;
19
+ setConnected(true);
20
+ console.log("WebSocket connected");
21
+ };
22
+ socket.onmessage = (event) => {
23
+ if (!isMounted)
24
+ return;
25
+ try {
26
+ const data = JSON.parse(event.data);
27
+ push({
28
+ ...data,
29
+ timestamp: new Date().toISOString(),
30
+ });
31
+ }
32
+ catch (err) {
33
+ console.error("Failed to parse WS message", err);
34
+ }
35
+ };
36
+ socket.onclose = () => {
37
+ if (!isMounted)
38
+ return;
39
+ setConnected(false);
40
+ console.log("WebSocket closed, reconnecting in 3s...");
41
+ reconnectTimeout.current = setTimeout(connect, 3000);
42
+ };
43
+ socket.onerror = (err) => {
44
+ console.error("WebSocket error", err);
45
+ socket?.close();
46
+ };
47
+ }
48
+ connect();
49
+ return () => {
50
+ isMounted = false;
51
+ if (reconnectTimeout.current)
52
+ clearTimeout(reconnectTimeout.current);
53
+ socket?.close();
54
+ };
55
+ }, [push, setConnected]);
56
+ }
dashboard/src/hooks/useWebSocket.ts ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useEffect, useRef } from "react";
2
+ import { useEventStore } from "../stores/eventStore";
3
+
4
+ export function useWebSocket() {
5
+ const { push, setConnected } = useEventStore();
6
+ const reconnectTimeout = useRef<NodeJS.Timeout | null>(null);
7
+
8
+ useEffect(() => {
9
+ let socket: WebSocket | null = null;
10
+ let isMounted = true;
11
+
12
+ function connect() {
13
+ if (reconnectTimeout.current) clearTimeout(reconnectTimeout.current);
14
+
15
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
16
+ const host = import.meta.env.DEV ? "localhost:7860" : window.location.host;
17
+ const url = `${protocol}//${host}/ws/events`;
18
+
19
+ socket = new WebSocket(url);
20
+
21
+ socket.onopen = () => {
22
+ if (!isMounted) return;
23
+ setConnected(true);
24
+ console.log("WebSocket connected");
25
+ };
26
+
27
+ socket.onmessage = (event) => {
28
+ if (!isMounted) return;
29
+ try {
30
+ const data = JSON.parse(event.data);
31
+ push({
32
+ ...data,
33
+ timestamp: new Date().toISOString(),
34
+ });
35
+ } catch (err) {
36
+ console.error("Failed to parse WS message", err);
37
+ }
38
+ };
39
+
40
+ socket.onclose = () => {
41
+ if (!isMounted) return;
42
+ setConnected(false);
43
+ console.log("WebSocket closed, reconnecting in 3s...");
44
+ reconnectTimeout.current = setTimeout(connect, 3000);
45
+ };
46
+
47
+ socket.onerror = (err) => {
48
+ console.error("WebSocket error", err);
49
+ socket?.close();
50
+ };
51
+ }
52
+
53
+ connect();
54
+
55
+ return () => {
56
+ isMounted = false;
57
+ if (reconnectTimeout.current) clearTimeout(reconnectTimeout.current);
58
+ socket?.close();
59
+ };
60
+ }, [push, setConnected]);
61
+ }
dashboard/src/index.css ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import "tailwindcss";
2
+
3
+ :root {
4
+ --color-bg: #f4f4f5; /* zinc-100 — soft warm gray */
5
+ --color-surface: #ffffff; /* pure white cards */
6
+ --color-border: #e4e4e7; /* zinc-200 — subtle borders */
7
+ --color-heading: #09090b; /* zinc-950 — near-black headings */
8
+ --color-body: #52525b; /* zinc-600 — body text */
9
+ --color-muted: #a1a1aa; /* zinc-400 — muted/secondary */
10
+ --color-accent: #6366f1; /* indigo-500 */
11
+ --color-success: #22c55e; /* green-500 */
12
+ --color-warning: #f59e0b; /* amber-500 */
13
+ --color-danger: #ef4444; /* red-500 */
14
+ }
15
+
16
+ * {
17
+ box-sizing: border-box;
18
+ }
19
+
20
+ body {
21
+ background-color: var(--color-bg);
22
+ color: var(--color-body);
23
+ font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
24
+ -webkit-font-smoothing: antialiased;
25
+ -moz-osx-font-smoothing: grayscale;
26
+ }
27
+
28
+ /* Elegant scrollbar */
29
+ ::-webkit-scrollbar {
30
+ width: 6px;
31
+ }
32
+ ::-webkit-scrollbar-track {
33
+ background: transparent;
34
+ }
35
+ ::-webkit-scrollbar-thumb {
36
+ background: #d4d4d8;
37
+ border-radius: 999px;
38
+ }
39
+ ::-webkit-scrollbar-thumb:hover {
40
+ background: #a1a1aa;
41
+ }
42
+
43
+ /* Smooth fade-in for event rows */
44
+ @keyframes fadeSlideIn {
45
+ from {
46
+ opacity: 0;
47
+ transform: translateY(-8px);
48
+ }
49
+ to {
50
+ opacity: 1;
51
+ transform: translateY(0);
52
+ }
53
+ }
54
+
55
+ .animate-fade-slide-in {
56
+ animation: fadeSlideIn 0.3s ease-out forwards;
57
+ }
dashboard/src/main.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import ReactDOM from "react-dom/client";
4
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
5
+ import "@fontsource/inter/400.css";
6
+ import "@fontsource/inter/600.css";
7
+ import "@fontsource/inter/700.css";
8
+ import "./index.css";
9
+ import App from "./App";
10
+ const queryClient = new QueryClient({
11
+ defaultOptions: {
12
+ queries: {
13
+ refetchOnWindowFocus: false,
14
+ retry: 1,
15
+ },
16
+ },
17
+ });
18
+ ReactDOM.createRoot(document.getElementById("root")).render(_jsx(React.StrictMode, { children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(App, {}) }) }));
dashboard/src/main.tsx ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import "@fontsource/inter/400.css";
5
+ import "@fontsource/inter/600.css";
6
+ import "@fontsource/inter/700.css";
7
+ import "./index.css";
8
+ import App from "./App";
9
+
10
+ const queryClient = new QueryClient({
11
+ defaultOptions: {
12
+ queries: {
13
+ refetchOnWindowFocus: false,
14
+ retry: 1,
15
+ },
16
+ },
17
+ });
18
+
19
+ ReactDOM.createRoot(document.getElementById("root")!).render(
20
+ <React.StrictMode>
21
+ <QueryClientProvider client={queryClient}>
22
+ <App />
23
+ </QueryClientProvider>
24
+ </React.StrictMode>
25
+ );
dashboard/src/stores/eventStore.js ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ import { create } from "zustand";
2
+ export const useEventStore = create((set) => ({
3
+ events: [],
4
+ connected: false,
5
+ push: (e) => set((s) => ({ events: [e, ...s.events].slice(0, 20) })),
6
+ clear: () => set({ events: [] }),
7
+ setConnected: (v) => set({ connected: v }),
8
+ }));
dashboard/src/stores/eventStore.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { create } from "zustand";
2
+ import { WsEvent } from "../types";
3
+
4
+ interface EventStore {
5
+ events: WsEvent[];
6
+ connected: boolean;
7
+ push: (e: WsEvent) => void;
8
+ clear: () => void;
9
+ setConnected: (v: boolean) => void;
10
+ }
11
+
12
+ export const useEventStore = create<EventStore>((set) => ({
13
+ events: [],
14
+ connected: false,
15
+ push: (e) => set((s) => ({ events: [e, ...s.events].slice(0, 20) })),
16
+ clear: () => set({ events: [] }),
17
+ setConnected: (v) => set({ connected: v }),
18
+ }));