ArshVerma commited on
Commit
adea8c3
·
1 Parent(s): bff00f6

feat: finalize CodeLens. rebranding and production environment polish

Browse files

- Complete transition to CodeLens identity across all source code and documents
- Integrate high-precision SVG logo and signature red-dot favicon
- Optimize Dashboard header with minimalist monospaced typography
- Fix backend static routing in app.py to correctly serve root brand assets
- Create GET_STARTED.md with troubleshooting for venv and database initialization
- Standardize all CLI commands (migrate.py init) and Docker tags
- Resolve Tailwind CSS linting warnings and refactor app startup to lifespan pattern

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/logo.svg +3 -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 +3 -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/logo.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/logo.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
+ }));