diff --git a/README.md b/README.md index 6f250e5..b512d5d 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Experiments with Google Agent Development Kit (ADK) for building AI agents with local Ollama models and Prefect workflows. +> The **Delta Command** engineering ops dashboard previously lived at `apps/delta-command/` and now has its own home at [nfaggian/delta-tools](https://github.com/nfaggian/delta-tools). + ## Quick Start ```bash diff --git a/apps/delta-command/.gitignore b/apps/delta-command/.gitignore deleted file mode 100644 index eb5c60a..0000000 --- a/apps/delta-command/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# Testing -/coverage - -# Next.js -/.next/ -/out/ - -# Production -/build - -# Misc -.DS_Store -*.pem - -# Debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Local env files -.env*.local - -# Vercel -.vercel - -# TypeScript -*.tsbuildinfo -next-env.d.ts - -# Next.js build output -/.next/ -/out/ - -# Legacy JSON store -/data/ diff --git a/apps/delta-command/Makefile b/apps/delta-command/Makefile deleted file mode 100644 index c98fa88..0000000 --- a/apps/delta-command/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -.PHONY: install backend-install frontend-install dev backend frontend test build - -install: backend-install frontend-install - -backend-install: - cd backend && uv sync - -frontend-install: - npm install - -dev: - @echo "Start backend: make backend" - @echo "Start frontend: make frontend" - -backend: - cd backend && uv run delta-command - -frontend: - npm run dev - -test: - cd backend && uv run pytest - npm run build - -build: - npm run build diff --git a/apps/delta-command/README.md b/apps/delta-command/README.md deleted file mode 100644 index 7331d6a..0000000 --- a/apps/delta-command/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# Delta Command - -A polished engineering operations dashboard for delta engineering teams. Track the opportunity pipeline, team utilization, and active project delivery — built for both engineers and leadership. - -## Architecture - -| Layer | Stack | -|-------|-------| -| **Frontend** | Next.js 15, TypeScript, Tailwind CSS, Recharts | -| **Backend** | Python 3.12+, FastAPI, Pydantic | -| **Database** | Single JSON file (`backend/config/data.json`) | -| **Dependencies** | [UV](https://docs.astral.sh/uv/) (Python), npm (frontend) | - -## Quick Start - -### 1. Backend (Python + UV) - -```bash -cd apps/delta-command/backend -uv sync -uv run delta-command -``` - -API runs at http://127.0.0.1:8000 - -### 2. Frontend (Next.js) - -In a second terminal: - -```bash -cd apps/delta-command -npm install -npm run dev -``` - -Open http://localhost:3000 — API requests are proxied to the Python backend. - -Or use the Makefile from `apps/delta-command/`: - -```bash -make install # install both -make backend # start API -make frontend # start UI -make test # run backend tests + frontend build -``` - -## Database - -All data lives in **one JSON file**: - -``` -backend/config/data.json -``` - -Every API read and write uses this file. UI edits (opportunity stages, project status, utilization timeline cells) are saved directly to disk via atomic JSON writes. - -Customize your team by editing `data.json`, or regenerate a 30-engineer roster: - -```bash -cd backend && uv run python scripts/seed_team.py -``` - -### Example JSON structure - -```json -{ - "lastUpdated": "2026-07-04T12:00:00Z", - "engineers": [ - { - "id": "eng-1", - "name": "Sarah Chen", - "role": "Principal Engineer", - "utilization": 95, - "status": "allocated", - "skills": ["Architecture", "Cloud"], - "currentProjects": ["proj-1"] - } - ], - "opportunities": [ - { - "id": "opp-1", - "title": "Enterprise Data Platform", - "client": "Meridian Financial", - "stage": "negotiation", - "value": 850000, - "probability": 75 - } - ], - "projects": [ - { - "id": "proj-1", - "name": "Core Banking Migration", - "status": "active", - "progress": 68, - "milestones": [ - { - "id": "ms-1", - "title": "Architecture Sign-off", - "dueDate": "2026-02-15", - "completed": true - } - ] - } - ] -} -``` - -Persistence is handled by `delta_command/json_db.py` (I/O) and `delta_command/store.py` (domain operations). - -## Features - -- **Executive Dashboard** — KPIs, pipeline funnel, utilization charts, at-risk alerts -- **Opportunity Pipeline** — Kanban board with stage management (persisted) -- **Team Utilization** — Editable timeline grid (persisted) -- **Project Execution** — Progress, budget, milestone tracking with status updates (persisted) - -## Environment Variables - -| Variable | Default | Description | -|----------|---------|-------------| -| `DELTA_API_URL` | `http://127.0.0.1:8000` | Backend URL (Next.js server-side) | -| `DELTA_DATA_PATH` | `backend/config/data.json` | JSON database file | -| `DELTA_HOST` / `DELTA_PORT` | `127.0.0.1` / `8000` | API bind address | - -`DELTA_CONFIG_PATH` is supported as an alias for `DELTA_DATA_PATH`. - -## Production - -```bash -# Backend -cd backend && uv sync --no-dev && uv run uvicorn delta_command.main:app --host 0.0.0.0 --port 8000 - -# Frontend -npm run build && npm start -``` - -For production at scale, replace the JSON file store with PostgreSQL by extending `delta_command/store.py` — the Pydantic models and API routes can stay the same. diff --git a/apps/delta-command/backend/.gitignore b/apps/delta-command/backend/.gitignore deleted file mode 100644 index 722fb86..0000000 --- a/apps/delta-command/backend/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.venv/ -__pycache__/ -*.py[cod] -.pytest_cache/ -.ruff_cache/ -config/runtime.json -config/runtime.yaml diff --git a/apps/delta-command/backend/README.md b/apps/delta-command/backend/README.md deleted file mode 100644 index 2fa416b..0000000 --- a/apps/delta-command/backend/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# Delta Command Backend - -Python API for Delta Command, backed by a single JSON file database. - -## Setup - -```bash -cd apps/delta-command/backend -uv sync -``` - -## Run - -```bash -uv run delta-command -``` - -API available at http://127.0.0.1:8000 - -## Database - -All data is stored in **`config/data.json`** — one file for reads and writes. - -UI changes (opportunity stages, project status, utilization timeline) persist directly to this file. - -Override the path with `DELTA_DATA_PATH`. - -Persistence uses atomic JSON writes via `delta_command/json_db.py`. diff --git a/apps/delta-command/backend/config/data.json b/apps/delta-command/backend/config/data.json deleted file mode 100644 index 1b8d2db..0000000 --- a/apps/delta-command/backend/config/data.json +++ /dev/null @@ -1,2338 +0,0 @@ -{ - "engineers": [ - { - "id": "eng-1", - "name": "Sarah Chen", - "role": "Senior Engineer", - "email": "sarah.chen@company.com", - "capacity": 100, - "utilization": 38, - "status": "available", - "skills": [ - "Data Pipelines", - "PostgreSQL", - "Kubernetes", - "Go" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 32, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 30, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 28, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 41, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 39, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 37, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 50, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 48, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-2", - "name": "Marcus Webb", - "role": "Senior Engineer", - "email": "marcus.webb@company.com", - "capacity": 100, - "utilization": 104, - "status": "overallocated", - "skills": [ - "TypeScript", - "Python", - "React", - "GCP", - "Data Pipelines" - ], - "currentProjects": [ - "proj-10" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 98, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 96, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 94, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 107, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 105, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 103, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 116, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 114, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-3", - "name": "Priya Sharma", - "role": "Senior Engineer", - "email": "priya.sharma@company.com", - "capacity": 100, - "utilization": 38, - "status": "available", - "skills": [ - "Frontend", - "FinTech", - "Data Pipelines" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 32, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 30, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 28, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 41, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 39, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 37, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 50, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 48, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-4", - "name": "James OBrien", - "role": "Senior Engineer", - "email": "james.obrien@company.com", - "capacity": 100, - "utilization": 70, - "status": "allocated", - "skills": [ - "DevOps", - "ML", - "Kubernetes", - "GCP", - "PostgreSQL" - ], - "currentProjects": [ - "proj-3" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 64, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 62, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 60, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 73, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 71, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 69, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 82, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 80, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-5", - "name": "Elena Rodriguez", - "role": "Engineer", - "email": "elena.rodriguez@company.com", - "capacity": 100, - "utilization": 83, - "status": "allocated", - "skills": [ - "PostgreSQL", - "ML", - "TypeScript", - "Analytics" - ], - "currentProjects": [ - "proj-6" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 77, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 75, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 73, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 86, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 84, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 82, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 95, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 93, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-6", - "name": "David Kim", - "role": "Senior Engineer", - "email": "david.kim@company.com", - "capacity": 100, - "utilization": 83, - "status": "allocated", - "skills": [ - "PostgreSQL", - "Architecture", - "GCP", - "React" - ], - "currentProjects": [ - "proj-9" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 77, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 75, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 73, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 86, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 84, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 82, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 95, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 93, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-7", - "name": "Amara Okonkwo", - "role": "Engineer", - "email": "amara.okonkwo@company.com", - "capacity": 100, - "utilization": 64, - "status": "allocated", - "skills": [ - "Mobile", - "ML" - ], - "currentProjects": [ - "proj-2", - "proj-4" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 58, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 56, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 54, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 67, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 65, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 63, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 76, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 74, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-8", - "name": "Tyler Foster", - "role": "Senior Engineer", - "email": "tyler.foster@company.com", - "capacity": 100, - "utilization": 81, - "status": "allocated", - "skills": [ - "GCP", - "ML", - "React", - "AWS" - ], - "currentProjects": [ - "proj-6" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 75, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 73, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 71, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 84, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 82, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 80, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 93, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 91, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-9", - "name": "Nina Patel", - "role": "Senior Engineer", - "email": "nina.patel@company.com", - "capacity": 100, - "utilization": 66, - "status": "allocated", - "skills": [ - "ML", - "Frontend", - "Data Pipelines", - "DevOps", - "TypeScript" - ], - "currentProjects": [ - "proj-8" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 60, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 58, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 56, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 69, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 67, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 65, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 78, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 76, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-10", - "name": "Omar Hassan", - "role": "Engineer", - "email": "omar.hassan@company.com", - "capacity": 100, - "utilization": 39, - "status": "available", - "skills": [ - "Mobile", - "ML", - "React", - "GCP" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 33, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 31, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 29, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 42, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 40, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 38, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 51, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 49, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-11", - "name": "Lisa Nguyen", - "role": "Principal Engineer", - "email": "lisa.nguyen@company.com", - "capacity": 100, - "utilization": 107, - "status": "overallocated", - "skills": [ - "Analytics", - "Kubernetes", - "ML", - "CI/CD", - "Data Pipelines" - ], - "currentProjects": [ - "proj-6", - "proj-4", - "proj-8" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 101, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 99, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 97, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 110, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 108, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 106, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 119, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 117, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-12", - "name": "Ryan Cooper", - "role": "Staff Engineer", - "email": "ryan.cooper@company.com", - "capacity": 100, - "utilization": 103, - "status": "overallocated", - "skills": [ - "Architecture", - "Data Pipelines", - "Kubernetes", - "Backend", - "Cloud" - ], - "currentProjects": [ - "proj-10", - "proj-7" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 97, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 95, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 93, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 106, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 104, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 102, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 115, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 113, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-13", - "name": "Keiko Tanaka", - "role": "Engineer", - "email": "keiko.tanaka@company.com", - "capacity": 100, - "utilization": 41, - "status": "available", - "skills": [ - "Kubernetes", - "AWS" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 35, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 33, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 31, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 44, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 42, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 40, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 53, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 51, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-14", - "name": "Andre Silva", - "role": "Staff Engineer", - "email": "andre.silva@company.com", - "capacity": 100, - "utilization": 89, - "status": "allocated", - "skills": [ - "Backend", - "ML", - "Frontend", - "Python", - "Go" - ], - "currentProjects": [ - "proj-2", - "proj-7", - "proj-9" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 83, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 81, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 79, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 92, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 90, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 88, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 101, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 99, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-15", - "name": "Sophie Martin", - "role": "Senior Engineer", - "email": "sophie.martin@company.com", - "capacity": 100, - "utilization": 103, - "status": "overallocated", - "skills": [ - "FinTech", - "AWS", - "Analytics", - "Python" - ], - "currentProjects": [ - "proj-6", - "proj-2" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 97, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 95, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 93, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 106, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 104, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 102, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 115, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 113, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-16", - "name": "Carlos Rivera", - "role": "Engineering Manager", - "email": "carlos.rivera@company.com", - "capacity": 100, - "utilization": 68, - "status": "allocated", - "skills": [ - "Backend", - "GCP", - "Kubernetes", - "Architecture" - ], - "currentProjects": [ - "proj-3", - "proj-9", - "proj-2" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 62, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 60, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 58, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 71, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 69, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 67, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 80, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 78, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-17", - "name": "Maya Brooks", - "role": "Staff Engineer", - "email": "maya.brooks@company.com", - "capacity": 100, - "utilization": 104, - "status": "overallocated", - "skills": [ - "Go", - "Architecture" - ], - "currentProjects": [ - "proj-1", - "proj-6", - "proj-8" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 98, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 96, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 94, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 107, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 105, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 103, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 116, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 114, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-18", - "name": "Ethan Clark", - "role": "Principal Engineer", - "email": "ethan.clark@company.com", - "capacity": 100, - "utilization": 74, - "status": "allocated", - "skills": [ - "CI/CD", - "React", - "PostgreSQL" - ], - "currentProjects": [ - "proj-1" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 68, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 66, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 64, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 77, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 75, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 73, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 86, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 84, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-19", - "name": "Aisha Williams", - "role": "Staff Engineer", - "email": "aisha.williams@company.com", - "capacity": 100, - "utilization": 43, - "status": "available", - "skills": [ - "Kubernetes", - "Cloud", - "Frontend" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 37, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 35, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 33, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 46, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 44, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 42, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 55, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 53, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-20", - "name": "Ben Carter", - "role": "Engineer", - "email": "ben.carter@company.com", - "capacity": 100, - "utilization": 102, - "status": "overallocated", - "skills": [ - "Mobile", - "Architecture", - "Analytics", - "Backend" - ], - "currentProjects": [ - "proj-7", - "proj-4", - "proj-9" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 96, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 94, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 92, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 105, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 103, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 101, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 114, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 112, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-21", - "name": "Chloe Davis", - "role": "Senior Engineer", - "email": "chloe.davis@company.com", - "capacity": 100, - "utilization": 66, - "status": "allocated", - "skills": [ - "Python", - "CI/CD", - "Frontend", - "Data Pipelines" - ], - "currentProjects": [ - "proj-2" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 60, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 58, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 56, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 69, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 67, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 65, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 78, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 76, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-22", - "name": "Daniel Evans", - "role": "Senior Engineer", - "email": "daniel.evans@company.com", - "capacity": 100, - "utilization": 35, - "status": "available", - "skills": [ - "TypeScript", - "Data Pipelines" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 29, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 27, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 25, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 38, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 36, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 34, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 47, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 45, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-23", - "name": "Fatima Ali", - "role": "Engineer", - "email": "fatima.ali@company.com", - "capacity": 100, - "utilization": 39, - "status": "available", - "skills": [ - "React", - "Backend", - "Data Pipelines", - "ML" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 33, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 31, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 29, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 42, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 40, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 38, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 51, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 49, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-24", - "name": "Greg Murphy", - "role": "Senior Engineer", - "email": "greg.murphy@company.com", - "capacity": 100, - "utilization": 62, - "status": "allocated", - "skills": [ - "FinTech", - "GCP", - "Go", - "Frontend", - "PostgreSQL" - ], - "currentProjects": [ - "proj-3", - "proj-8", - "proj-4" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 56, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 54, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 52, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 65, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 63, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 61, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 74, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 72, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-25", - "name": "Hannah Lee", - "role": "Senior Engineer", - "email": "hannah.lee@company.com", - "capacity": 100, - "utilization": 87, - "status": "allocated", - "skills": [ - "Mobile", - "DevOps" - ], - "currentProjects": [ - "proj-1", - "proj-2" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 81, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 79, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 77, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 90, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 88, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 86, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 99, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 97, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-26", - "name": "Ivan Petrov", - "role": "Staff Engineer", - "email": "ivan.petrov@company.com", - "capacity": 100, - "utilization": 48, - "status": "available", - "skills": [ - "GCP", - "PostgreSQL", - "Frontend" - ], - "currentProjects": [], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 42, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 40, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 38, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 51, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 49, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 47, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 60, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 58, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-27", - "name": "Julia Santos", - "role": "Senior Engineer", - "email": "julia.santos@company.com", - "capacity": 100, - "utilization": 89, - "status": "allocated", - "skills": [ - "Data Pipelines", - "React", - "Analytics", - "Go", - "TypeScript" - ], - "currentProjects": [ - "proj-5" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 83, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 81, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 79, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 92, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 90, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 88, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 101, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 99, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-28", - "name": "Kevin Wright", - "role": "Senior Engineer", - "email": "kevin.wright@company.com", - "capacity": 100, - "utilization": 104, - "status": "overallocated", - "skills": [ - "AWS", - "FinTech", - "Cloud" - ], - "currentProjects": [ - "proj-2" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 98, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 96, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 94, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 107, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 105, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 103, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 116, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 114, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-29", - "name": "Luna Zhang", - "role": "Senior Engineer", - "email": "luna.zhang@company.com", - "capacity": 100, - "utilization": 86, - "status": "allocated", - "skills": [ - "Python", - "Mobile", - "ML", - "Analytics", - "Security" - ], - "currentProjects": [ - "proj-3" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 80, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 78, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 76, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 89, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 87, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 85, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 98, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 96, - "note": null - } - ], - "avatar": null - }, - { - "id": "eng-30", - "name": "Noah Adams", - "role": "Senior Engineer", - "email": "noah.adams@company.com", - "capacity": 100, - "utilization": 106, - "status": "overallocated", - "skills": [ - "GCP", - "TypeScript", - "Frontend", - "CI/CD" - ], - "currentProjects": [ - "proj-8", - "proj-3", - "proj-4" - ], - "utilizationTimeline": [ - { - "weekStart": "2026-06-15", - "utilization": 100, - "note": null - }, - { - "weekStart": "2026-06-22", - "utilization": 98, - "note": null - }, - { - "weekStart": "2026-06-29", - "utilization": 96, - "note": null - }, - { - "weekStart": "2026-07-06", - "utilization": 109, - "note": null - }, - { - "weekStart": "2026-07-13", - "utilization": 107, - "note": null - }, - { - "weekStart": "2026-07-20", - "utilization": 105, - "note": null - }, - { - "weekStart": "2026-07-27", - "utilization": 118, - "note": null - }, - { - "weekStart": "2026-08-03", - "utilization": 116, - "note": null - } - ], - "avatar": null - } - ], - "opportunities": [ - { - "id": "opp-1", - "title": "Enterprise Data Platform Modernization", - "client": "Meridian Financial", - "stage": "negotiation", - "value": 850000, - "probability": 75, - "owner": "Sarah Chen", - "expectedClose": "2026-07-15", - "description": "Full-stack data platform migration from legacy on-prem to cloud-native architecture.", - "tags": [ - "Data", - "Cloud", - "Enterprise" - ], - "createdAt": "2026-03-01", - "updatedAt": "2026-06-28" - }, - { - "id": "opp-2", - "title": "AI-Powered Customer Analytics Suite", - "client": "RetailMax Group", - "stage": "proposal", - "value": 620000, - "probability": 55, - "owner": "Elena Rodriguez", - "expectedClose": "2026-08-01", - "description": "Build ML-driven analytics dashboard for customer behavior prediction and segmentation.", - "tags": [ - "AI/ML", - "Analytics", - "Retail" - ], - "createdAt": "2026-04-10", - "updatedAt": "2026-06-25" - }, - { - "id": "opp-3", - "title": "Zero-Trust Security Architecture", - "client": "HealthFirst Systems", - "stage": "qualified", - "value": 480000, - "probability": 40, - "owner": "David Kim", - "expectedClose": "2026-09-15", - "description": "Design and implement zero-trust security framework for healthcare data systems.", - "tags": [ - "Security", - "Healthcare", - "Compliance" - ], - "createdAt": "2026-05-01", - "updatedAt": "2026-06-20" - }, - { - "id": "opp-4", - "title": "Mobile Banking App Redesign", - "client": "Coastal Credit Union", - "stage": "prospect", - "value": 320000, - "probability": 20, - "owner": "Amara Okonkwo", - "expectedClose": "2026-10-01", - "description": "Complete redesign of mobile banking experience with biometric auth and real-time notifications.", - "tags": [ - "Mobile", - "FinTech", - "UX" - ], - "createdAt": "2026-06-01", - "updatedAt": "2026-06-15" - }, - { - "id": "opp-5", - "title": "Supply Chain Visibility Platform", - "client": "GlobalLogistics Inc", - "stage": "proposal", - "value": 750000, - "probability": 60, - "owner": "Marcus Webb", - "expectedClose": "2026-07-30", - "description": "Real-time supply chain tracking and predictive delay analytics platform.", - "tags": [ - "IoT", - "Logistics", - "Real-time" - ], - "createdAt": "2026-04-20", - "updatedAt": "2026-06-27" - }, - { - "id": "opp-6", - "title": "Legacy ERP Integration Hub", - "client": "ManufactureCo", - "stage": "won", - "value": 540000, - "probability": 100, - "owner": "Thomas Berg", - "expectedClose": "2026-06-01", - "description": "Integration middleware connecting SAP, Salesforce, and custom manufacturing systems.", - "tags": [ - "Integration", - "ERP", - "Manufacturing" - ], - "createdAt": "2026-01-15", - "updatedAt": "2026-06-01" - }, - { - "id": "opp-7", - "title": "Cloud Cost Optimization Program", - "client": "TechVentures Ltd", - "stage": "qualified", - "value": 180000, - "probability": 35, - "owner": "James O'Brien", - "expectedClose": "2026-08-15", - "description": "Audit and optimize multi-cloud infrastructure spending with automated right-sizing.", - "tags": [ - "Cloud", - "FinOps", - "Optimization" - ], - "createdAt": "2026-05-15", - "updatedAt": "2026-06-22" - }, - { - "id": "opp-8", - "title": "Digital Twin for Smart Factory", - "client": "AutoParts Global", - "stage": "lost", - "value": 920000, - "probability": 0, - "owner": "Sarah Chen", - "expectedClose": "2026-05-30", - "description": "IoT-enabled digital twin platform for predictive maintenance in automotive manufacturing.", - "tags": [ - "IoT", - "Digital Twin", - "Manufacturing" - ], - "createdAt": "2026-02-01", - "updatedAt": "2026-05-30" - } - ], - "projects": [ - { - "id": "proj-1", - "name": "Meridian Core Banking Migration", - "client": "Meridian Financial", - "status": "active", - "progress": 68, - "startDate": "2026-01-15", - "endDate": "2026-09-30", - "budget": 720000, - "spent": 489600, - "leadEngineer": "Sarah Chen", - "team": [ - "eng-1", - "eng-2" - ], - "description": "Migrating core banking systems to cloud-native microservices architecture.", - "milestones": [ - { - "id": "ms-1", - "title": "Architecture Sign-off", - "dueDate": "2026-02-15", - "completed": true - }, - { - "id": "ms-2", - "title": "Phase 1 Migration", - "dueDate": "2026-05-01", - "completed": true - }, - { - "id": "ms-3", - "title": "Integration Testing", - "dueDate": "2026-07-15", - "completed": false - }, - { - "id": "ms-4", - "title": "Production Cutover", - "dueDate": "2026-09-30", - "completed": false - } - ], - "opportunityId": null - }, - { - "id": "proj-2", - "name": "RetailMax Analytics Dashboard", - "client": "RetailMax Group", - "status": "active", - "progress": 42, - "startDate": "2026-03-01", - "endDate": "2026-10-15", - "budget": 450000, - "spent": 189000, - "leadEngineer": "Priya Sharma", - "team": [ - "eng-2", - "eng-3", - "eng-8" - ], - "description": "Customer analytics dashboard with real-time KPI tracking and drill-down capabilities.", - "milestones": [ - { - "id": "ms-5", - "title": "UI/UX Prototype", - "dueDate": "2026-04-01", - "completed": true - }, - { - "id": "ms-6", - "title": "Data Pipeline MVP", - "dueDate": "2026-06-15", - "completed": true - }, - { - "id": "ms-7", - "title": "Beta Release", - "dueDate": "2026-08-01", - "completed": false - }, - { - "id": "ms-8", - "title": "GA Launch", - "dueDate": "2026-10-15", - "completed": false - } - ], - "opportunityId": "opp-2" - }, - { - "id": "proj-3", - "name": "HealthFirst Compliance Portal", - "client": "HealthFirst Systems", - "status": "at_risk", - "progress": 55, - "startDate": "2026-02-01", - "endDate": "2026-08-01", - "budget": 380000, - "spent": 209000, - "leadEngineer": "Sarah Chen", - "team": [ - "eng-1", - "eng-4" - ], - "description": "HIPAA-compliant patient data portal with audit logging and access controls.", - "milestones": [ - { - "id": "ms-9", - "title": "Security Audit", - "dueDate": "2026-03-15", - "completed": true - }, - { - "id": "ms-10", - "title": "Compliance Review", - "dueDate": "2026-06-01", - "completed": false - }, - { - "id": "ms-11", - "title": "Penetration Testing", - "dueDate": "2026-07-01", - "completed": false - } - ], - "opportunityId": null - }, - { - "id": "proj-4", - "name": "GlobalLogistics Tracking MVP", - "client": "GlobalLogistics Inc", - "status": "planning", - "progress": 15, - "startDate": "2026-06-01", - "endDate": "2026-11-30", - "budget": 600000, - "spent": 90000, - "leadEngineer": "Marcus Webb", - "team": [ - "eng-2", - "eng-5" - ], - "description": "Minimum viable product for real-time shipment tracking across global logistics network.", - "milestones": [ - { - "id": "ms-12", - "title": "Requirements Finalization", - "dueDate": "2026-06-30", - "completed": false - }, - { - "id": "ms-13", - "title": "Prototype Demo", - "dueDate": "2026-08-15", - "completed": false - } - ], - "opportunityId": "opp-5" - }, - { - "id": "proj-5", - "name": "ManufactureCo ERP Integration", - "client": "ManufactureCo", - "status": "active", - "progress": 78, - "startDate": "2026-03-15", - "endDate": "2026-07-30", - "budget": 540000, - "spent": 421200, - "leadEngineer": "Thomas Berg", - "team": [ - "eng-6", - "eng-8" - ], - "description": "Middleware integration hub connecting SAP, Salesforce, and MES systems.", - "milestones": [ - { - "id": "ms-14", - "title": "SAP Connector", - "dueDate": "2026-04-30", - "completed": true - }, - { - "id": "ms-15", - "title": "Salesforce Sync", - "dueDate": "2026-06-01", - "completed": true - }, - { - "id": "ms-16", - "title": "End-to-End Testing", - "dueDate": "2026-07-15", - "completed": false - }, - { - "id": "ms-17", - "title": "Go-Live", - "dueDate": "2026-07-30", - "completed": false - } - ], - "opportunityId": "opp-6" - }, - { - "id": "proj-6", - "name": "API Gateway Modernization", - "client": "TechVentures Ltd", - "status": "planning", - "progress": 12, - "startDate": "2026-03-01", - "endDate": "2026-11-30", - "budget": 572154, - "spent": 122209, - "leadEngineer": "Marcus Webb", - "team": [ - "eng-19", - "eng-16" - ], - "description": "Delivery initiative for TechVentures Ltd.", - "milestones": [ - { - "id": "ms-6-1", - "title": "Kickoff", - "dueDate": "2026-04-15", - "completed": false - }, - { - "id": "ms-6-2", - "title": "MVP Delivery", - "dueDate": "2026-08-01", - "completed": false - } - ] - }, - { - "id": "proj-7", - "name": "Customer Identity Platform", - "client": "Meridian Financial", - "status": "active", - "progress": 45, - "startDate": "2026-03-01", - "endDate": "2026-11-30", - "budget": 443638, - "spent": 263535, - "leadEngineer": "Maya Brooks", - "team": [ - "eng-2", - "eng-17" - ], - "description": "Delivery initiative for Meridian Financial.", - "milestones": [ - { - "id": "ms-7-1", - "title": "Kickoff", - "dueDate": "2026-04-15", - "completed": true - }, - { - "id": "ms-7-2", - "title": "MVP Delivery", - "dueDate": "2026-08-01", - "completed": false - } - ] - }, - { - "id": "proj-8", - "name": "IoT Fleet Monitoring", - "client": "GlobalLogistics Inc", - "status": "active", - "progress": 62, - "startDate": "2026-03-01", - "endDate": "2026-11-30", - "budget": 222001, - "spent": 263174, - "leadEngineer": "David Kim", - "team": [ - "eng-20", - "eng-3" - ], - "description": "Delivery initiative for GlobalLogistics Inc.", - "milestones": [ - { - "id": "ms-8-1", - "title": "Kickoff", - "dueDate": "2026-04-15", - "completed": true - }, - { - "id": "ms-8-2", - "title": "MVP Delivery", - "dueDate": "2026-08-01", - "completed": true - } - ] - }, - { - "id": "proj-9", - "name": "Regulatory Reporting Automation", - "client": "HealthFirst Systems", - "status": "planning", - "progress": 8, - "startDate": "2026-03-01", - "endDate": "2026-11-30", - "budget": 534005, - "spent": 265920, - "leadEngineer": "Tyler Foster", - "team": [ - "eng-4", - "eng-29", - "eng-19" - ], - "description": "Delivery initiative for HealthFirst Systems.", - "milestones": [ - { - "id": "ms-9-1", - "title": "Kickoff", - "dueDate": "2026-04-15", - "completed": false - }, - { - "id": "ms-9-2", - "title": "MVP Delivery", - "dueDate": "2026-08-01", - "completed": false - } - ] - }, - { - "id": "proj-10", - "name": "Real-time Fraud Detection", - "client": "Coastal Credit Union", - "status": "active", - "progress": 38, - "startDate": "2026-03-01", - "endDate": "2026-11-30", - "budget": 309087, - "spent": 191760, - "leadEngineer": "Ben Carter", - "team": [ - "eng-20", - "eng-3" - ], - "description": "Delivery initiative for Coastal Credit Union.", - "milestones": [ - { - "id": "ms-10-1", - "title": "Kickoff", - "dueDate": "2026-04-15", - "completed": true - }, - { - "id": "ms-10-2", - "title": "MVP Delivery", - "dueDate": "2026-08-01", - "completed": false - } - ] - } - ], - "lastUpdated": "2026-07-04T13:40:00Z" -} diff --git a/apps/delta-command/backend/pyproject.toml b/apps/delta-command/backend/pyproject.toml deleted file mode 100644 index 3bdbe90..0000000 --- a/apps/delta-command/backend/pyproject.toml +++ /dev/null @@ -1,38 +0,0 @@ -[project] -name = "delta-command" -version = "1.0.0" -description = "Delta Command engineering operations API" -readme = "README.md" -requires-python = ">=3.12" -dependencies = [ - "fastapi>=0.115.0", - "uvicorn[standard]>=0.34.0", - "pydantic>=2.10.0", -] - -[project.scripts] -delta-command = "delta_command.main:run" - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["src/delta_command"] - -[dependency-groups] -dev = [ - "httpx>=0.28.0", - "pytest>=8.3.0", - "ruff>=0.11.0", -] - -[tool.ruff] -line-length = 100 -target-version = "py312" - -[tool.ruff.lint] -select = ["E", "F", "I", "UP"] - -[tool.pytest.ini_options] -testpaths = ["tests"] diff --git a/apps/delta-command/backend/scripts/seed_team.py b/apps/delta-command/backend/scripts/seed_team.py deleted file mode 100644 index 2b4c7be..0000000 --- a/apps/delta-command/backend/scripts/seed_team.py +++ /dev/null @@ -1,106 +0,0 @@ -"""Generate a 30-engineer seed dataset for config/data.json.""" - -from __future__ import annotations - -import json -import random -from datetime import date, timedelta -from pathlib import Path - -FIRST = [ - "Sarah", "Marcus", "Priya", "James", "Elena", "David", "Amara", "Tyler", "Nina", "Omar", - "Lisa", "Ryan", "Keiko", "Andre", "Sophie", "Carlos", "Maya", "Ethan", "Aisha", "Ben", - "Chloe", "Daniel", "Fatima", "Greg", "Hannah", "Ivan", "Julia", "Kevin", "Luna", "Noah", -] -LAST = [ - "Chen", "Webb", "Sharma", "OBrien", "Rodriguez", "Kim", "Okonkwo", "Foster", "Patel", "Hassan", - "Nguyen", "Cooper", "Tanaka", "Silva", "Martin", "Rivera", "Brooks", "Clark", "Williams", "Carter", - "Davis", "Evans", "Ali", "Murphy", "Lee", "Petrov", "Santos", "Wright", "Zhang", "Adams", -] -ROLES = [ - ("Engineer", 0.35), - ("Senior Engineer", 0.35), - ("Staff Engineer", 0.15), - ("Principal Engineer", 0.1), - ("Engineering Manager", 0.05), -] -SKILLS = [ - "Python", "TypeScript", "React", "Go", "Kubernetes", "AWS", "GCP", "Data Pipelines", "ML", - "Security", "DevOps", "Architecture", "Mobile", "FinTech", "Analytics", "Cloud", "Backend", - "Frontend", "CI/CD", "PostgreSQL", -] -PROJECT_IDS = [f"proj-{i}" for i in range(1, 11)] - - -def pick_role(rng: random.Random) -> str: - roll = rng.random() - cumulative = 0.0 - for role, weight in ROLES: - cumulative += weight - if roll <= cumulative: - return role - return "Engineer" - - -def week_start(value: date) -> date: - return value - timedelta(days=value.weekday()) - - -def build_timeline(base: int, rng: random.Random) -> list[dict]: - today = date.today() - current = week_start(today) - start = current - timedelta(weeks=2) - timeline: list[dict] = [] - for index in range(8): - week = start + timedelta(weeks=index) - drift = (index - 2) * 3 - value = max(0, min(150, base + drift - (index % 3) * 5 + rng.randint(-2, 2))) - timeline.append({"weekStart": week.isoformat(), "utilization": value, "note": None}) - return timeline - - -def status_for(utilization: int) -> str: - if utilization >= 100: - return "overallocated" - if utilization >= 50: - return "allocated" - return "available" - - -def build_engineers(count: int = 30, seed: int = 42) -> list[dict]: - rng = random.Random(seed) - engineers: list[dict] = [] - for index in range(count): - first, last = FIRST[index], LAST[index] - utilization = rng.randint(35, 115) - project_count = 0 if utilization < 55 else rng.randint(1, 3) - projects = rng.sample(PROJECT_IDS, k=min(project_count, len(PROJECT_IDS))) if project_count else [] - engineers.append( - { - "id": f"eng-{index + 1}", - "name": f"{first} {last}", - "role": pick_role(rng), - "email": f"{first.lower()}.{last.lower()}@company.com", - "capacity": 100, - "utilization": utilization, - "status": status_for(utilization), - "skills": rng.sample(SKILLS, k=rng.randint(2, 5)), - "currentProjects": projects, - "utilizationTimeline": build_timeline(utilization, rng), - "avatar": None, - } - ) - return engineers - - -def main() -> None: - config_path = Path(__file__).resolve().parents[1] / "config" / "data.json" - data = json.loads(config_path.read_text(encoding="utf-8")) - data["engineers"] = build_engineers() - data["lastUpdated"] = date.today().isoformat() + "T12:00:00Z" - config_path.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") - print(f"Wrote {len(data['engineers'])} engineers to {config_path}") - - -if __name__ == "__main__": - main() diff --git a/apps/delta-command/backend/src/delta_command/__init__.py b/apps/delta-command/backend/src/delta_command/__init__.py deleted file mode 100644 index 464cd59..0000000 --- a/apps/delta-command/backend/src/delta_command/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -"""Delta Command — engineering operations API.""" - -__version__ = "1.0.0" diff --git a/apps/delta-command/backend/src/delta_command/json_db.py b/apps/delta-command/backend/src/delta_command/json_db.py deleted file mode 100644 index 7154461..0000000 --- a/apps/delta-command/backend/src/delta_command/json_db.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import annotations - -import json -import os -import tempfile -from pathlib import Path - -DEFAULT_DATA_PATH = Path(__file__).resolve().parents[2] / "config" / "data.json" -LEGACY_RUNTIME_PATH = Path(__file__).resolve().parents[2] / "config" / "runtime.json" - - -def database_path() -> Path: - override = os.environ.get("DELTA_DATA_PATH") or os.environ.get("DELTA_CONFIG_PATH") - if override: - return Path(override) - return DEFAULT_DATA_PATH - - -def load_json(path: Path) -> dict: - if not path.exists(): - return {} - text = path.read_text(encoding="utf-8").strip() - if not text: - return {} - return json.loads(text) - - -def save_json(path: Path, data: dict) -> None: - path.parent.mkdir(parents=True, exist_ok=True) - payload = json.dumps(data, indent=2, ensure_ascii=False) + "\n" - fd, temp_name = tempfile.mkstemp( - dir=path.parent, - prefix=f".{path.stem}-", - suffix=".tmp", - ) - temp_path = Path(temp_name) - try: - with os.fdopen(fd, "w", encoding="utf-8") as handle: - handle.write(payload) - handle.flush() - os.fsync(handle.fileno()) - temp_path.replace(path) - finally: - if temp_path.exists(): - temp_path.unlink(missing_ok=True) - - -def migrate_legacy_runtime(data_path: Path | None = None) -> None: - """One-time migration: merge legacy runtime.json into the single data file.""" - target = data_path or database_path() - legacy = LEGACY_RUNTIME_PATH - if not legacy.exists(): - return - legacy_data = load_json(legacy) - if not legacy_data.get("engineers"): - legacy.unlink(missing_ok=True) - return - save_json(target, legacy_data) - legacy.unlink(missing_ok=True) diff --git a/apps/delta-command/backend/src/delta_command/main.py b/apps/delta-command/backend/src/delta_command/main.py deleted file mode 100644 index fc66246..0000000 --- a/apps/delta-command/backend/src/delta_command/main.py +++ /dev/null @@ -1,130 +0,0 @@ -from __future__ import annotations - -import os - -import uvicorn -from fastapi import FastAPI, HTTPException -from fastapi.middleware.cors import CORSMiddleware - -from delta_command.json_db import database_path -from delta_command.metrics import compute_dashboard_metrics -from delta_command.models import ( - DashboardMetrics, - Engineer, - EngineerStatus, - EngineerUtilizationUpdate, - Opportunity, - OpportunityStageUpdate, - Project, - ProjectStatusUpdate, - UtilizationTimelineResponse, - UtilizationTimelineUpdate, -) -from delta_command.store import ( - get_utilization_timeline, - list_engineers, - load_database, - update_engineer_utilization, - update_opportunity_stage, - update_project_status, - update_timeline_cell, -) - -app = FastAPI( - title="Delta Command API", - description="Engineering operations backend for pipeline, utilization, and projects.", - version="1.0.0", -) - -app.add_middleware( - CORSMiddleware, - allow_origins=os.environ.get("DELTA_CORS_ORIGINS", "http://localhost:3000").split(","), - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - - -@app.get("/api/health") -def health() -> dict[str, str]: - return { - "status": "ok", - "datastore": "json", - "path": str(database_path()), - } - - -@app.get("/api/dashboard") -def get_dashboard() -> DashboardMetrics: - db = load_database() - return compute_dashboard_metrics(db) - - -@app.get("/api/opportunities") -def list_opportunities() -> list[Opportunity]: - return load_database().opportunities - - -@app.patch("/api/opportunities") -def patch_opportunity(body: OpportunityStageUpdate) -> Opportunity: - updated = update_opportunity_stage(body.id, body.stage) - if updated is None: - raise HTTPException(status_code=404, detail="Opportunity not found") - return updated - - -@app.get("/api/projects") -def list_projects() -> list[Project]: - return load_database().projects - - -@app.patch("/api/projects") -def patch_project(body: ProjectStatusUpdate) -> Project: - updated = update_project_status(body.id, body.status) - if updated is None: - raise HTTPException(status_code=404, detail="Project not found") - return updated - - -@app.get("/api/engineers") -def get_engineers( - search: str | None = None, - status: EngineerStatus | None = None, -) -> list[Engineer]: - return list_engineers(search=search, status=status) - - -@app.patch("/api/engineers") -def patch_engineer(body: EngineerUtilizationUpdate) -> Engineer: - updated = update_engineer_utilization(body.id, body.utilization) - if updated is None: - raise HTTPException(status_code=404, detail="Engineer not found") - return updated - - -@app.get("/api/utilization/timeline") -def get_timeline() -> UtilizationTimelineResponse: - return get_utilization_timeline() - - -@app.patch("/api/utilization/timeline") -def patch_timeline(body: UtilizationTimelineUpdate) -> UtilizationTimelineResponse: - try: - return update_timeline_cell( - body.engineer_id, - body.week_start, - body.utilization, - body.note, - ) - except ValueError as exc: - raise HTTPException(status_code=404, detail=str(exc)) from exc - - -def run() -> None: - host = os.environ.get("DELTA_HOST", "127.0.0.1") - port = int(os.environ.get("DELTA_PORT", "8000")) - uvicorn.run("delta_command.main:app", host=host, port=port, reload=True) - - -if __name__ == "__main__": - run() diff --git a/apps/delta-command/backend/src/delta_command/metrics.py b/apps/delta-command/backend/src/delta_command/metrics.py deleted file mode 100644 index a4c9bdd..0000000 --- a/apps/delta-command/backend/src/delta_command/metrics.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import annotations - -from delta_command.models import DashboardMetrics, Database, OpportunityStage, ProjectStatus - - -def compute_dashboard_metrics(db: Database) -> DashboardMetrics: - active_opportunities = [ - o for o in db.opportunities if o.stage not in (OpportunityStage.WON, OpportunityStage.LOST) - ] - pipeline_value = sum(o.value * (o.probability / 100) for o in active_opportunities) - total_pipeline = sum(o.value for o in active_opportunities) - active_projects = [ - p for p in db.projects if p.status in (ProjectStatus.ACTIVE, ProjectStatus.AT_RISK) - ] - at_risk_projects = [p for p in db.projects if p.status == ProjectStatus.AT_RISK] - avg_utilization = ( - round(sum(e.utilization for e in db.engineers) / len(db.engineers)) - if db.engineers - else 0 - ) - available_capacity = sum(1 for e in db.engineers if e.utilization < 70) - won_this_quarter = sum(1 for o in db.opportunities if o.stage == OpportunityStage.WON) - - return DashboardMetrics( - pipelineValue=pipeline_value, - totalPipeline=total_pipeline, - activeOpportunities=len(active_opportunities), - activeProjects=len(active_projects), - atRiskProjects=len(at_risk_projects), - avgUtilization=avg_utilization, - availableCapacity=available_capacity, - wonThisQuarter=won_this_quarter, - teamSize=len(db.engineers), - lastUpdated=db.last_updated, - ) diff --git a/apps/delta-command/backend/src/delta_command/models.py b/apps/delta-command/backend/src/delta_command/models.py deleted file mode 100644 index ea970d6..0000000 --- a/apps/delta-command/backend/src/delta_command/models.py +++ /dev/null @@ -1,181 +0,0 @@ -from __future__ import annotations - -from datetime import datetime -from enum import StrEnum - -from pydantic import BaseModel, ConfigDict, Field - - -class OpportunityStage(StrEnum): - PROSPECT = "prospect" - QUALIFIED = "qualified" - PROPOSAL = "proposal" - NEGOTIATION = "negotiation" - WON = "won" - LOST = "lost" - - -class ProjectStatus(StrEnum): - PLANNING = "planning" - ACTIVE = "active" - ON_HOLD = "on_hold" - COMPLETED = "completed" - AT_RISK = "at_risk" - - -class EngineerStatus(StrEnum): - AVAILABLE = "available" - ALLOCATED = "allocated" - OVERALLOCATED = "overallocated" - - -class Milestone(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - id: str - title: str - due_date: str = Field(alias="dueDate") - completed: bool - - -class UtilizationWeek(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - week_start: str = Field(alias="weekStart") - utilization: int - note: str | None = None - - -class Engineer(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - id: str - name: str - role: str - email: str - capacity: int = 100 - utilization: int - status: EngineerStatus - skills: list[str] = Field(default_factory=list) - current_projects: list[str] = Field(default_factory=list, alias="currentProjects") - utilization_timeline: list[UtilizationWeek] = Field( - default_factory=list, alias="utilizationTimeline" - ) - avatar: str | None = None - - -class Opportunity(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - id: str - title: str - client: str - stage: OpportunityStage - value: int - probability: int - owner: str - expected_close: str = Field(alias="expectedClose") - description: str - tags: list[str] = Field(default_factory=list) - created_at: str = Field(alias="createdAt") - updated_at: str = Field(alias="updatedAt") - - -class Project(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - id: str - name: str - client: str - status: ProjectStatus - progress: int - start_date: str = Field(alias="startDate") - end_date: str = Field(alias="endDate") - budget: int - spent: int - lead_engineer: str = Field(alias="leadEngineer") - team: list[str] = Field(default_factory=list) - description: str - milestones: list[Milestone] = Field(default_factory=list) - opportunity_id: str | None = Field(default=None, alias="opportunityId") - - -class Database(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - engineers: list[Engineer] = Field(default_factory=list) - opportunities: list[Opportunity] = Field(default_factory=list) - projects: list[Project] = Field(default_factory=list) - last_updated: str = Field( - default_factory=lambda: datetime.utcnow().isoformat() + "Z", - alias="lastUpdated", - ) - - -class DashboardMetrics(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - pipeline_value: float = Field(alias="pipelineValue") - total_pipeline: float = Field(alias="totalPipeline") - active_opportunities: int = Field(alias="activeOpportunities") - active_projects: int = Field(alias="activeProjects") - at_risk_projects: int = Field(alias="atRiskProjects") - avg_utilization: int = Field(alias="avgUtilization") - available_capacity: int = Field(alias="availableCapacity") - won_this_quarter: int = Field(alias="wonThisQuarter") - team_size: int = Field(alias="teamSize") - last_updated: str = Field(alias="lastUpdated") - - -class OpportunityStageUpdate(BaseModel): - id: str - stage: OpportunityStage - - -class ProjectStatusUpdate(BaseModel): - id: str - status: ProjectStatus - - -class EngineerUtilizationUpdate(BaseModel): - id: str - utilization: int - - -class UtilizationTimelineWeek(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - week_start: str = Field(alias="weekStart") - label: str - is_current: bool = Field(alias="isCurrent") - - -class UtilizationTimelineCell(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - week_start: str = Field(alias="weekStart") - utilization: int - note: str | None = None - - -class UtilizationTimelineRow(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - engineer_id: str = Field(alias="engineerId") - name: str - role: str - cells: list[UtilizationTimelineCell] - - -class UtilizationTimelineResponse(BaseModel): - weeks: list[UtilizationTimelineWeek] - rows: list[UtilizationTimelineRow] - - -class UtilizationTimelineUpdate(BaseModel): - model_config = ConfigDict(populate_by_name=True) - - engineer_id: str = Field(alias="engineerId") - week_start: str = Field(alias="weekStart") - utilization: int - note: str | None = None diff --git a/apps/delta-command/backend/src/delta_command/store.py b/apps/delta-command/backend/src/delta_command/store.py deleted file mode 100644 index ad47ae1..0000000 --- a/apps/delta-command/backend/src/delta_command/store.py +++ /dev/null @@ -1,205 +0,0 @@ -from __future__ import annotations - -from datetime import datetime, timezone - -from pydantic import TypeAdapter - -from delta_command.json_db import database_path, load_json, migrate_legacy_runtime, save_json -from delta_command.models import ( - Database, - Engineer, - Opportunity, - OpportunityStage, - Project, - ProjectStatus, - UtilizationTimelineCell, - UtilizationTimelineResponse, - UtilizationTimelineRow, - UtilizationTimelineWeek, -) -from delta_command.utilization_timeline import ( - build_week_columns, - current_week_utilization, - ensure_engineer_timeline, - status_for_utilization, -) - -DatabaseAdapter = TypeAdapter(Database) - - -def _data_path(): - path = database_path() - migrate_legacy_runtime(path) - return path - - -def load_database() -> Database: - raw = load_json(_data_path()) - return DatabaseAdapter.validate_python(raw) - - -def list_engineers( - search: str | None = None, - status: EngineerStatus | None = None, -) -> list[Engineer]: - engineers = load_database().engineers - if search: - query = search.strip().lower() - engineers = [ - engineer - for engineer in engineers - if query in engineer.name.lower() - or query in engineer.role.lower() - or query in engineer.email.lower() - ] - if status is not None: - engineers = [engineer for engineer in engineers if engineer.status == status] - return engineers - - -def save_database(db: Database) -> None: - db.last_updated = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") - payload = db.model_dump(by_alias=True, mode="json") - save_json(_data_path(), payload) - - -def update_opportunity_stage(opportunity_id: str, stage: OpportunityStage) -> Opportunity | None: - db = load_database() - for index, opportunity in enumerate(db.opportunities): - if opportunity.id != opportunity_id: - continue - updated = opportunity.model_copy( - update={ - "stage": stage, - "updated_at": datetime.now(timezone.utc).date().isoformat(), - "probability": ( - 100 - if stage == OpportunityStage.WON - else 0 - if stage == OpportunityStage.LOST - else opportunity.probability - ), - } - ) - db.opportunities[index] = updated - save_database(db) - return updated - return None - - -def update_project_status(project_id: str, status: ProjectStatus) -> Project | None: - db = load_database() - for index, project in enumerate(db.projects): - if project.id != project_id: - continue - updated = project.model_copy(update={"status": status}) - db.projects[index] = updated - save_database(db) - return updated - return None - - -def update_engineer_utilization(engineer_id: str, utilization: int) -> Engineer | None: - db = load_database() - week_columns = build_week_columns() - for index, engineer in enumerate(db.engineers): - if engineer.id != engineer_id: - continue - engineer = ensure_engineer_timeline(engineer, week_columns) - status = status_for_utilization(utilization) - timeline = list(engineer.utilization_timeline) - current = next((w for w in week_columns if w["isCurrent"]), week_columns[-1]) - for cell_index, cell in enumerate(timeline): - if cell.week_start == current["weekStart"]: - timeline[cell_index] = cell.model_copy(update={"utilization": utilization}) - break - updated = engineer.model_copy( - update={"utilization": utilization, "status": status, "utilization_timeline": timeline} - ) - db.engineers[index] = updated - save_database(db) - return updated - return None - - -def get_utilization_timeline() -> UtilizationTimelineResponse: - db = load_database() - week_columns = build_week_columns() - engineers = [ensure_engineer_timeline(e, week_columns) for e in db.engineers] - if any( - e.utilization_timeline != db.engineers[i].utilization_timeline - for i, e in enumerate(engineers) - ): - db.engineers = engineers - save_database(db) - - weeks = [ - UtilizationTimelineWeek( - weekStart=column["weekStart"], - label=column["label"], - isCurrent=column["isCurrent"], - ) - for column in week_columns - ] - rows: list[UtilizationTimelineRow] = [] - for engineer in engineers: - rows.append( - UtilizationTimelineRow( - engineerId=engineer.id, - name=engineer.name, - role=engineer.role, - cells=[ - UtilizationTimelineCell( - weekStart=cell.week_start, - utilization=cell.utilization, - note=cell.note, - ) - for cell in engineer.utilization_timeline - ], - ) - ) - return UtilizationTimelineResponse(weeks=weeks, rows=rows) - - -def update_timeline_cell( - engineer_id: str, - week_start: str, - utilization: int, - note: str | None = None, -) -> UtilizationTimelineResponse: - db = load_database() - week_columns = build_week_columns() - utilization = max(0, min(150, utilization)) - found = False - - for index, engineer in enumerate(db.engineers): - if engineer.id != engineer_id: - continue - engineer = ensure_engineer_timeline(engineer, week_columns) - timeline = list(engineer.utilization_timeline) - for cell_index, cell in enumerate(timeline): - if cell.week_start != week_start: - continue - timeline[cell_index] = cell.model_copy( - update={"utilization": utilization, "note": note} - ) - found = True - break - current_util = current_week_utilization( - engineer.model_copy(update={"utilization_timeline": timeline}), - week_columns, - ) - db.engineers[index] = engineer.model_copy( - update={ - "utilization_timeline": timeline, - "utilization": current_util, - "status": status_for_utilization(current_util), - } - ) - break - - if not found: - raise ValueError("Engineer or week not found") - - save_database(db) - return get_utilization_timeline() diff --git a/apps/delta-command/backend/src/delta_command/utilization_timeline.py b/apps/delta-command/backend/src/delta_command/utilization_timeline.py deleted file mode 100644 index 9f5c044..0000000 --- a/apps/delta-command/backend/src/delta_command/utilization_timeline.py +++ /dev/null @@ -1,86 +0,0 @@ -from __future__ import annotations - -from datetime import date, timedelta - -from delta_command.models import Engineer, EngineerStatus, UtilizationWeek - -TIMELINE_WEEKS = 8 - - -def _week_start(value: date) -> date: - return value - timedelta(days=value.weekday()) - - -def week_label(week_start: date) -> str: - return week_start.strftime("%b %d") - - -def build_week_columns(reference: date | None = None) -> list[dict]: - today = reference or date.today() - current_start = _week_start(today) - start = current_start - timedelta(weeks=2) - columns: list[dict] = [] - for offset in range(TIMELINE_WEEKS): - week_start = start + timedelta(weeks=offset) - columns.append( - { - "weekStart": week_start.isoformat(), - "label": week_label(week_start), - "isCurrent": week_start == current_start, - } - ) - return columns - - -def seed_timeline(engineer: Engineer, week_columns: list[dict]) -> list[UtilizationWeek]: - base = engineer.utilization - timeline: list[UtilizationWeek] = [] - for index, week in enumerate(week_columns): - drift = (index - 2) * 3 - value = max(0, min(150, base + drift - (index % 3) * 5)) - timeline.append( - UtilizationWeek( - weekStart=week["weekStart"], - utilization=value, - ) - ) - return timeline - - -def ensure_engineer_timeline( - engineer: Engineer, week_columns: list[dict] -) -> Engineer: - if engineer.utilization_timeline: - by_week = {item.week_start: item for item in engineer.utilization_timeline} - merged: list[UtilizationWeek] = [] - for week in week_columns: - existing = by_week.get(week["weekStart"]) - if existing: - merged.append(existing) - else: - merged.append( - UtilizationWeek( - weekStart=week["weekStart"], - utilization=engineer.utilization, - ) - ) - return engineer.model_copy(update={"utilization_timeline": merged}) - return engineer.model_copy( - update={"utilization_timeline": seed_timeline(engineer, week_columns)} - ) - - -def current_week_utilization(engineer: Engineer, week_columns: list[dict]) -> int: - current = next((w for w in week_columns if w["isCurrent"]), week_columns[-1]) - for item in engineer.utilization_timeline: - if item.week_start == current["weekStart"]: - return item.utilization - return engineer.utilization - - -def status_for_utilization(utilization: int) -> EngineerStatus: - if utilization >= 100: - return EngineerStatus.OVERALLOCATED - if utilization >= 50: - return EngineerStatus.ALLOCATED - return EngineerStatus.AVAILABLE diff --git a/apps/delta-command/backend/tests/test_api.py b/apps/delta-command/backend/tests/test_api.py deleted file mode 100644 index 8637a26..0000000 --- a/apps/delta-command/backend/tests/test_api.py +++ /dev/null @@ -1,129 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import pytest -from fastapi.testclient import TestClient - -from delta_command.json_db import load_json -from delta_command.main import app -from delta_command.metrics import compute_dashboard_metrics -from delta_command.models import Database - - -@pytest.fixture -def client(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> TestClient: - data_file = tmp_path / "data.json" - source = Path(__file__).resolve().parents[1] / "config" / "data.json" - data_file.write_text(source.read_text(encoding="utf-8"), encoding="utf-8") - monkeypatch.setenv("DELTA_DATA_PATH", str(data_file)) - return TestClient(app) - - -def test_health(client: TestClient) -> None: - response = client.get("/api/health") - assert response.status_code == 200 - payload = response.json() - assert payload["status"] == "ok" - assert payload["datastore"] == "json" - assert payload["path"].endswith("data.json") - - -def test_dashboard_metrics(client: TestClient) -> None: - response = client.get("/api/dashboard") - assert response.status_code == 200 - payload = response.json() - assert payload["teamSize"] == 30 - assert payload["activeOpportunities"] >= 6 - - -def test_opportunity_stage_update(client: TestClient) -> None: - response = client.patch("/api/opportunities", json={"id": "opp-4", "stage": "qualified"}) - assert response.status_code == 200 - assert response.json()["stage"] == "qualified" - - -def test_opportunity_stage_update_persists_to_disk(client: TestClient) -> None: - path = Path(client.get("/api/health").json()["path"]) - client.patch("/api/opportunities", json={"id": "opp-4", "stage": "won"}) - on_disk = load_json(path) - opp = next(item for item in on_disk["opportunities"] if item["id"] == "opp-4") - assert opp["stage"] == "won" - - -def test_project_status_update_persists_to_disk(client: TestClient) -> None: - path = Path(client.get("/api/health").json()["path"]) - response = client.patch("/api/projects", json={"id": "proj-1", "status": "at_risk"}) - assert response.status_code == 200 - on_disk = load_json(path) - project = next(item for item in on_disk["projects"] if item["id"] == "proj-1") - assert project["status"] == "at_risk" - - -def test_compute_dashboard_metrics_from_json() -> None: - config = Path(__file__).resolve().parents[1] / "config" / "data.json" - raw = load_json(config) - db = Database.model_validate(raw) - metrics = compute_dashboard_metrics(db) - assert metrics.team_size == 30 - - -def test_utilization_timeline(client: TestClient) -> None: - response = client.get("/api/utilization/timeline") - assert response.status_code == 200 - payload = response.json() - assert len(payload["weeks"]) == 8 - assert len(payload["rows"]) == 30 - assert payload["rows"][0]["cells"][0]["utilization"] >= 0 - - -def test_utilization_timeline_update(client: TestClient) -> None: - timeline = client.get("/api/utilization/timeline").json() - row = timeline["rows"][0] - week = timeline["weeks"][0]["weekStart"] - response = client.patch( - "/api/utilization/timeline", - json={ - "engineerId": row["engineerId"], - "weekStart": week, - "utilization": 72, - }, - ) - assert response.status_code == 200 - updated_row = response.json()["rows"][0] - assert updated_row["cells"][0]["utilization"] == 72 - - -def test_engineers_search_filter(client: TestClient) -> None: - response = client.get("/api/engineers", params={"search": "chen"}) - assert response.status_code == 200 - payload = response.json() - assert len(payload) >= 1 - assert all("chen" in engineer["name"].lower() for engineer in payload) - - -def test_engineers_status_filter(client: TestClient) -> None: - response = client.get("/api/engineers", params={"status": "overallocated"}) - assert response.status_code == 200 - payload = response.json() - assert len(payload) >= 1 - assert all(engineer["status"] == "overallocated" for engineer in payload) - - -def test_utilization_timeline_update_persists_to_disk(client: TestClient) -> None: - path = Path(client.get("/api/health").json()["path"]) - timeline = client.get("/api/utilization/timeline").json() - row = timeline["rows"][0] - week = timeline["weeks"][0]["weekStart"] - client.patch( - "/api/utilization/timeline", - json={ - "engineerId": row["engineerId"], - "weekStart": week, - "utilization": 81, - }, - ) - on_disk = load_json(path) - engineer = next(item for item in on_disk["engineers"] if item["id"] == row["engineerId"]) - cell = next(item for item in engineer["utilizationTimeline"] if item["weekStart"] == week) - assert cell["utilization"] == 81 diff --git a/apps/delta-command/backend/tests/test_json_db.py b/apps/delta-command/backend/tests/test_json_db.py deleted file mode 100644 index 915956a..0000000 --- a/apps/delta-command/backend/tests/test_json_db.py +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations - -from pathlib import Path - -import pytest - -from delta_command.json_db import database_path, load_json, migrate_legacy_runtime, save_json - - -def test_save_json_writes_valid_json(tmp_path: Path) -> None: - target = tmp_path / "store.json" - payload = {"engineers": [{"id": "eng-1", "name": "Test"}]} - save_json(target, payload) - assert load_json(target) == payload - - -def test_load_json_returns_empty_dict_for_missing_file(tmp_path: Path) -> None: - assert load_json(tmp_path / "missing.json") == {} - - -def test_migrate_legacy_runtime(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - data_file = tmp_path / "data.json" - legacy_file = tmp_path / "runtime.json" - legacy_file.write_text( - '{"engineers":[{"id":"eng-1","name":"Legacy"}],"opportunities":[],"projects":[]}\n', - encoding="utf-8", - ) - monkeypatch.setattr("delta_command.json_db.LEGACY_RUNTIME_PATH", legacy_file) - migrate_legacy_runtime(data_file) - assert load_json(data_file)["engineers"][0]["name"] == "Legacy" - assert not legacy_file.exists() - - -def test_database_path_prefers_delta_data_path(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - custom = tmp_path / "custom.json" - monkeypatch.setenv("DELTA_DATA_PATH", str(custom)) - assert database_path() == custom diff --git a/apps/delta-command/backend/uv.lock b/apps/delta-command/backend/uv.lock deleted file mode 100644 index d3c2e57..0000000 --- a/apps/delta-command/backend/uv.lock +++ /dev/null @@ -1,636 +0,0 @@ -version = 1 -revision = 3 -requires-python = ">=3.12" - -[[package]] -name = "annotated-doc" -version = "0.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.14.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" }, -] - -[[package]] -name = "certifi" -version = "2026.6.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, -] - -[[package]] -name = "click" -version = "8.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "delta-command" -version = "1.0.0" -source = { editable = "." } -dependencies = [ - { name = "fastapi" }, - { name = "pydantic" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[package.dev-dependencies] -dev = [ - { name = "httpx" }, - { name = "pytest" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "fastapi", specifier = ">=0.115.0" }, - { name = "pydantic", specifier = ">=2.10.0" }, - { name = "uvicorn", extras = ["standard"], specifier = ">=0.34.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "httpx", specifier = ">=0.28.0" }, - { name = "pytest", specifier = ">=8.3.0" }, - { name = "ruff", specifier = ">=0.11.0" }, -] - -[[package]] -name = "fastapi" -version = "0.139.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-doc" }, - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d3/af/a5f50ccfa659ec1802cb4ca842c23f06d906a8cc9aef6016a2caeea3d4ed/fastapi-0.139.0.tar.gz", hash = "sha256:99ab7b2d92223c76d6cf10757ab3f89d45b38267fc20b2a136cf02f6beac3145", size = 423016, upload-time = "2026-07-01T16:35:33.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl", hash = "sha256:cf15e1e9e667ddb0ad63811e60bd11390d1aac838ca4a7a23f421807b2308189", size = 130339, upload-time = "2026-07-01T16:35:32.19Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/e5/d471fcb0e14523fe1c3f4ba58ca52480e7bd70ad7109a3846bc75892f7fb/httptools-0.8.0.tar.gz", hash = "sha256:6b2a32f18d97e16e90827d7a819ffa8dbd8cc245fc4e1fa9d1095b54ef4bd999", size = 271342, upload-time = "2026-05-25T22:17:48.841Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/14/88/1d21a36da8f5cb0fa49eafd4b169eba5608d57e75bbcf61845cbc6243216/httptools-0.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:880490234c10f70a9830743097e8958d6e4b9f5a0ffc24515023afeef984054d", size = 208247, upload-time = "2026-05-25T22:17:07.843Z" }, - { url = "https://files.pythonhosted.org/packages/a5/42/cc4feea2945cb3051038f090c9b36bd5b8a9d7f5a894a506a8983e33fd1c/httptools-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5931891fb7b441b8a3853cf1b85c82c903defce084dd5f6771ca46e31bf862c5", size = 113064, upload-time = "2026-05-25T22:17:09.136Z" }, - { url = "https://files.pythonhosted.org/packages/e3/a6/febbb8b8db0f58b38e44ad6cb946e6a255ae49b55f2e8543408fb7501ccd/httptools-0.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b15fc622b0f869d19207c4089a501d9bcc63ca5e071ffdd2f03f922df882dcb2", size = 523851, upload-time = "2026-05-25T22:17:10.106Z" }, - { url = "https://files.pythonhosted.org/packages/b7/e4/f90a0df0b83beff265b7e3b65f2a4cefd95792d4be0ac3e16049f2acd3c2/httptools-0.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:425f83884fd6343828d8c565f046cb72b6d19063f6924093e11bcd8e1548cd09", size = 518842, upload-time = "2026-05-25T22:17:11.218Z" }, - { url = "https://files.pythonhosted.org/packages/9e/2d/0c9ac76dd2c893841fbf6498d6acec4f2442e1b7067f6e3e316a80e494e8/httptools-0.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ef7c3c97f4311c7be57e2986629df89d49cb434dbff78eafcd48c2bff986b15a", size = 501238, upload-time = "2026-05-25T22:17:12.728Z" }, - { url = "https://files.pythonhosted.org/packages/ca/42/906adc91ae3a5fa9c59c0a2f21c139725bd7e5b41ae6acd485cd14123ebf/httptools-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a1afd7c9fbff0d9f5d489c4ce2768bd09c84a46ddefc7161e6aa82ae35c85745", size = 509567, upload-time = "2026-05-25T22:17:13.842Z" }, - { url = "https://files.pythonhosted.org/packages/05/0b/4240efeb672751ee5b9b380cb0e3fdc050bc05f68adc7a8aefc4fcd9a69a/httptools-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:cd96f29b4bab1d42fa6e3d008711c75e0f79e94e06827330160e3a304227f150", size = 90918, upload-time = "2026-05-25T22:17:15.155Z" }, - { url = "https://files.pythonhosted.org/packages/5e/e5/8cfcabc5546e8022f168be28bcdaa128a240a0befdd03b59d558b4f18bd6/httptools-0.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:614ceea8ea606848bece2338ac03b3ce5324bcb4be8dc7d377ed708012fa4db8", size = 205148, upload-time = "2026-05-25T22:17:16.333Z" }, - { url = "https://files.pythonhosted.org/packages/2a/0e/0fb14848c19a686c8062ff9067c1a48793e3224b47bc5b201535b6036fce/httptools-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2d689918c15a013c65ef52d9fd495d766893ab831a2c8d89f2ac5940a5df847c", size = 111368, upload-time = "2026-05-25T22:17:17.586Z" }, - { url = "https://files.pythonhosted.org/packages/2e/1b/46f1cecf06b9bbde8e4b8c88034ac7908989e5ff7a3a388ef38392949c1f/httptools-0.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb3028cca2fc0a6d720e52ef61d8ebb62fcbfeb1de56874546d858d3f25a26b7", size = 486447, upload-time = "2026-05-25T22:17:18.564Z" }, - { url = "https://files.pythonhosted.org/packages/77/00/258bfc0837221f81d9725c45f9b948a6a6b2994a147a4fb66e85100c668f/httptools-0.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88bdd940f2b5d487b4d032c6afa5489a7dc4694410d43de3c38c4fb3af0dc45d", size = 482448, upload-time = "2026-05-25T22:17:19.912Z" }, - { url = "https://files.pythonhosted.org/packages/04/ab/d1cef3b5523f4d272a70f42a776c3169a2dddfe3a54de4b2ce4a36341528/httptools-0.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a43c9dd399758ccc0531acb0a3c4a6c299ee893ee9400e9c893b7bdcfae0681", size = 464460, upload-time = "2026-05-25T22:17:20.882Z" }, - { url = "https://files.pythonhosted.org/packages/ce/48/5d1d072442277bb2b3434e0e60690b8e8c23840ef7de8b6ea54040a536d3/httptools-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0770728beb05094c809b98e814edff5fef69d26ad7d21185f2f6d5884a0ba683", size = 471312, upload-time = "2026-05-25T22:17:22.085Z" }, - { url = "https://files.pythonhosted.org/packages/0d/66/b96623b27e51a68199ef4efdda0613cced9233fe3062ac74e50749c5ad37/httptools-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:7685df791fad561384bfb139e77fde27a1ffd93134e016f95a0db424ffbf77b1", size = 90117, upload-time = "2026-05-25T22:17:23.074Z" }, - { url = "https://files.pythonhosted.org/packages/1a/12/fa3fbf5f9517b273edea2dc982aa82a8c634091e67c590792b729017bc6f/httptools-0.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:de242a49b5d18e0a8776e654e9f6bf6d89f3875a5c35b425a0e7ce940feb3fd6", size = 206183, upload-time = "2026-05-25T22:17:24.004Z" }, - { url = "https://files.pythonhosted.org/packages/30/fc/5e7c4cb443370f2090a3aba0453a07384d29ff66b7435bb90e77e1037599/httptools-0.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:159e9ab5f701ccd42e555a12f1ad8ff69702910fc1c996cf2bb66e5fcb7a231b", size = 112079, upload-time = "2026-05-25T22:17:25.216Z" }, - { url = "https://files.pythonhosted.org/packages/ba/53/771bd891eb0f236f32145d6a1775777ec85745f3cc983a1f23d1a3b8ddfe/httptools-0.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c4a9f1707e4823d54dfec6c33fa3697d302aed536ed352a7ebb5a061ddb869d0", size = 481596, upload-time = "2026-05-25T22:17:26.186Z" }, - { url = "https://files.pythonhosted.org/packages/62/42/94e15bc68ce3d423243c45d7f1b0c7561f13844f97dc52ae23182fb65628/httptools-0.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d76ad7b951387e3632c8716a9bb03ac5b45c5f16119aa409db0459520887944e", size = 480865, upload-time = "2026-05-25T22:17:27.542Z" }, - { url = "https://files.pythonhosted.org/packages/1c/7c/fe2980fc03723272e30f135b62360b075f513dfe7cc73aef36c7f04012bd/httptools-0.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a3b7387147361c3fd47a0bde763c5c91b5b4cd4dc9989b8ece84ff436c99843b", size = 463189, upload-time = "2026-05-25T22:17:28.546Z" }, - { url = "https://files.pythonhosted.org/packages/15/1b/47fc5fff68acd1bfa20b4734059c9a06cadb88119dcd5258b5b0d21d91c8/httptools-0.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f256d6ce930c52ca1cb2a960b7da03548c454e7d28b06059ad41bfe789036ce0", size = 466610, upload-time = "2026-05-25T22:17:29.816Z" }, - { url = "https://files.pythonhosted.org/packages/60/bd/07b13c93ffd9bec9546e0d43f8e19378dd696dbd278511406bc07371ef1f/httptools-0.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:19d1ee275bb59ba2643ba9a3a1e51cc0c788caf2b8df506368e03f56fdd08527", size = 92705, upload-time = "2026-05-25T22:17:31.133Z" }, - { url = "https://files.pythonhosted.org/packages/fd/c4/121648f68ce066d7bd762d6b6d97e620847642d38d54f3d90ff11d947629/httptools-0.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:de1ed58a974e75d56560acc7e7fed01a454994429456f65209789992e41f2568", size = 215023, upload-time = "2026-05-25T22:17:32.401Z" }, - { url = "https://files.pythonhosted.org/packages/b9/b0/312a062ae741ae3e8baa8c8bf20be81b2e67337b259ab4349bebc7b6142e/httptools-0.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e93c227b595c6926c1acee96891dd9da4be338cfbe82e5cd3bb9d8dd7dc4ac0b", size = 117405, upload-time = "2026-05-25T22:17:33.742Z" }, - { url = "https://files.pythonhosted.org/packages/fc/37/fccd705f795386bb05bf413012fecff2a33e5aa8c2f069096de3e9fd8702/httptools-0.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2a021c3a8e65cc125390d72f59b968afca3bdcaff25bd67965e0a055a14946ca", size = 558497, upload-time = "2026-05-25T22:17:34.732Z" }, - { url = "https://files.pythonhosted.org/packages/bd/39/f172e8003576de35f5ba77ff417cf0e34429d35dc014deef15afa337a72c/httptools-0.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48774d39cbb70e2b1f71f88852a3087ae1d3a1eb80482bb48c13067ab080c14f", size = 571585, upload-time = "2026-05-25T22:17:35.813Z" }, - { url = "https://files.pythonhosted.org/packages/3e/b9/f5564760af99f3dbbf3f9104dc00e5da27e96cf433c6bdcf77617f70bf3f/httptools-0.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:88eead8ec8680a9f146c655bc88445a325bd7921cfd8194c7337e9467282427d", size = 543297, upload-time = "2026-05-25T22:17:37.08Z" }, - { url = "https://files.pythonhosted.org/packages/99/67/8d9f2c313618e161b82f3873188e7196126da1d6e29688df40eb3997c77a/httptools-0.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2c032fa028f46871ec7e1fc59fc15e8023eab3e6bbe6ece786a1611719a5d081", size = 539535, upload-time = "2026-05-25T22:17:38.032Z" }, - { url = "https://files.pythonhosted.org/packages/48/63/b906c01e53f50d432c0defe43ce52764a111dc1bdd028bafbeb54dcfd008/httptools-0.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:384c17174464c8e873398b7af24f0b1f44d992c820328413951a625323155d77", size = 108209, upload-time = "2026-05-25T22:17:39.473Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.18" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, -] - -[[package]] -name = "iniconfig" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, -] - -[[package]] -name = "packaging" -version = "26.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", size = 228134, upload-time = "2026-04-24T20:15:23.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e", size = 100195, upload-time = "2026-04-24T20:15:22.081Z" }, -] - -[[package]] -name = "pluggy" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, -] - -[[package]] -name = "pydantic" -version = "2.13.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/a5/b60d21ac674192f8ab0ba4e9fd860690f9b4a6e51ca5df118733b487d8d6/pydantic-2.13.4.tar.gz", hash = "sha256:c40756b57adaa8b1efeeced5c196f3f3b7c435f90e84ea7f443901bec8099ef6", size = 844775, upload-time = "2026-05-06T13:43:05.343Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/7b/122376b1fd3c62c1ed9dc80c931ace4844b3c55407b6fb2d199377c9736f/pydantic-2.13.4-py3-none-any.whl", hash = "sha256:45a282cde31d808236fd7ea9d919b128653c8b38b393d1c4ab335c62924d9aba", size = 472262, upload-time = "2026-05-06T13:43:02.641Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.46.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/56/921726b776ace8d8f5db44c4ef961006580d91dc52b803c489fafd1aa249/pydantic_core-2.46.4.tar.gz", hash = "sha256:62f875393d7f270851f20523dd2e29f082bcc82292d66db2b64ea71f64b6e1c1", size = 471464, upload-time = "2026-05-06T13:37:06.98Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/8c/af022f0af448d7747c5154288d46b5f2bc5f17366eaa0e23e9aa04d59f3b/pydantic_core-2.46.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3245406455a5d98187ec35530fd772b1d799b26667980872c8d4614991e2c4a2", size = 2106158, upload-time = "2026-05-06T13:38:57.215Z" }, - { url = "https://files.pythonhosted.org/packages/19/95/6195171e385007300f0f5574592e467c568becce2d937a0b6804f218bc49/pydantic_core-2.46.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:962ccbab7b642487b1d8b7df90ef677e03134cf1fd8880bf698649b22a69371f", size = 1951724, upload-time = "2026-05-06T13:37:02.697Z" }, - { url = "https://files.pythonhosted.org/packages/8e/bc/f47d1ff9cbb1620e1b5b697eef06010035735f07820180e74178226b27b3/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8233f2947cf85404441fd7e0085f53b10c93e0ee78611099b5c7237e36aacbf7", size = 1975742, upload-time = "2026-05-06T13:37:09.448Z" }, - { url = "https://files.pythonhosted.org/packages/5b/11/9b9a5b0306345664a2da6410877af6e8082481b5884b3ddd78d47c6013ce/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3a233125ac121aa3ffba9a2b59edfc4a985a76092dc8279586ab4b71390875e7", size = 2052418, upload-time = "2026-05-06T13:37:38.234Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b7/a65fec226f5d78fc39f4a13c4cc0c768c22b113438f60c14adc9d2865038/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b712b53160b79a5850310b912a5ef8e57e56947c8ad690c227f5c9d7e561712", size = 2232274, upload-time = "2026-05-06T13:38:27.753Z" }, - { url = "https://files.pythonhosted.org/packages/68/f0/92039db98b907ef49269a8271f67db9cb78ae2fc68062ef7e4e77adb5f61/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9401557acd873c3a7f3eb9383edef8ac4968f9510e340f4808d427e75667e7b4", size = 2309940, upload-time = "2026-05-06T13:38:05.353Z" }, - { url = "https://files.pythonhosted.org/packages/5f/97/2aab507d3d00ca626e8e57c1eac6a79e4e5fbcc63eb99733ff55d1717f65/pydantic_core-2.46.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:926c9541b14b12b1681dca8a0b75feb510b06c6341b70a8e500c2fdcff837cce", size = 2094516, upload-time = "2026-05-06T13:39:10.577Z" }, - { url = "https://files.pythonhosted.org/packages/22/37/a8aca44d40d737dde2bc05b3c6c07dff0de07ce6f82e9f3167aeaf4d5dea/pydantic_core-2.46.4-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:56cb4851bcaf3d117eddcef4fe66afd750a50274b0da8e22be256d10e5611987", size = 2136854, upload-time = "2026-05-06T13:40:22.59Z" }, - { url = "https://files.pythonhosted.org/packages/24/99/fcef1b79238c06a8cbec70819ac722ba76e02bc8ada9b0fd66eba40da01b/pydantic_core-2.46.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c68fcd102d71ea85c5b2dfac3f4f8476eff42a9e078fd5faefff6d145063536b", size = 2180306, upload-time = "2026-05-06T13:40:10.666Z" }, - { url = "https://files.pythonhosted.org/packages/ae/6c/fc44000918855b42779d007ae63b0532794739027b2f417321cddbc44f6a/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b2f69dec1725e79a012d920df1707de5caf7ed5e08f3be4435e25803efc47458", size = 2190044, upload-time = "2026-05-06T13:40:43.231Z" }, - { url = "https://files.pythonhosted.org/packages/6b/65/d9cadc9f1920d7a127ad2edba16c1db7916e59719285cd6c94600b0080ba/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:8d0820e8192167f80d88d64038e609c31452eeca865b4e1d9950a27a4609b00b", size = 2329133, upload-time = "2026-05-06T13:39:57.365Z" }, - { url = "https://files.pythonhosted.org/packages/d0/cf/c873d91679f3a30bcf5e7ac280ce5573483e72295307685120d0d5ad3416/pydantic_core-2.46.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fbdb89b3e1c94a30cc5edfce477c6e6a5dc4d8f84665b455c27582f211a1c72c", size = 2374464, upload-time = "2026-05-06T13:38:06.976Z" }, - { url = "https://files.pythonhosted.org/packages/47/bd/6f2fc8188f31bf10590f1e98e7b306336161fac930a8c514cd7bd828c7dc/pydantic_core-2.46.4-cp312-cp312-win32.whl", hash = "sha256:9aa768456404a8bf48a4406685ac2bec8e72b62c69313734fa3b73cf33b3a894", size = 1974823, upload-time = "2026-05-06T13:40:47.985Z" }, - { url = "https://files.pythonhosted.org/packages/40/8c/985c1d41ea1107c2534abd9870e4ed5c8e7669b5c308297835c001e7a1c4/pydantic_core-2.46.4-cp312-cp312-win_amd64.whl", hash = "sha256:e9c26f834c65f5752f3f06cb08cb86a913ceb7274d0db6e267808a708b46bc89", size = 2072919, upload-time = "2026-05-06T13:39:21.153Z" }, - { url = "https://files.pythonhosted.org/packages/c4/ba/f463d006e0c47373ca7ec5e1a261c59dc01ef4d62b2657af925fb0deee3a/pydantic_core-2.46.4-cp312-cp312-win_arm64.whl", hash = "sha256:4fc73cb559bdb54b1134a706a2802a4cddd27a0633f5abb7e53056268751ac6a", size = 2027604, upload-time = "2026-05-06T13:39:03.753Z" }, - { url = "https://files.pythonhosted.org/packages/51/a2/5d30b469c5267a17b39dec53208222f76a8d351dfac4af661888c5aee77d/pydantic_core-2.46.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5d5902252db0d3cedf8d4a1bc68f70eeb430f7e4c7104c8c476753519b423008", size = 2106306, upload-time = "2026-05-06T13:37:48.029Z" }, - { url = "https://files.pythonhosted.org/packages/c1/81/4fa520eaffa8bd7d1525e644cd6d39e7d60b1592bc5b516693c7340b50f1/pydantic_core-2.46.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94f0688e7b8d0a67abf40e57a7eaaecd17cc9586706a31b76c031f63df052b4", size = 1951906, upload-time = "2026-05-06T13:37:17.012Z" }, - { url = "https://files.pythonhosted.org/packages/03/d5/fd02da45b659668b05923b17ba3a0100a0a3d5541e3bd8fcc4ecb711309e/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f027324c56cd5406ca49c124b0db10e56c69064fec039acc571c29020cc87c76", size = 1976802, upload-time = "2026-05-06T13:37:35.113Z" }, - { url = "https://files.pythonhosted.org/packages/21/f2/95727e1368be3d3ed485eaab7adbd7dda408f33f7a36e8b48e0144002b91/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e739fee756ba1010f8bcccb534252e85a35fe45ae92c295a06059ce58b74ccd3", size = 2052446, upload-time = "2026-05-06T13:37:12.313Z" }, - { url = "https://files.pythonhosted.org/packages/9c/86/5d99feea3f77c7234b8718075b23db11532773c1a0dbd9b9490215dc2eeb/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d56801be94b86a9da183e5f3766e6310752b99ff647e38b09a9500d88e46e76", size = 2232757, upload-time = "2026-05-06T13:39:01.149Z" }, - { url = "https://files.pythonhosted.org/packages/d2/3a/508ac615935ef7588cf6d9e9b91309fdc2da751af865e02a9098de88258c/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2412e734dcb48da14d4e4006b82b46b74f2518b8a26ee7e58c6844a6cd6d03c4", size = 2309275, upload-time = "2026-05-06T13:37:41.406Z" }, - { url = "https://files.pythonhosted.org/packages/07/f8/41db9de19d7987d6b04715a02b3b40aea467000275d9d758ffaa31af7d50/pydantic_core-2.46.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9551187363ffc0de2a00b2e47c25aeaeb1020b69b668762966df15fc5659dd5a", size = 2094467, upload-time = "2026-05-06T13:39:18.847Z" }, - { url = "https://files.pythonhosted.org/packages/2c/e2/f35033184cb11d0052daf4416e8e10a502ea2ac006fc4f459aee872727d1/pydantic_core-2.46.4-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:0186750b482eefa11d7f435892b09c5c606193ef3375bcf94aa00ae6bfb66262", size = 2134417, upload-time = "2026-05-06T13:40:17.944Z" }, - { url = "https://files.pythonhosted.org/packages/7e/7b/6ceeb1cc90e193862f444ebe373d8fdf613f0a82572dde03fb10734c6c71/pydantic_core-2.46.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5855698a4856556d86e8e6cd8434bc3ac0314ee8e12089ae0e143f64c6256e4e", size = 2179782, upload-time = "2026-05-06T13:40:32.618Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f2/c8d7773ede6af08036423a00ae0ceffce266c3c52a096c435d68c896083f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:cbaf13819775b7f769bf4a1f066cb6df7a28d4480081a589828ef190226881cd", size = 2188782, upload-time = "2026-05-06T13:36:51.018Z" }, - { url = "https://files.pythonhosted.org/packages/59/31/0c864784e31f09f05cdd87606f08923b9c9e7f6e51dd27f20f62f975ce9f/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:633147d34cf4550417f12e2b1a0383973bdf5cdfde212cb09e9a581cf10820be", size = 2328334, upload-time = "2026-05-06T13:40:37.764Z" }, - { url = "https://files.pythonhosted.org/packages/c2/eb/4f6c8a41efa30baa755590f4141abf3a8c370fab610915733e74134a7270/pydantic_core-2.46.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:82cf5301172168103724d49a1444d3378cb20cdee30b116a1bd6031236298a5d", size = 2372986, upload-time = "2026-05-06T13:39:34.152Z" }, - { url = "https://files.pythonhosted.org/packages/5b/24/b375a480d53113860c299764bfe9f349a3dc9108b3adc0d7f0d786492ebf/pydantic_core-2.46.4-cp313-cp313-win32.whl", hash = "sha256:9fa8ae11da9e2b3126c6426f147e0fba88d96d65921799bb30c6abd1cb2c97fb", size = 1973693, upload-time = "2026-05-06T13:37:55.072Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e8/cff247591966f2d22ec8c003cd7587e27b7ba7b81ab2fb888e3ab75dc285/pydantic_core-2.46.4-cp313-cp313-win_amd64.whl", hash = "sha256:6b3ace8194b0e5204818c92802dcdca7fc6d88aabbb799d7c795540d9cd6d292", size = 2071819, upload-time = "2026-05-06T13:38:49.139Z" }, - { url = "https://files.pythonhosted.org/packages/c6/1a/f4aee670d5670e9e148e0c82c7db98d780be566c6e6a97ee8035528ca0b3/pydantic_core-2.46.4-cp313-cp313-win_arm64.whl", hash = "sha256:184c081504d17f1c1066e430e117142b2c77d9448a97f7b65c6ac9fd9aee238d", size = 2027411, upload-time = "2026-05-06T13:40:45.796Z" }, - { url = "https://files.pythonhosted.org/packages/8d/74/228a26ddad29c6672b805d9fd78e8d251cd04004fa7eed0e622096cd0250/pydantic_core-2.46.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:428e04521a40150c85216fc8b85e8d39fece235a9cf5e383761238c7fa9b96fb", size = 2102079, upload-time = "2026-05-06T13:38:41.019Z" }, - { url = "https://files.pythonhosted.org/packages/ad/1f/8970b150a4b4365623ae00fc88603491f763c627311ae8031e3111356d6e/pydantic_core-2.46.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:23ace664830ee0bfe014a0c7bc248b1f7f25ed7ad103852c317624a1083af462", size = 1952179, upload-time = "2026-05-06T13:36:59.812Z" }, - { url = "https://files.pythonhosted.org/packages/95/30/5211a831ae054928054b2f79731661087a2bc5c01e825c672b3a4a8f1b3e/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5c1d2a8b27468f433ca974829c44060b8097eedc39933e3c206a90ee49c4a9", size = 1978926, upload-time = "2026-05-06T13:37:39.933Z" }, - { url = "https://files.pythonhosted.org/packages/57/e9/689668733b1eb67adeef047db3c2e8788fcf65a7fd9c9e2b46b7744fe245/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7283d57845ecf5a163403eb0702dfc220cc4fbdd18919cb5ccea4f95ee1cdab4", size = 2046785, upload-time = "2026-05-06T13:38:01.995Z" }, - { url = "https://files.pythonhosted.org/packages/60/d9/6715260422ff50a2109878fd24d948a6c3446bb2664f34ee78cd972b3acd/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8daafc69c93ee8a0204506a3b6b30f586ef54028f52aeeeb5c4cfc5184fd5914", size = 2228733, upload-time = "2026-05-06T13:40:50.371Z" }, - { url = "https://files.pythonhosted.org/packages/18/ae/fdb2f64316afca925640f8e70bb1a564b0ec2721c1389e25b8eb4bf9a299/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd2213145bcc2ba85884d0ac63d222fece9209678f77b9b4d76f054c561adb28", size = 2307534, upload-time = "2026-05-06T13:37:21.531Z" }, - { url = "https://files.pythonhosted.org/packages/89/1d/8eff589b45bb8190a9d12c49cfad0f176a5cbd1534908a6b5125e2886239/pydantic_core-2.46.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a5f930472650a82629163023e630d160863fce524c616f4e5186e5de9d9a49b", size = 2099732, upload-time = "2026-05-06T13:39:31.942Z" }, - { url = "https://files.pythonhosted.org/packages/06/d5/ee5a3366637fee41dee51a1fc91562dcf12ddbc68fda34e6b253da2324bb/pydantic_core-2.46.4-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c1b3f518abeca3aa13c712fd202306e145abf59a18b094a6bafb2d2bbf59192c", size = 2129627, upload-time = "2026-05-06T13:37:25.033Z" }, - { url = "https://files.pythonhosted.org/packages/94/33/2414be571d2c6a6c4d08be21f9292b6d3fdb08949a97b6dfe985017821db/pydantic_core-2.46.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a7dd0b3ee80d90150e3495a3a13ac34dbcbfd4f012996a6a1d8900e91b5c0fb", size = 2179141, upload-time = "2026-05-06T13:37:14.046Z" }, - { url = "https://files.pythonhosted.org/packages/7b/79/7daa95be995be0eecc4cf75064cb33f9bbbfe3fe0158caf2f0d4a996a5c7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:3fb702cd90b0446a3a1c5e470bfa0dd23c0233b676a9099ddcc964fa6ca13898", size = 2184325, upload-time = "2026-05-06T13:36:53.615Z" }, - { url = "https://files.pythonhosted.org/packages/9f/cb/d0a382f5c0de8a222dc61c65348e0ce831b1f68e0a018450d31c2cace3a5/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b8458003118a712e66286df6a707db01c52c0f52f7db8e4a38f0da1d3b94fc4e", size = 2323990, upload-time = "2026-05-06T13:40:29.971Z" }, - { url = "https://files.pythonhosted.org/packages/05/db/d9ba624cc4a5aced1598e88c04fdbd8310c8a69b9d38b9a3d39ce3a61ed7/pydantic_core-2.46.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:372429a130e469c9cd698925ce5fc50940b7a1336b0d82038e63d5bbc4edc519", size = 2369978, upload-time = "2026-05-06T13:37:23.027Z" }, - { url = "https://files.pythonhosted.org/packages/f2/20/d15df15ba918c423461905802bfd2981c3af0bfa0e40d05e13edbfa48bc3/pydantic_core-2.46.4-cp314-cp314-win32.whl", hash = "sha256:85bb3611ff1802f3ee7fdd7dbff26b56f343fb432d57a4728fdd49b6ef35e2f4", size = 1966354, upload-time = "2026-05-06T13:38:03.499Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b6/6b8de4c0a7d7ab3004c439c80c5c1e0a3e8d78bbae19379b01960383d9e5/pydantic_core-2.46.4-cp314-cp314-win_amd64.whl", hash = "sha256:811ff8e9c313ab425368bcbb36e5c4ebd7108c2bbf4e4089cfbb0b01eff63fac", size = 2072238, upload-time = "2026-05-06T13:39:40.807Z" }, - { url = "https://files.pythonhosted.org/packages/32/36/51eb763beec1f4cf59b1db243a7dcc39cbb41230f050a09b9d69faaf0a48/pydantic_core-2.46.4-cp314-cp314-win_arm64.whl", hash = "sha256:bfec22eab3c8cc2ceec0248aec886624116dc079afa027ecc8ad4a7e62010f8a", size = 2018251, upload-time = "2026-05-06T13:37:26.72Z" }, - { url = "https://files.pythonhosted.org/packages/e8/91/855af51d625b23aa987116a19e231d2aaef9c4a415273ddc189b79a45fee/pydantic_core-2.46.4-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:af8244b2bef6aaad6d92cda81372de7f8c8d36c9f0c3ea36e827c60e7d9467a0", size = 2099593, upload-time = "2026-05-06T13:39:47.682Z" }, - { url = "https://files.pythonhosted.org/packages/fb/1b/8784a54c65edb5f49f0a14d6977cf1b209bba85a4c77445b255c2de58ab3/pydantic_core-2.46.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5a4330cdbc57162e4b3aa303f588ba752257694c9c9be3e7ebb11b4aca659b5d", size = 1935226, upload-time = "2026-05-06T13:40:40.428Z" }, - { url = "https://files.pythonhosted.org/packages/e8/e7/1955d28d1afc56dd4b3ad7cc0cf39df1b9852964cf16e5d13912756d6d6b/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c61fc04a3d840155ff08e475a04809278972fe6aef51e2720554e96367e34b", size = 1974605, upload-time = "2026-05-06T13:37:32.029Z" }, - { url = "https://files.pythonhosted.org/packages/93/e2/3fedbf0ba7a22850e6e9fd78117f1c0f10f950182344d8a6c535d468fdd8/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c50f2528cf200c5eed56faf3f4e22fcd5f38c157a8b78576e6ba3168ec35f000", size = 2030777, upload-time = "2026-05-06T13:38:55.239Z" }, - { url = "https://files.pythonhosted.org/packages/f8/61/46be275fcaaba0b4f5b9669dd852267ce1ff616592dccf7a7845588df091/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0cbe8b01f948de4286c74cdd6c667aceb38f5c1e26f0693b3983d9d74887c65e", size = 2236641, upload-time = "2026-05-06T13:37:08.096Z" }, - { url = "https://files.pythonhosted.org/packages/60/db/12e93e46a8bac9988be3c016860f83293daea8c716c029c9ace279036f2f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:617d7e2ca7dcb8c5cf6bcb8c59b8832c94b36196bbf1cbd1bfb56ed341905edd", size = 2286404, upload-time = "2026-05-06T13:40:20.221Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4a/4d8b19008f38d31c53b8219cfedc2e3d5de5fe99d90076b7e767de29274f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7027560ee92211647d0d34e3f7cd6f50da56399d26a9c8ad0da286d3869a53f3", size = 2109219, upload-time = "2026-05-06T13:38:12.153Z" }, - { url = "https://files.pythonhosted.org/packages/88/70/3cbc40978fefb7bb09c6708d40d4ad1a5d70fd7213c3d17f971de868ec1f/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:f99626688942fb746e545232e7726926f3be91b5975f8b55327665fafda991c7", size = 2110594, upload-time = "2026-05-06T13:40:02.971Z" }, - { url = "https://files.pythonhosted.org/packages/9d/20/b8d36736216e29491125531685b2f9e61aa5b4b2599893f8268551da3338/pydantic_core-2.46.4-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc3e9034a63de20e15e8ade85358bc6efc614008cab72898b4b4952bea0509ff", size = 2159542, upload-time = "2026-05-06T13:39:27.506Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a2/367df868eb584dacf6bf82a389272406d7178e301c4ac82545ab98bc2dd9/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:97e7cf2be5c77b7d1a9713a05605d49460d02c6078d38d8bef3cbe323c548424", size = 2168146, upload-time = "2026-05-06T13:38:31.93Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b8/4460f77f7e201893f649a29ab355dddd3beee8a97bcb1a320db414f9a06e/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:3bf92c5d0e00fefaab325a4d27828fe6b6e2a21848686b5b60d2d9eeb09d76c6", size = 2306309, upload-time = "2026-05-06T13:37:44.717Z" }, - { url = "https://files.pythonhosted.org/packages/64/c4/be2639293acd87dc8ddbcec41a73cee9b2ebf996fe6d892a1a74e88ad3f7/pydantic_core-2.46.4-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:3ecbc122d18468d06ca279dc26a8c2e2d5acb10943bb35e36ae92096dc3b5565", size = 2369736, upload-time = "2026-05-06T13:37:05.645Z" }, - { url = "https://files.pythonhosted.org/packages/30/a6/9f9f380dbb301f67023bf8f707aaa75daadf84f7152d95c410fd7e81d994/pydantic_core-2.46.4-cp314-cp314t-win32.whl", hash = "sha256:e846ae7835bf0703ae43f534ab79a867146dadd59dc9ca5c8b53d5c8f7c9ef02", size = 1955575, upload-time = "2026-05-06T13:38:51.116Z" }, - { url = "https://files.pythonhosted.org/packages/40/1f/f1eb9eb350e795d1af8586289746f5c5677d16043040d63710e22abc43c9/pydantic_core-2.46.4-cp314-cp314t-win_amd64.whl", hash = "sha256:2108ba5c1c1eca18030634489dc544844144ee36357f2f9f780b93e7ddbb44b5", size = 2051624, upload-time = "2026-05-06T13:38:21.672Z" }, - { url = "https://files.pythonhosted.org/packages/f6/d2/42dd53d0a85c27606f316d3aa5d2869c4e8470a5ed6dec30e4a1abe19192/pydantic_core-2.46.4-cp314-cp314t-win_arm64.whl", hash = "sha256:4fcbe087dbc2068af7eda3aa87634eba216dbda64d1ae73c8684b621d33f6596", size = 2017325, upload-time = "2026-05-06T13:40:52.723Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1d/8987ad40f65ae1432753072f214fb5c74fe47ffbd0698bb9cbbb585664f8/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:1d8ba486450b14f3b1d63bc521d410ec7565e52f887b9fb671791886436a42f7", size = 2095527, upload-time = "2026-05-06T13:39:52.283Z" }, - { url = "https://files.pythonhosted.org/packages/64/d3/84c282a7eee1d3ac4c0377546ef5a1ea436ce26840d9ac3b7ed54a377507/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:3009f12e4e90b7f88b4f9adb1b0c4a3d58fe7820f3238c190047209d148026df", size = 1936024, upload-time = "2026-05-06T13:40:15.671Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ca/eac61596cdeb4d7e174d3dc0bd8a6238f14f75f97a24e7b7db4c7e7340a0/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad785e92e6dc634c21555edc8bd6b64957ab844541bcb96a1366c202951ae526", size = 1990696, upload-time = "2026-05-06T13:38:34.717Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c3/7c8b240552251faf6b3a957db200fcfbbcec36763c050428b601e0c9b83b/pydantic_core-2.46.4-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00c603d540afdd6b80eb39f078f33ebd46211f02f33e34a32d9f053bba711de0", size = 2147590, upload-time = "2026-05-06T13:39:29.883Z" }, -] - -[[package]] -name = "pygments" -version = "2.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, -] - -[[package]] -name = "pytest" -version = "9.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" }, - { url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" }, - { url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" }, - { url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" }, - { url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" }, - { url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" }, - { url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" }, - { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, - { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, - { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, - { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, - { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, - { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, - { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, - { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, - { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", size = 181814, upload-time = "2025-09-25T21:32:35.712Z" }, - { url = "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", size = 173809, upload-time = "2025-09-25T21:32:36.789Z" }, - { url = "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", size = 766454, upload-time = "2025-09-25T21:32:37.966Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", size = 836355, upload-time = "2025-09-25T21:32:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", size = 794175, upload-time = "2025-09-25T21:32:40.865Z" }, - { url = "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", size = 755228, upload-time = "2025-09-25T21:32:42.084Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", size = 789194, upload-time = "2025-09-25T21:32:43.362Z" }, - { url = "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", size = 156429, upload-time = "2025-09-25T21:32:57.844Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", size = 143912, upload-time = "2025-09-25T21:32:59.247Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", size = 189108, upload-time = "2025-09-25T21:32:44.377Z" }, - { url = "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", size = 183641, upload-time = "2025-09-25T21:32:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", size = 831901, upload-time = "2025-09-25T21:32:48.83Z" }, - { url = "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", size = 861132, upload-time = "2025-09-25T21:32:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", size = 839261, upload-time = "2025-09-25T21:32:51.808Z" }, - { url = "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", size = 805272, upload-time = "2025-09-25T21:32:52.941Z" }, - { url = "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", size = 829923, upload-time = "2025-09-25T21:32:54.537Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", size = 174062, upload-time = "2025-09-25T21:32:55.767Z" }, - { url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" }, -] - -[[package]] -name = "ruff" -version = "0.15.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" }, - { url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" }, - { url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" }, - { url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" }, - { url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" }, - { url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" }, - { url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" }, - { url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" }, - { url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" }, - { url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" }, - { url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" }, - { url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" }, - { url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" }, -] - -[[package]] -name = "starlette" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.50.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2e/41/06cce5dbb9f77591512957710ac709e60b12e6216a2f2d0d607fd49706e8/uvicorn-0.50.0.tar.gz", hash = "sha256:0c92e1bc2259cb7faa4fcef774a5966588f2e88542744550b66799fba10b76f1", size = 93257, upload-time = "2026-07-04T05:03:26.33Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/3a/eb70620ca2bf8213603d5c731460687c49fee38b0072f0b4a637781f0a53/uvicorn-0.50.0-py3-none-any.whl", hash = "sha256:05f0eb19edf38208f79f43df8a63081b48df31b0cd1e5997be957a4dc97d1b19", size = 72716, upload-time = "2026-07-04T05:03:24.848Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.22.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" }, - { url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" }, - { url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" }, - { url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" }, - { url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" }, - { url = "https://files.pythonhosted.org/packages/89/8c/182a2a593195bfd39842ea68ebc084e20c850806117213f5a299dfc513d9/uvloop-0.22.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:561577354eb94200d75aca23fbde86ee11be36b00e52a4eaf8f50fb0c86b7705", size = 1358611, upload-time = "2025-10-16T22:16:36.833Z" }, - { url = "https://files.pythonhosted.org/packages/d2/14/e301ee96a6dc95224b6f1162cd3312f6d1217be3907b79173b06785f2fe7/uvloop-0.22.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cdf5192ab3e674ca26da2eada35b288d2fa49fdd0f357a19f0e7c4e7d5077c8", size = 751811, upload-time = "2025-10-16T22:16:38.275Z" }, - { url = "https://files.pythonhosted.org/packages/b7/02/654426ce265ac19e2980bfd9ea6590ca96a56f10c76e63801a2df01c0486/uvloop-0.22.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e2ea3d6190a2968f4a14a23019d3b16870dd2190cd69c8180f7c632d21de68d", size = 4288562, upload-time = "2025-10-16T22:16:39.375Z" }, - { url = "https://files.pythonhosted.org/packages/15/c0/0be24758891ef825f2065cd5db8741aaddabe3e248ee6acc5e8a80f04005/uvloop-0.22.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0530a5fbad9c9e4ee3f2b33b148c6a64d47bbad8000ea63704fa8260f4cf728e", size = 4366890, upload-time = "2025-10-16T22:16:40.547Z" }, - { url = "https://files.pythonhosted.org/packages/d2/53/8369e5219a5855869bcee5f4d317f6da0e2c669aecf0ef7d371e3d084449/uvloop-0.22.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5ef13bbc10b5335792360623cc378d52d7e62c2de64660616478c32cd0598e", size = 4119472, upload-time = "2025-10-16T22:16:41.694Z" }, - { url = "https://files.pythonhosted.org/packages/f8/ba/d69adbe699b768f6b29a5eec7b47dd610bd17a69de51b251126a801369ea/uvloop-0.22.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1f38ec5e3f18c8a10ded09742f7fb8de0108796eb673f30ce7762ce1b8550cad", size = 4239051, upload-time = "2025-10-16T22:16:43.224Z" }, - { url = "https://files.pythonhosted.org/packages/90/cd/b62bdeaa429758aee8de8b00ac0dd26593a9de93d302bff3d21439e9791d/uvloop-0.22.1-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3879b88423ec7e97cd4eba2a443aa26ed4e59b45e6b76aabf13fe2f27023a142", size = 1362067, upload-time = "2025-10-16T22:16:44.503Z" }, - { url = "https://files.pythonhosted.org/packages/0d/f8/a132124dfda0777e489ca86732e85e69afcd1ff7686647000050ba670689/uvloop-0.22.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4baa86acedf1d62115c1dc6ad1e17134476688f08c6efd8a2ab076e815665c74", size = 752423, upload-time = "2025-10-16T22:16:45.968Z" }, - { url = "https://files.pythonhosted.org/packages/a3/94/94af78c156f88da4b3a733773ad5ba0b164393e357cc4bd0ab2e2677a7d6/uvloop-0.22.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:297c27d8003520596236bdb2335e6b3f649480bd09e00d1e3a99144b691d2a35", size = 4272437, upload-time = "2025-10-16T22:16:47.451Z" }, - { url = "https://files.pythonhosted.org/packages/b5/35/60249e9fd07b32c665192cec7af29e06c7cd96fa1d08b84f012a56a0b38e/uvloop-0.22.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c1955d5a1dd43198244d47664a5858082a3239766a839b2102a269aaff7a4e25", size = 4292101, upload-time = "2025-10-16T22:16:49.318Z" }, - { url = "https://files.pythonhosted.org/packages/02/62/67d382dfcb25d0a98ce73c11ed1a6fba5037a1a1d533dcbb7cab033a2636/uvloop-0.22.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b31dc2fccbd42adc73bc4e7cdbae4fc5086cf378979e53ca5d0301838c5682c6", size = 4114158, upload-time = "2025-10-16T22:16:50.517Z" }, - { url = "https://files.pythonhosted.org/packages/f0/7a/f1171b4a882a5d13c8b7576f348acfe6074d72eaf52cccef752f748d4a9f/uvloop-0.22.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:93f617675b2d03af4e72a5333ef89450dfaa5321303ede6e67ba9c9d26878079", size = 4177360, upload-time = "2025-10-16T22:16:52.646Z" }, - { url = "https://files.pythonhosted.org/packages/79/7b/b01414f31546caf0919da80ad57cbfe24c56b151d12af68cee1b04922ca8/uvloop-0.22.1-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:37554f70528f60cad66945b885eb01f1bb514f132d92b6eeed1c90fd54ed6289", size = 1454790, upload-time = "2025-10-16T22:16:54.355Z" }, - { url = "https://files.pythonhosted.org/packages/d4/31/0bb232318dd838cad3fa8fb0c68c8b40e1145b32025581975e18b11fab40/uvloop-0.22.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:b76324e2dc033a0b2f435f33eb88ff9913c156ef78e153fb210e03c13da746b3", size = 796783, upload-time = "2025-10-16T22:16:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/42/38/c9b09f3271a7a723a5de69f8e237ab8e7803183131bc57c890db0b6bb872/uvloop-0.22.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:badb4d8e58ee08dad957002027830d5c3b06aea446a6a3744483c2b3b745345c", size = 4647548, upload-time = "2025-10-16T22:16:57.008Z" }, - { url = "https://files.pythonhosted.org/packages/c1/37/945b4ca0ac27e3dc4952642d4c900edd030b3da6c9634875af6e13ae80e5/uvloop-0.22.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b91328c72635f6f9e0282e4a57da7470c7350ab1c9f48546c0f2866205349d21", size = 4467065, upload-time = "2025-10-16T22:16:58.206Z" }, - { url = "https://files.pythonhosted.org/packages/97/cc/48d232f33d60e2e2e0b42f4e73455b146b76ebe216487e862700457fbf3c/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:daf620c2995d193449393d6c62131b3fbd40a63bf7b307a1527856ace637fe88", size = 4328384, upload-time = "2025-10-16T22:16:59.36Z" }, - { url = "https://files.pythonhosted.org/packages/e4/16/c1fd27e9549f3c4baf1dc9c20c456cd2f822dbf8de9f463824b0c0357e06/uvloop-0.22.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cde23eeda1a25c75b2e07d39970f3374105d5eafbaab2a4482be82f272d5a5e", size = 4296730, upload-time = "2025-10-16T22:17:00.744Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cd/41/5e1a4bb12aac5f1493fa1bdc11154eca3b258ca4eba65d39c473fe19d8e9/watchfiles-1.2.0.tar.gz", hash = "sha256:c995fba777f1ea992f090f9236e9284cf7a5d1a0130dd5a3d82c598cacd76838", size = 108252, upload-time = "2026-05-18T04:32:04.251Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/2f/e42c992d2afda3108ea1c02acecc991b9f31d05c14adc2a7cee9ee211fc4/watchfiles-1.2.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:bc13eb17538be00c874699dc0abe4ee2bc8d50bb1166a6b9e175ef3fd7eb8f26", size = 400115, upload-time = "2026-05-18T04:32:02.06Z" }, - { url = "https://files.pythonhosted.org/packages/5f/8f/6af2ea19065c91d8b0ea3516fdfc8c0d349f407e8e9fbf4e5a17360de8ad/watchfiles-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d95ddc1eb6914154253d239089900813f6a767e174b8e6a50e7fdacb7e4236c", size = 393659, upload-time = "2026-05-18T04:30:50.951Z" }, - { url = "https://files.pythonhosted.org/packages/13/01/b32a967c56fb3e3e5be3db52c3d3b87fa4513aa367d8ed1ad96d42952e5f/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f70d8b291ef6e88d19b1f297a6905ddb978888d9272b0d05e6f53309856bcfc", size = 453207, upload-time = "2026-05-18T04:31:04.231Z" }, - { url = "https://files.pythonhosted.org/packages/04/98/97557a812180338cb1abd32e1cffcc4588f59b5f23e0cb006b2ba95ba64a/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:56d8641cf834c2836922899105bd3ce3d0dfc69291d52edf0b4d0436829b34c0", size = 459273, upload-time = "2026-05-18T04:31:50.377Z" }, - { url = "https://files.pythonhosted.org/packages/e8/a8/b4b08dcb7653b8087c6586f7ce649505900e866bbcfe40dc9587af02e686/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2581a94056e55d7d0a31a823ea92bf73749c489ca2285bfdc0fbe6b2bb49d50c", size = 489927, upload-time = "2026-05-18T04:31:42.485Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/3dceea03545d2e5ddfd839f0ddd5e1cecbf1697b5a428d5ba11cef6af95d/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41bc1199f7523b3f82843c88cbb979180c949caef0342cf90968f178e5d49b01", size = 570476, upload-time = "2026-05-18T04:31:03.071Z" }, - { url = "https://files.pythonhosted.org/packages/cc/f2/d39a5450c3532092b91f81d274360e613c2371bc874a89c7a1a3c5e8d138/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7571e4464cb6e434958f867f7f730b8ab0b75e3f8e5eac0499168486ab3c33a8", size = 465650, upload-time = "2026-05-18T04:30:12.701Z" }, - { url = "https://files.pythonhosted.org/packages/22/24/ed72f68cbc1333ca9b9f2200aa048bb6658ae41709bc1caad4310f4bdffd/watchfiles-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e53a384f76b631c3ae5334ce6a52f0baa3a911eb94a4eac7f160079868b716d5", size = 456398, upload-time = "2026-05-18T04:30:13.784Z" }, - { url = "https://files.pythonhosted.org/packages/0d/64/982ef4a4e5bab5b6e5b6becc8cd5e732f6130a78b855f0abec6439a9a135/watchfiles-1.2.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:d20029a60a71a052a24c4db7673bc4de39ab89adbaccbfb5d67987c5d73f424d", size = 465140, upload-time = "2026-05-18T04:31:52.111Z" }, - { url = "https://files.pythonhosted.org/packages/a0/0c/95282abf4ed680b6096010bcfc30c5fa7a041fc5aa5a2ad17a2cc6c75bba/watchfiles-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2cb93af48550faf1cea04c303107c8b75833de7013e57ce27d3b8d21d8d0f58c", size = 630259, upload-time = "2026-05-18T04:31:25.676Z" }, - { url = "https://files.pythonhosted.org/packages/30/45/607c1de1530c4bdcf2cf1d1ecc2505ddba5d96bd43ba9f2b0e79876f850f/watchfiles-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2995c176de7692b86a2e4c58d9ec718f753150a979cb4a754e2b4ffa38e70906", size = 659859, upload-time = "2026-05-18T04:30:24.333Z" }, - { url = "https://files.pythonhosted.org/packages/fa/08/d9e2e0f9e8e6791d33aefc694ad7eefa7f901f63caff84a81ded38692f9c/watchfiles-1.2.0-cp312-cp312-win32.whl", hash = "sha256:7a2cffd17d27d2ecbb310c2b1d8174f222a5495b1a721894afa88ec11e25b898", size = 275480, upload-time = "2026-05-18T04:30:31.307Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e6/9d42569c0102645cc8cea5d8c7d8a1e9d4ada2cb7f05f75e554b8aa2202a/watchfiles-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:f155b3a1b2a5fc89cdc70d47ee5d54e3b75e88efa34982028a35daef9ba00379", size = 288718, upload-time = "2026-05-18T04:32:10.745Z" }, - { url = "https://files.pythonhosted.org/packages/0a/26/88e0dc6ee3898169d7fa22bb6a69cabf2502d2ee25cb8c876d1262d204f8/watchfiles-1.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:8fa585ede612ee9f9e91b18bebf9ba11b9ae29a4e3a0d0cf6fca3e382133f0d5", size = 281026, upload-time = "2026-05-18T04:30:22.23Z" }, - { url = "https://files.pythonhosted.org/packages/d1/4d/70a7feced9f87e2ff26dba42667290f41694fc64646c67261fbb8cab5d5c/watchfiles-1.2.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:01ea8d66f0693b9b60a6541c8d10263091ca9a9060d242f3c1f3143f9aad2c98", size = 399730, upload-time = "2026-05-18T04:31:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/31/3a/0da302f2307aee316922806ebd5726c542cbd787c938271cf14a074c7daf/watchfiles-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7ba0480b9a74af058f43b337e937a451e109295c420916d68ad24e3dc02f5e44", size = 392842, upload-time = "2026-05-18T04:30:27.051Z" }, - { url = "https://files.pythonhosted.org/packages/db/ef/d5bdb705c224dbc256aa0c1ec47bf4e61ec52558f2afb44a71a1fe4d7015/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f34e26a19f91f710c08e0183429f0d1d15df734e6bc78c31e77b9ea9c433658", size = 452989, upload-time = "2026-05-18T04:31:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/71/29/5495f2c1661949ef7a35e4d71111d129cfe7606414a26887a919d0a55406/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b4e77f6a55f858504069abd35d336a637555c09bca453dde1ee1e5ada8a6a1fb", size = 458978, upload-time = "2026-05-18T04:30:52.606Z" }, - { url = "https://files.pythonhosted.org/packages/d5/8c/7f9c07c433811c2fffd93e13fdfb7135de9aab5f2ae41be08960fa0047dc/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb4d80e212f116474a545c21c912b445f16bb0cef9e6a73a498164223e14e2f", size = 490248, upload-time = "2026-05-18T04:31:36.003Z" }, - { url = "https://files.pythonhosted.org/packages/3c/11/d93632febc52fbc21be90231bb7c17fd5387f46c9076fd40a5f9c2ae6910/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b974946a10af379d425e2eef5b62f5c6ebeaccf91d45eaad6f5b27ecd4f91aa0", size = 571847, upload-time = "2026-05-18T04:31:10.862Z" }, - { url = "https://files.pythonhosted.org/packages/55/b4/383173e73aabb07ad1d9c7aa859d95437ac46a6d6a1e11005facda0c9d19/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86bc13c25a8d1fcd70b51d0ce7c9b65e90de5666fcbfd3e34957cc73ee19aeb5", size = 465974, upload-time = "2026-05-18T04:30:17.006Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6c/89b1a230a78f57c52dd8893adb1f92f94411721b6ec12596c56d98c74356/watchfiles-1.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca148d73dea36c9763aaa351e4d7a51780ec1584217c45276f4fe8239c768b71", size = 454782, upload-time = "2026-05-18T04:30:35.656Z" }, - { url = "https://files.pythonhosted.org/packages/24/62/1732118367cfff0a9fce3bf62ff4bfded09ef5df21d9d446b858b3f70a96/watchfiles-1.2.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:c525543d91961c6955b2636b308569e84a1d1c5f5f2932041ab9ef46422f43e3", size = 465182, upload-time = "2026-05-18T04:30:20.846Z" }, - { url = "https://files.pythonhosted.org/packages/28/96/716f7e5f51339bf22963f3345f9f27d7f3b30e2eadc597e257c881dd3c53/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a204794696ffb8f9b10fba6f7cb5216d42f3b2b71860ccac6b6e42f5f10973b0", size = 629841, upload-time = "2026-05-18T04:31:05.397Z" }, - { url = "https://files.pythonhosted.org/packages/4c/fe/c40783950fd771ccf66ab3ec2722d188a9af1c7f96c6e811f36e40c6e03f/watchfiles-1.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:10d86db20695afe7997ac9e1717637d6714a8d0220458c33f3d2061f54cec427", size = 658028, upload-time = "2026-05-18T04:31:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/71/72/4508db1856d1d87fcbb3b63f4839bab1b5682cb0e8d224d122263c09654a/watchfiles-1.2.0-cp313-cp313-win32.whl", hash = "sha256:eb283ee99e21ad6443c8cdb06ac5b34b1308c329cbdf03fa02b445363714c799", size = 275183, upload-time = "2026-05-18T04:30:59.57Z" }, - { url = "https://files.pythonhosted.org/packages/f9/36/14b76ca57652e5cc5fd1c11f32a261292c08a0d19a00351013c2549cbfb2/watchfiles-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:a0f27f01bee51861392bb6b7c4fdb290b27d1eb194e9e28788d68102a0e898d9", size = 288059, upload-time = "2026-05-18T04:32:07.937Z" }, - { url = "https://files.pythonhosted.org/packages/1b/8d/0a85e395398d8d20fadfe5c5d32c726eee17a519e78fb356f2cf7531bffe/watchfiles-1.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:3651aa7058595e9cfb75d35dd5ada2bf9f48a5b8a0f3562821d3e210c507e077", size = 280186, upload-time = "2026-05-18T04:31:54.484Z" }, - { url = "https://files.pythonhosted.org/packages/37/68/36db056f1fdcc5f07302f56e631774d6835bcd6fa3ace402304621d5f9e5/watchfiles-1.2.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:faea288b6f0ab1902ef08f4ca6de005dccf856c4e0c4f21b8c5fce02d90a1b08", size = 399031, upload-time = "2026-05-18T04:30:44.576Z" }, - { url = "https://files.pythonhosted.org/packages/c1/64/01a9d6f66a82a5c101ce939274106cc72759d62427e153f01edd2b9f87c2/watchfiles-1.2.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01859b11fd9fbca670f4d5da00fbac282cfea9bd67a2125d8b2833a3b5617ea9", size = 391205, upload-time = "2026-05-18T04:30:25.413Z" }, - { url = "https://files.pythonhosted.org/packages/84/2c/0a44fe058cb4bb7b8ede6b6670698bbb7c0400740e378d00022189b7b31d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fff610d7bb2256a317bb1e96f0d7862c7aa8076733ee5df0fd41bbe76a24a4f4", size = 451892, upload-time = "2026-05-18T04:32:14.005Z" }, - { url = "https://files.pythonhosted.org/packages/67/a1/351e0d56cd35e6488b5c8b4fb11a809a5bc923e8fe8fed9faf8920be0c89/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b141a4891c995a039cd89e9a49e62df1dc8a559a5d1a6e4c7106d16c12777a55", size = 458867, upload-time = "2026-05-18T04:31:22.279Z" }, - { url = "https://files.pythonhosted.org/packages/d5/7d/9d09605187f1b838998624049fcf8bf47b73c1a3b76901fcac1782f62277/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22943b7770483f6ea0721c6b11d022947a98eb0acae14694de034f4d0d38925", size = 490217, upload-time = "2026-05-18T04:31:43.657Z" }, - { url = "https://files.pythonhosted.org/packages/60/5d/a17a16eccb182f04188cd308ec24b1a71a9b5c4e7098269cf35d9fa56d02/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1bc6195825b7dcd217968bb1f801a60fd4c16e8eeab5bedc7fe917d7d5995ab4", size = 571458, upload-time = "2026-05-18T04:32:11.875Z" }, - { url = "https://files.pythonhosted.org/packages/d3/3d/4dd457062083ab1938e5dfd45032eb425cee2ac817287ca8ff4356183e5d/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4a4b147f5dca2a5d325a06a832fb43f345751adfbc63204aec30e0d9ca965a2", size = 464707, upload-time = "2026-05-18T04:30:43.492Z" }, - { url = "https://files.pythonhosted.org/packages/c6/71/ea8c57b128f5383de74d0c7d2d9c57ad7c9a65a930c451bd25d524b295b7/watchfiles-1.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4543579a9bdb0c9560039b4ffddbdb39545707659fbc430ce4c10f3f68d557f9", size = 454663, upload-time = "2026-05-18T04:30:16.061Z" }, - { url = "https://files.pythonhosted.org/packages/53/fd/2e812bf938406d7db351f0703ddd3fc6c061cf30d96153a77bc79a943a44/watchfiles-1.2.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:20aa0e708b920bde876a4aa82dc7dd6ebea228a63a67cda6632c2fc87b787efa", size = 463537, upload-time = "2026-05-18T04:31:44.9Z" }, - { url = "https://files.pythonhosted.org/packages/86/56/d17a7f1dd1bc3035f1072694a551301272f1739c2d8e319c927cb9e29b38/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:d413349d565dab74297f2a63e84a097936be69bf8f3b3801f27f380e32040f44", size = 629194, upload-time = "2026-05-18T04:31:14.141Z" }, - { url = "https://files.pythonhosted.org/packages/be/06/f1ff66bf5cae50aa4062779a0ecd0bbaf15e466195719074078947d9a17d/watchfiles-1.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:f28b2725eb8cce327b9b3ab02415c853011dc55c95832fe90de6bc56f5315f72", size = 656194, upload-time = "2026-05-18T04:31:47.14Z" }, - { url = "https://files.pythonhosted.org/packages/e7/54/a9c7ea9a82a4ac65e7004c0a03920b5cdd2f9c3b678757d9cd425aa51d53/watchfiles-1.2.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:b8c8358484d5fa12ef34f05b7f4168eaf1932f408725ff6d023c33ec17bd79d4", size = 400205, upload-time = "2026-05-18T04:32:05.153Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5d/c9ab3534374a4a67450696905d6ef16a04405448b8dc52bd752ae50423d4/watchfiles-1.2.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9f04b092229ad2c50126dd3c922c8822e51e605993764a33058d4a791ab42281", size = 392508, upload-time = "2026-05-18T04:30:54.849Z" }, - { url = "https://files.pythonhosted.org/packages/26/ca/1ad30103535cf0cecd7b993e8d50edc5351b1820e38f2d22e3df58962feb/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a7ce236284f002a156f70add88efe5c70879cccbb658be0822c54b1306fc09d", size = 452448, upload-time = "2026-05-18T04:30:53.727Z" }, - { url = "https://files.pythonhosted.org/packages/37/a1/ceee2cdf2afbd715fa07758d39c9859513eae411b23196f7fd039e5feedd/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b9909cc2b48468b575eefa944919e1fe8a36c5849d5c7c168f80a8c1db69398e", size = 459605, upload-time = "2026-05-18T04:30:23.312Z" }, - { url = "https://files.pythonhosted.org/packages/e8/f6/421e30fd1cb3907a84ed92ab3f1983e37ba2dca015e9a894a048418417a2/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a37faaed405c67e28e6be45a1fa4f206ef5a2860f27c237db9fa30704c38242", size = 490757, upload-time = "2026-05-18T04:30:47.358Z" }, - { url = "https://files.pythonhosted.org/packages/41/b0/55ed1b97ed08be7bba6f9a541cac15f2a858e1d74d2b07b6da70a82aab00/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9649193aa27bd9ff2e80ff29bfaa93085496c7a3a377592823cc58b77ee88add", size = 568672, upload-time = "2026-05-18T04:30:38.915Z" }, - { url = "https://files.pythonhosted.org/packages/d1/cf/d8ae8a80dd7bafab395ea7681c10237311bbf34d37704a8c744e7cf31fc7/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e4ff8e37f99cf1da89e255e07c9c4b37c214038c4283707bdec308cb1b0ea1f", size = 464197, upload-time = "2026-05-18T04:30:09.914Z" }, - { url = "https://files.pythonhosted.org/packages/7c/8a/3076c496ca8dafe0e8cd03fcebdfc47be4b1174b4e5b24ff6e396e6b3af2/watchfiles-1.2.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:054dc20fd2e3132b4c3883b4a00d72fd6e1f56fdaf89fccd12e8057d74cd74d7", size = 453181, upload-time = "2026-05-18T04:30:14.829Z" }, - { url = "https://files.pythonhosted.org/packages/e5/10/9745e17c98e7b8a86454df0a3c7b5686bd650383f1e9f26e4ebcbd6cc0c0/watchfiles-1.2.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:e140ed30ebde76796b686e67c182cff10ea2fbab186fafd1560f74bb5a473a6e", size = 465109, upload-time = "2026-05-18T04:30:28.123Z" }, - { url = "https://files.pythonhosted.org/packages/8f/95/8ef4a95481d3e0cb52d62a06fa6e972e81424be2d9698b91a2fecca9904c/watchfiles-1.2.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:bb7e52ecf68ba46d22df23467b87cffeb2146908aa523ebfe803019618cfda06", size = 630653, upload-time = "2026-05-18T04:31:49.304Z" }, - { url = "https://files.pythonhosted.org/packages/fd/e4/3b3bf36b0f829b50c6ebcb8d031583863c59f923d6a6af3d485e470d0fac/watchfiles-1.2.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:23282a321c8baf9b3a3c4afff673f9fe65eb7fdc2338d765ccad9d3d1916a5ba", size = 657838, upload-time = "2026-05-18T04:31:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/21/b1/6cbbb50c1f3002ab568777d44aa21206dfb8807a840990c4037523b51812/watchfiles-1.2.0-cp314-cp314-win32.whl", hash = "sha256:c0db965c5f79aa49fe672d297cf1febc5ad149b658594944f49a54a2b96270a7", size = 275108, upload-time = "2026-05-18T04:30:06.891Z" }, - { url = "https://files.pythonhosted.org/packages/92/45/190ce6db8dcb4536682cf75d3889ff1a27182a58cb519d343cb6d9ea63d8/watchfiles-1.2.0-cp314-cp314-win_amd64.whl", hash = "sha256:71283b39fd17e5408eb123bd37aeecfd9d54c81fc184421943208aadb879d103", size = 288441, upload-time = "2026-05-18T04:32:12.901Z" }, - { url = "https://files.pythonhosted.org/packages/74/0d/3eae1c2313ab08378431d907c3f8095ecca00f3eda33111cf4f0f2591799/watchfiles-1.2.0-cp314-cp314-win_arm64.whl", hash = "sha256:c5c19526f4e54a00f2666a6c0e9e40d582c09e865055ea7378bf0009aab857b3", size = 280684, upload-time = "2026-05-18T04:31:26.902Z" }, - { url = "https://files.pythonhosted.org/packages/b1/75/fb64e6c25d6b5ca636d03df34ffb1c6e9873303e76d27967e045f8df088f/watchfiles-1.2.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:d73a585accffa5ae39c17264c36ec3166d2fad7000c780f5ef83b2722afb9dd2", size = 398857, upload-time = "2026-05-18T04:32:17.108Z" }, - { url = "https://files.pythonhosted.org/packages/73/4e/9f7adf01754cbf81843722ccfec169d8f26c69778281a302855cecd2ee08/watchfiles-1.2.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ae99b14c5f21e026e0e9d96f40e07d8570ebee6cafd9d8fc318354606daa7a28", size = 392413, upload-time = "2026-05-18T04:31:07.911Z" }, - { url = "https://files.pythonhosted.org/packages/47/c8/bec626bcc2d69f44b9acb24ce7d60ed7b16b73628eea747fcbd169d8edda/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4429f3b105524a10b72c3a819b091c495d2811d419c1e1e8df773a5a5974f831", size = 452409, upload-time = "2026-05-18T04:31:20.142Z" }, - { url = "https://files.pythonhosted.org/packages/00/b7/b6362068e81e7c556d155a34c35d40ac3ef42d747b06d7f6e5bf58e359c2/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:43d818978d06062d9b22c4fab2ebe44cf5213d42dc8e62bda8c2760cfa2eeb33", size = 458827, upload-time = "2026-05-18T04:32:06.219Z" }, - { url = "https://files.pythonhosted.org/packages/67/f8/9a813fa42afb1e0b4625e75f0479826644d3ee8dc287e093799bc01f390c/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9f732dc58b2dbe69e464ccf8fff7a03b0dd0be439da4c0720d3558527d3d6b4", size = 490104, upload-time = "2026-05-18T04:31:56.034Z" }, - { url = "https://files.pythonhosted.org/packages/2f/bf/27dfb6094ca4c9aad21298b5525b6c53cb36121ee454331d05161e58d130/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f200104103feb097de4cab8fe4f5dd18a2026934c7dea98c55a2f5fd6d5a33b", size = 571360, upload-time = "2026-05-18T04:31:57.133Z" }, - { url = "https://files.pythonhosted.org/packages/fb/39/44a096d67270ea93df91d33877dbe91fbda3aa4f8ec2edf799d93eda8736/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ac26eefbf4af1741247d6fb68b11c49a25b2f7413fbd318a83a12aaa9cf666", size = 464644, upload-time = "2026-05-18T04:30:57.33Z" }, - { url = "https://files.pythonhosted.org/packages/0e/80/c7472203bad6268e3ef1ad260739704847898938ad7ea8b63a5131f46b50/watchfiles-1.2.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4997d4e4a55f0d02b6cde327322daf3a0400e5df6c6b15948994bf72497925", size = 454771, upload-time = "2026-05-18T04:30:48.736Z" }, - { url = "https://files.pythonhosted.org/packages/51/cf/3b10b268b4b7f0fc26e9debb5eef1998b515887840f444cd3ec80c688755/watchfiles-1.2.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:4c887eba18b7945ac73067a8b4a66f21cd46c2539b2bc68588f7be6c7eb6d26b", size = 463494, upload-time = "2026-05-18T04:31:33.826Z" }, - { url = "https://files.pythonhosted.org/packages/3d/3e/a4302545cd589262a0dc7d140e86f7688eba3f9c72776c27f7e23b8864c4/watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:3416ff151bb6b5a8d8d11664974fbef4d9305b9b2957839ab5a270468fd8df30", size = 629383, upload-time = "2026-05-18T04:31:15.596Z" }, - { url = "https://files.pythonhosted.org/packages/db/99/d5649df0a9a410d45b7c882304d0b790903ac9b6e8f2cfd12114e0c6b9f2/watchfiles-1.2.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:0e831a271c035d89789cffc386b6aa1375f39f1cd25eb7ca0997e4970d152fc5", size = 656093, upload-time = "2026-05-18T04:31:58.707Z" }, - { url = "https://files.pythonhosted.org/packages/92/b9/362702539275019a54dd2e94511b31a9b89c5f9e6a21966de7eb692549fc/watchfiles-1.2.0-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:37a6721cdf3f65dbb13aa9503510ccb4451603ac837e44d265d7992a597e1374", size = 400109, upload-time = "2026-05-18T04:31:16.879Z" }, - { url = "https://files.pythonhosted.org/packages/8f/75/71d5ba62db781e5587bded1d944c675374bc4aa37ff33d5018d98e8b6538/watchfiles-1.2.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2b37d10b5a63bd4d87e18472d80fa525bd670586fae62e5dd580452764879b65", size = 392167, upload-time = "2026-05-18T04:31:28.058Z" }, - { url = "https://files.pythonhosted.org/packages/3c/01/c66dd95d0423fe30d31820e2d1d5bda773764131bbb6ac0cb1cf303ac328/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a105bc2283f67e8fbec74253ec2d94925de92ed72c0393f1206bf326b7b7b69", size = 452372, upload-time = "2026-05-18T04:31:00.836Z" }, - { url = "https://files.pythonhosted.org/packages/91/15/2fe99557e72f85627c6a8eed50d889e8d101623e060a22ad75b875cb932d/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5327989a465505f05cfe06f04fa9d0c2fd5432bb243e10e6f012b1bdca3c8579", size = 459596, upload-time = "2026-05-18T04:31:34.96Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/d4acfa0023367428ed48351b3b9b267893037b6cadae55620c61c24bcfd4/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ecb47f183a8025b2aa18b546725c3657e542112ae9c0613a2af79b4fa8d04ad7", size = 490869, upload-time = "2026-05-18T04:31:59.923Z" }, - { url = "https://files.pythonhosted.org/packages/a4/5f/3164cbdce06c9fb95c4f7b9e2f9760b5e2797af43a9ecc317ef42a23a278/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8520a4ab0e37f770afc34459c4f8f7019e153f9124dc101c15538365875d1ab2", size = 571641, upload-time = "2026-05-18T04:32:00.948Z" }, - { url = "https://files.pythonhosted.org/packages/41/e6/85d3731c55e65cd7690f3f803d24c139588aaf863e4bf2148fe7a7fa1a19/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71cd71740ed2c15211ebb237ced4e39a1cdf6f80566e5fe95428da1626f4fde6", size = 464444, upload-time = "2026-05-18T04:30:34.298Z" }, - { url = "https://files.pythonhosted.org/packages/f4/7d/562641012b8b09872742c3b8adf9629ec479fd78f8d68ae4a0c13da8add6/watchfiles-1.2.0-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f88af53d6ddaf72179ef613ddc905e6f4785f712b49b80b3bef9f3525e6194b4", size = 453593, upload-time = "2026-05-18T04:31:23.464Z" }, - { url = "https://files.pythonhosted.org/packages/56/fe/cb8ef3d6f929d14158fdaaad9925985b7310abc9384dcd4d82dd0016fb59/watchfiles-1.2.0-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:cee9d5efd929efdac5f7e58f72b3376f676b64050a91c5b99a7094c5b2317488", size = 465096, upload-time = "2026-05-18T04:31:30.384Z" }, - { url = "https://files.pythonhosted.org/packages/25/91/80908e835e100527a9267147b08c0eee1fa6ab0ffec15edc04d1d44885f7/watchfiles-1.2.0-cp315-cp315-musllinux_1_1_aarch64.whl", hash = "sha256:b718bf356bbc15e559bd8ef41782b573b8ae0e3f177ab244b440568d7ea02cfb", size = 630638, upload-time = "2026-05-18T04:30:49.89Z" }, - { url = "https://files.pythonhosted.org/packages/46/4b/95ab2f256bb4af3cb2eb23b9317bda984ee6e0f11733a5c004a6c95b06e3/watchfiles-1.2.0-cp315-cp315-musllinux_1_1_x86_64.whl", hash = "sha256:922c0e019fe68b3ae392965a766b02a71ba1168c932cebc3733cd52c5fe5b377", size = 657684, upload-time = "2026-05-18T04:31:32.027Z" }, -] - -[[package]] -name = "websockets" -version = "16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" }, - { url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" }, - { url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" }, - { url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" }, - { url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" }, - { url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" }, - { url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" }, - { url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" }, - { url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" }, - { url = "https://files.pythonhosted.org/packages/cc/9c/baa8456050d1c1b08dd0ec7346026668cbc6f145ab4e314d707bb845bf0d/websockets-16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:878b336ac47938b474c8f982ac2f7266a540adc3fa4ad74ae96fea9823a02cc9", size = 177364, upload-time = "2026-01-10T09:22:59.333Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0c/8811fc53e9bcff68fe7de2bcbe75116a8d959ac699a3200f4847a8925210/websockets-16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52a0fec0e6c8d9a784c2c78276a48a2bdf099e4ccc2a4cad53b27718dbfd0230", size = 175039, upload-time = "2026-01-10T09:23:01.171Z" }, - { url = "https://files.pythonhosted.org/packages/aa/82/39a5f910cb99ec0b59e482971238c845af9220d3ab9fa76dd9162cda9d62/websockets-16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e6578ed5b6981005df1860a56e3617f14a6c307e6a71b4fff8c48fdc50f3ed2c", size = 175323, upload-time = "2026-01-10T09:23:02.341Z" }, - { url = "https://files.pythonhosted.org/packages/bd/28/0a25ee5342eb5d5f297d992a77e56892ecb65e7854c7898fb7d35e9b33bd/websockets-16.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:95724e638f0f9c350bb1c2b0a7ad0e83d9cc0c9259f3ea94e40d7b02a2179ae5", size = 184975, upload-time = "2026-01-10T09:23:03.756Z" }, - { url = "https://files.pythonhosted.org/packages/f9/66/27ea52741752f5107c2e41fda05e8395a682a1e11c4e592a809a90c6a506/websockets-16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c0204dc62a89dc9d50d682412c10b3542d748260d743500a85c13cd1ee4bde82", size = 186203, upload-time = "2026-01-10T09:23:05.01Z" }, - { url = "https://files.pythonhosted.org/packages/37/e5/8e32857371406a757816a2b471939d51c463509be73fa538216ea52b792a/websockets-16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:52ac480f44d32970d66763115edea932f1c5b1312de36df06d6b219f6741eed8", size = 185653, upload-time = "2026-01-10T09:23:06.301Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/f926bac29882894669368dc73f4da900fcdf47955d0a0185d60103df5737/websockets-16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6e5a82b677f8f6f59e8dfc34ec06ca6b5b48bc4fcda346acd093694cc2c24d8f", size = 184920, upload-time = "2026-01-10T09:23:07.492Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a1/3d6ccdcd125b0a42a311bcd15a7f705d688f73b2a22d8cf1c0875d35d34a/websockets-16.0-cp313-cp313-win32.whl", hash = "sha256:abf050a199613f64c886ea10f38b47770a65154dc37181bfaff70c160f45315a", size = 178255, upload-time = "2026-01-10T09:23:09.245Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ae/90366304d7c2ce80f9b826096a9e9048b4bb760e44d3b873bb272cba696b/websockets-16.0-cp313-cp313-win_amd64.whl", hash = "sha256:3425ac5cf448801335d6fdc7ae1eb22072055417a96cc6b31b3861f455fbc156", size = 178689, upload-time = "2026-01-10T09:23:10.483Z" }, - { url = "https://files.pythonhosted.org/packages/f3/1d/e88022630271f5bd349ed82417136281931e558d628dd52c4d8621b4a0b2/websockets-16.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8cc451a50f2aee53042ac52d2d053d08bf89bcb31ae799cb4487587661c038a0", size = 177406, upload-time = "2026-01-10T09:23:12.178Z" }, - { url = "https://files.pythonhosted.org/packages/f2/78/e63be1bf0724eeb4616efb1ae1c9044f7c3953b7957799abb5915bffd38e/websockets-16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:daa3b6ff70a9241cf6c7fc9e949d41232d9d7d26fd3522b1ad2b4d62487e9904", size = 175085, upload-time = "2026-01-10T09:23:13.511Z" }, - { url = "https://files.pythonhosted.org/packages/bb/f4/d3c9220d818ee955ae390cf319a7c7a467beceb24f05ee7aaaa2414345ba/websockets-16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fd3cb4adb94a2a6e2b7c0d8d05cb94e6f1c81a0cf9dc2694fb65c7e8d94c42e4", size = 175328, upload-time = "2026-01-10T09:23:14.727Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/d3e208028de777087e6fb2b122051a6ff7bbcca0d6df9d9c2bf1dd869ae9/websockets-16.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:781caf5e8eee67f663126490c2f96f40906594cb86b408a703630f95550a8c3e", size = 185044, upload-time = "2026-01-10T09:23:15.939Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6e/9a0927ac24bd33a0a9af834d89e0abc7cfd8e13bed17a86407a66773cc0e/websockets-16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caab51a72c51973ca21fa8a18bd8165e1a0183f1ac7066a182ff27107b71e1a4", size = 186279, upload-time = "2026-01-10T09:23:17.148Z" }, - { url = "https://files.pythonhosted.org/packages/b9/ca/bf1c68440d7a868180e11be653c85959502efd3a709323230314fda6e0b3/websockets-16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:19c4dc84098e523fd63711e563077d39e90ec6702aff4b5d9e344a60cb3c0cb1", size = 185711, upload-time = "2026-01-10T09:23:18.372Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f8/fdc34643a989561f217bb477cbc47a3a07212cbda91c0e4389c43c296ebf/websockets-16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5e18a238a2b2249c9a9235466b90e96ae4795672598a58772dd806edc7ac6d3", size = 184982, upload-time = "2026-01-10T09:23:19.652Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d1/574fa27e233764dbac9c52730d63fcf2823b16f0856b3329fc6268d6ae4f/websockets-16.0-cp314-cp314-win32.whl", hash = "sha256:a069d734c4a043182729edd3e9f247c3b2a4035415a9172fd0f1b71658a320a8", size = 177915, upload-time = "2026-01-10T09:23:21.458Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f1/ae6b937bf3126b5134ce1f482365fde31a357c784ac51852978768b5eff4/websockets-16.0-cp314-cp314-win_amd64.whl", hash = "sha256:c0ee0e63f23914732c6d7e0cce24915c48f3f1512ec1d079ed01fc629dab269d", size = 178381, upload-time = "2026-01-10T09:23:22.715Z" }, - { url = "https://files.pythonhosted.org/packages/06/9b/f791d1db48403e1f0a27577a6beb37afae94254a8c6f08be4a23e4930bc0/websockets-16.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:a35539cacc3febb22b8f4d4a99cc79b104226a756aa7400adc722e83b0d03244", size = 177737, upload-time = "2026-01-10T09:23:24.523Z" }, - { url = "https://files.pythonhosted.org/packages/bd/40/53ad02341fa33b3ce489023f635367a4ac98b73570102ad2cdd770dacc9a/websockets-16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b784ca5de850f4ce93ec85d3269d24d4c82f22b7212023c974c401d4980ebc5e", size = 175268, upload-time = "2026-01-10T09:23:25.781Z" }, - { url = "https://files.pythonhosted.org/packages/74/9b/6158d4e459b984f949dcbbb0c5d270154c7618e11c01029b9bbd1bb4c4f9/websockets-16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:569d01a4e7fba956c5ae4fc988f0d4e187900f5497ce46339c996dbf24f17641", size = 175486, upload-time = "2026-01-10T09:23:27.033Z" }, - { url = "https://files.pythonhosted.org/packages/e5/2d/7583b30208b639c8090206f95073646c2c9ffd66f44df967981a64f849ad/websockets-16.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:50f23cdd8343b984957e4077839841146f67a3d31ab0d00e6b824e74c5b2f6e8", size = 185331, upload-time = "2026-01-10T09:23:28.259Z" }, - { url = "https://files.pythonhosted.org/packages/45/b0/cce3784eb519b7b5ad680d14b9673a31ab8dcb7aad8b64d81709d2430aa8/websockets-16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:152284a83a00c59b759697b7f9e9cddf4e3c7861dd0d964b472b70f78f89e80e", size = 186501, upload-time = "2026-01-10T09:23:29.449Z" }, - { url = "https://files.pythonhosted.org/packages/19/60/b8ebe4c7e89fb5f6cdf080623c9d92789a53636950f7abacfc33fe2b3135/websockets-16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bc59589ab64b0022385f429b94697348a6a234e8ce22544e3681b2e9331b5944", size = 186062, upload-time = "2026-01-10T09:23:31.368Z" }, - { url = "https://files.pythonhosted.org/packages/88/a8/a080593f89b0138b6cba1b28f8df5673b5506f72879322288b031337c0b8/websockets-16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:32da954ffa2814258030e5a57bc73a3635463238e797c7375dc8091327434206", size = 185356, upload-time = "2026-01-10T09:23:32.627Z" }, - { url = "https://files.pythonhosted.org/packages/c2/b6/b9afed2afadddaf5ebb2afa801abf4b0868f42f8539bfe4b071b5266c9fe/websockets-16.0-cp314-cp314t-win32.whl", hash = "sha256:5a4b4cc550cb665dd8a47f868c8d04c8230f857363ad3c9caf7a0c3bf8c61ca6", size = 178085, upload-time = "2026-01-10T09:23:33.816Z" }, - { url = "https://files.pythonhosted.org/packages/9f/3e/28135a24e384493fa804216b79a6a6759a38cc4ff59118787b9fb693df93/websockets-16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b14dc141ed6d2dde437cddb216004bcac6a1df0935d79656387bd41632ba0bbd", size = 178531, upload-time = "2026-01-10T09:23:35.016Z" }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, -] diff --git a/apps/delta-command/next.config.ts b/apps/delta-command/next.config.ts deleted file mode 100644 index a519cb8..0000000 --- a/apps/delta-command/next.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { NextConfig } from "next"; - -const backendUrl = process.env.DELTA_API_URL ?? "http://127.0.0.1:8000"; - -const nextConfig: NextConfig = { - reactStrictMode: true, - async rewrites() { - return [ - { - source: "/api/:path*", - destination: `${backendUrl}/api/:path*`, - }, - ]; - }, -}; - -export default nextConfig; diff --git a/apps/delta-command/package-lock.json b/apps/delta-command/package-lock.json deleted file mode 100644 index 8b44c30..0000000 --- a/apps/delta-command/package-lock.json +++ /dev/null @@ -1,2560 +0,0 @@ -{ - "name": "delta-command", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "delta-command", - "version": "1.0.0", - "dependencies": { - "clsx": "^2.1.1", - "date-fns": "^4.1.0", - "lucide-react": "^0.468.0", - "next": "^15.1.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "recharts": "^2.15.0", - "tailwind-merge": "^2.6.0" - }, - "devDependencies": { - "@types/node": "^22.10.0", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "autoprefixer": "^10.4.20", - "playwright": "^1.49.1", - "postcss": "^8.4.49", - "tailwindcss": "^3.4.16", - "typescript": "^5.7.2" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.2.tgz", - "integrity": "sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@next/env": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.20.tgz", - "integrity": "sha512-dXh51Wvddf8daEyBXryZZEe1FdVxEWx9lgaTseLZUtC1XP/W8Wri+Z+VPOElHlByk23CyqHdc2oVByX7wsTWsw==", - "license": "MIT" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.20.tgz", - "integrity": "sha512-in0yXG7/pRBVjWeEl7f7ZZETpletSMFKXVS4GJgHENTPVrJFNJKPrYewa9rpZcvdjwFece5fZP0CK34G4PxowA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.20.tgz", - "integrity": "sha512-0hsFshdPnTzGJdDTHeHJ+XPUShOpnyp9pUFDwDhqctsA0Cd8NcIVGRPtptYhgYY9DjkKgCDRkXxmgRc+CgT5Wg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.20.tgz", - "integrity": "sha512-DMvkoBtAABOzE6pMZRW/xNm7sKqql3wzzzZJ1R/d/rp4BCxv6LykouD3tHjGY8WdQqGpZs11t+R9AtjPxvvljw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.20.tgz", - "integrity": "sha512-RQmDfeYBtXV2FSId7dfA1hE6M/T6+g7wdbYnFQ47tw/gUBwV+CccLVejNmCGa9yLDitk83foeg8hl/3DjfYQ5g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.20.tgz", - "integrity": "sha512-DkWLEdKajJwdGt27M3i1VEO2kelTvZrK6Pcb7JvW2BY+nofWm7FBsBNDj7g7Pr1NuQ5PLJvqEqYa20GTsBDnKQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.20.tgz", - "integrity": "sha512-rAO5b7pKHvX+ExdmJskusDXTNbiNZfptifIPZItbUx+AOXxxTydVBsPt7Oz84DRd5mY8e0DcE8kvLj3AIfjE6w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.20.tgz", - "integrity": "sha512-Hp3zFsN8N8Kj9+vY6L4vnZ9EtA9eXyATu0q4EfGbZTiocgPUNSfz8NWhym6xvaOmHpJ8EuoypuU1WejCPsTFtg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.20.tgz", - "integrity": "sha512-T/L7CXpR1M0wij/xbF3rT1+7KvSkfOLr7C+ToHHWZTG2eKmb52C5WvsyGCBNtkVvDEUESWkRUbbqSH4rSbOCYQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@types/d3-array": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", - "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", - "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", - "license": "MIT" - }, - "node_modules/@types/d3-ease": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", - "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", - "license": "MIT" - }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", - "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", - "license": "MIT", - "dependencies": { - "@types/d3-color": "*" - } - }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", - "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", - "license": "MIT", - "dependencies": { - "@types/d3-time": "*" - } - }, - "node_modules/@types/d3-shape": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", - "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", - "license": "MIT", - "dependencies": { - "@types/d3-path": "*" - } - }, - "node_modules/@types/d3-time": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", - "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", - "license": "MIT" - }, - "node_modules/@types/d3-timer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", - "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.20.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.0.tgz", - "integrity": "sha512-QWlFW2wf3nTjC13/DqRnBpR4ZO36VJH/JVBkA/vcnmbTBNQIlnObqyqZE1tUR7+Ni23Lda8R1BxMfbXRpCUx5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.17", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", - "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", - "dev": true, - "license": "MIT", - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "10.5.2", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.2.tgz", - "integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.4", - "caniuse-lite": "^1.0.30001799", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.41", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.41.tgz", - "integrity": "sha512-WwS7MHhqGHHlaVsqRZnhvCEMS0owDX+SxRlve7JkuH7My1Ara3ZriTmCQupPfYjxMZ8I/tgxtJYr2t7taHaH4A==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", - "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "baseline-browser-mapping": "^2.10.38", - "caniuse-lite": "^1.0.30001799", - "electron-to-chromium": "^1.5.376", - "node-releases": "^2.0.48", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001800", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", - "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", - "license": "MIT" - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", - "license": "ISC", - "dependencies": { - "internmap": "1 - 2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-ease": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", - "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-format": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", - "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", - "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/date-fns": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.4.0.tgz", - "integrity": "sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/decimal.js-light": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", - "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.387", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.387.tgz", - "integrity": "sha512-TaxwufTFDufvPEoXdhwVrA3UdFWBeWGkYoJ1K8ldF1xe6gKfth6iRNS5lTQ5JPNOHdGQm8PT1QYKUqFLCiUefQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/eventemitter3": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", - "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", - "license": "MIT" - }, - "node_modules/fast-equals": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.4.0.tgz", - "integrity": "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lucide-react": { - "version": "0.468.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", - "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.15", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz", - "integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/next": { - "version": "15.5.20", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.20.tgz", - "integrity": "sha512-cvyS3/geydan1xLtE3FA8VCgdoQ/Gg/dlOldFkFCbB5VcVYJV7090hQLBnvTW2PwT76Z/dHdzDZCsVhZpoOlUA==", - "license": "MIT", - "dependencies": { - "@next/env": "15.5.20", - "@swc/helpers": "0.5.15", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.20", - "@next/swc-darwin-x64": "15.5.20", - "@next/swc-linux-arm64-gnu": "15.5.20", - "@next/swc-linux-arm64-musl": "15.5.20", - "@next/swc-linux-x64-gnu": "15.5.20", - "@next/swc-linux-x64-musl": "15.5.20", - "@next/swc-win32-arm64-msvc": "15.5.20", - "@next/swc-win32-x64-msvc": "15.5.20", - "sharp": "^0.34.3" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/node-releases": { - "version": "2.0.50", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", - "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/playwright": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", - "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.49.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.49.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", - "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/postcss": { - "version": "8.5.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz", - "integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", - "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", - "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.7" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, - "node_modules/react-smooth": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", - "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", - "license": "MIT", - "dependencies": { - "fast-equals": "^5.0.1", - "prop-types": "^15.8.1", - "react-transition-group": "^4.4.5" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "license": "BSD-3-Clause", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/recharts": { - "version": "2.15.4", - "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", - "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", - "deprecated": "1.x and 2.x branches are no longer active. Bump to Recharts v3 to receive latest features and bugfixes. See https://github.com/recharts/recharts/wiki/3.0-migration-guide", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0", - "eventemitter3": "^4.0.1", - "lodash": "^4.17.21", - "react-is": "^18.3.1", - "react-smooth": "^4.0.4", - "recharts-scale": "^0.4.4", - "tiny-invariant": "^1.3.1", - "victory-vendor": "^36.6.8" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/recharts-scale": { - "version": "0.4.5", - "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", - "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", - "license": "MIT", - "dependencies": { - "decimal.js-light": "^2.4.1" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.2", - "semver": "^7.7.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "license": "MIT", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwind-merge": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", - "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tiny-invariant": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", - "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/victory-vendor": { - "version": "36.9.2", - "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", - "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", - "license": "MIT AND ISC", - "dependencies": { - "@types/d3-array": "^3.0.3", - "@types/d3-ease": "^3.0.0", - "@types/d3-interpolate": "^3.0.1", - "@types/d3-scale": "^4.0.2", - "@types/d3-shape": "^3.1.0", - "@types/d3-time": "^3.0.0", - "@types/d3-timer": "^3.0.0", - "d3-array": "^3.1.6", - "d3-ease": "^3.0.1", - "d3-interpolate": "^3.0.1", - "d3-scale": "^4.0.2", - "d3-shape": "^3.1.0", - "d3-time": "^3.0.0", - "d3-timer": "^3.0.1" - } - } - } -} diff --git a/apps/delta-command/package.json b/apps/delta-command/package.json deleted file mode 100644 index 128bb6c..0000000 --- a/apps/delta-command/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "delta-command", - "version": "1.0.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "clsx": "^2.1.1", - "date-fns": "^4.1.0", - "lucide-react": "^0.468.0", - "next": "^15.1.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "recharts": "^2.15.0", - "tailwind-merge": "^2.6.0" - }, - "devDependencies": { - "@types/node": "^22.10.0", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "autoprefixer": "^10.4.20", - "playwright": "^1.49.1", - "postcss": "^8.4.49", - "tailwindcss": "^3.4.16", - "typescript": "^5.7.2" - } -} diff --git a/apps/delta-command/postcss.config.mjs b/apps/delta-command/postcss.config.mjs deleted file mode 100644 index 2ef30fc..0000000 --- a/apps/delta-command/postcss.config.mjs +++ /dev/null @@ -1,9 +0,0 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; - -export default config; diff --git a/apps/delta-command/scripts/capture-ui.mjs b/apps/delta-command/scripts/capture-ui.mjs deleted file mode 100644 index 0256205..0000000 --- a/apps/delta-command/scripts/capture-ui.mjs +++ /dev/null @@ -1,26 +0,0 @@ -import { chromium } from "playwright"; - -const routes = [ - ["/dashboard", "/opt/cursor/artifacts/dashboard-styled.png"], - ["/team", "/opt/cursor/artifacts/team-timeline-styled.png"], - ["/opportunities", "/opt/cursor/artifacts/opportunities-styled.png"], - ["/projects", "/opt/cursor/artifacts/projects-styled.png"], -]; - -const browser = await chromium.launch(); -const page = await browser.newPage({ viewport: { width: 1440, height: 900 } }); - -for (const [path, file] of routes) { - await page.goto(`http://localhost:3000${path}`, { waitUntil: "networkidle" }); - await page.waitForFunction(() => { - const sidebar = document.querySelector(".nav-drawer"); - if (!sidebar) return false; - const bg = getComputedStyle(sidebar).backgroundColor; - return bg !== "rgba(0, 0, 0, 0)" && bg !== "transparent"; - }); - await page.waitForTimeout(800); - await page.screenshot({ path: file, fullPage: true }); - console.log(`Saved ${file}`); -} - -await browser.close(); diff --git a/apps/delta-command/src/app/dashboard/page.tsx b/apps/delta-command/src/app/dashboard/page.tsx deleted file mode 100644 index 0c2e064..0000000 --- a/apps/delta-command/src/app/dashboard/page.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { Header } from "@/components/layout/Header"; -import { KPICard } from "@/components/dashboard/KPICard"; -import { PipelineChart } from "@/components/dashboard/PipelineChart"; -import { UtilizationChart } from "@/components/dashboard/UtilizationChart"; -import { ActionItemsPanel } from "@/components/dashboard/ActionItemsPanel"; -import { - PipelineHealthPanel, - MilestonesPanel, -} from "@/components/dashboard/PipelineHealthPanel"; -import { - DeliveryOverviewPanel, - TeamSnapshotPanel, -} from "@/components/dashboard/DeliveryOverviewPanel"; -import { ProjectCard } from "@/components/projects/ProjectCard"; -import { getDashboardMetrics, getEngineers, getOpportunities, getProjects } from "@/core/api"; -import { buildDashboardInsights } from "@/core/dashboard-analytics"; -import { formatCurrency, formatDate } from "@/core/utils"; -import { - DollarSign, - Target, - FolderKanban, - Users, - Layers, - Flame, - CalendarClock, -} from "lucide-react"; -import Link from "next/link"; - -export const dynamic = "force-dynamic"; - -export default async function DashboardPage() { - const [metrics, engineers, opportunities, projects] = await Promise.all([ - getDashboardMetrics(), - getEngineers(), - getOpportunities(), - getProjects(), - ]); - - const insights = buildDashboardInsights(engineers, opportunities, projects); - const { pipeline, delivery, team, actions, milestones } = insights; - - const atRiskProjects = projects.filter((p) => p.status === "at_risk"); - const upcomingCloses = opportunities - .filter((o) => !["won", "lost"].includes(o.stage)) - .sort( - (a, b) => - new Date(a.expectedClose).getTime() - new Date(b.expectedClose).getTime() - ) - .slice(0, 5); - - const engineerNames = Object.fromEntries( - engineers.map((e) => [e.id, e.name]) - ); - - return ( -
-
- -
- {/* Primary KPIs — derived from live data */} -
- - - - - - -
- - {/* Prioritized actions */} - - - {/* Charts */} -
- - -
- - {/* Insight panels */} -
- - - -
- - - - {/* Closes + projects */} -
-
-
-
-

Upcoming Closes

-

- {formatCurrency(pipeline.closingValue30Days)} in next 30 days -

-
- - View all - -
-
- {upcomingCloses.map((opp) => ( -
-
-

- {opp.title} -

-

{opp.client}

-
- {opp.stage} - - {opp.probability}% - -
-
-
-

- {formatCurrency(opp.value)} -

-

- - {formatDate(opp.expectedClose)} -

-

- Wtd {formatCurrency(opp.value * (opp.probability / 100))} -

-
-
- ))} -
-
- -
-
-
-

Projects Needing Attention

-

- {atRiskProjects.length > 0 - ? `${atRiskProjects.length} at risk · ${delivery.overdueMilestones} overdue milestones` - : "Active delivery status"} -

-
- - View all projects - -
-
- {(atRiskProjects.length > 0 - ? atRiskProjects - : projects.filter((p) => p.status === "active").slice(0, 2) - ).map((project) => ( - - ))} -
-
-
- -
-

- Last updated {formatDate(metrics.lastUpdated.split("T")[0])} ·{" "} - {metrics.teamSize} engineers · {metrics.activeOpportunities} active - opportunities · {metrics.availableCapacity} with capacity below 70% -

-
-
-
- ); -} diff --git a/apps/delta-command/src/app/globals.css b/apps/delta-command/src/app/globals.css deleted file mode 100644 index 3b4177e..0000000 --- a/apps/delta-command/src/app/globals.css +++ /dev/null @@ -1,217 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - :root { - --sidebar-width: 15rem; - color-scheme: dark; - } - - * { - @apply border-outline-variant/50; - } - - body { - @apply bg-surface text-surface-on antialiased; - font-feature-settings: "kern" 1, "liga" 1; - } - - h1, h2, h3, h4 { - @apply tracking-tight text-surface-on; - } - - select option { - @apply bg-surface-bright text-surface-on; - } -} - -@layer components { - .card { - @apply rounded-xl border border-white/[0.06] bg-surface-bright/80 shadow-card - backdrop-blur-sm transition-all duration-300 ease-emphasized - hover:border-white/[0.1] hover:bg-surface-bright hover:shadow-elevated; - } - - .card-flat { - @apply rounded-xl border border-white/[0.06] bg-surface-bright/80; - } - - .badge { - @apply inline-flex items-center rounded-md px-2 py-0.5 text-[11px] font-medium leading-4; - } - - .chip { - @apply inline-flex items-center rounded-md bg-surface-container/60 px-2 py-0.5 - text-[11px] font-medium leading-4 text-surface-on-variant ring-1 ring-inset ring-white/[0.06]; - } - - .btn-primary { - @apply inline-flex items-center justify-center gap-2 rounded-lg bg-accent px-5 py-2 - text-sm font-medium text-white shadow-sm - transition-all duration-200 ease-standard - hover:bg-blue-400 active:scale-[0.98] - focus-visible:outline-none focus-visible:shadow-glow; - } - - .btn-secondary { - @apply inline-flex items-center justify-center gap-2 rounded-lg border border-white/[0.08] - bg-surface-container px-5 py-2 text-sm font-medium text-surface-on - transition-all duration-200 ease-standard - hover:bg-surface-container-high - focus-visible:outline-none focus-visible:shadow-glow; - } - - .btn-tonal { - @apply inline-flex items-center justify-center gap-2 rounded-lg bg-accent-muted px-5 py-2 - text-sm font-medium text-accent-foreground - transition-all duration-200 ease-standard hover:bg-blue-500/20; - } - - .icon-btn { - @apply relative flex h-9 w-9 items-center justify-center rounded-lg - text-surface-on-variant transition-all duration-200 ease-standard - hover:bg-white/[0.06] hover:text-surface-on; - } - - .headline-md { - @apply text-2xl font-semibold leading-8 tracking-tight; - } - - .title-lg { - @apply text-lg font-semibold leading-7 tracking-tight; - } - - .title-md { - @apply text-sm font-semibold leading-5; - } - - .title-sm { - @apply text-sm font-medium leading-5; - } - - .body-md { - @apply text-sm font-normal leading-5 text-surface-on-variant; - } - - .label-md { - @apply text-xs font-medium uppercase tracking-wider text-surface-on-variant/70; - } - - .section-title { - @apply text-base font-semibold tracking-tight text-surface-on; - } - - .metric-value { - @apply text-3xl font-semibold leading-none tracking-tight text-surface-on; - } - - .metric-label { - @apply text-xs font-medium uppercase tracking-wider text-surface-on-variant/80; - } - - .nav-item { - @apply relative flex items-center gap-3 rounded-lg px-3 py-2.5 text-sm font-medium - text-sidebar-muted transition-all duration-200 ease-standard - hover:bg-white/[0.05] hover:text-sidebar-foreground; - } - - .nav-item-active { - @apply bg-white/[0.08] text-sidebar-foreground before:absolute before:left-0 before:top-1/2 - before:h-5 before:w-0.5 before:-translate-y-1/2 before:rounded-full before:bg-accent - before:shadow-[0_0_8px_rgb(59_130_246/0.6)] before:content-['']; - } - - .text-field-outlined { - @apply rounded-lg border border-white/[0.08] bg-surface-container/80 text-sm text-surface-on - outline-none transition-all duration-200 - placeholder:text-surface-on-variant/40 - focus:border-accent/60 focus:shadow-glow; - } - - .banner-error { - @apply flex items-center gap-3 rounded-xl border border-red-500/30 bg-red-500/10 px-5 py-3.5 - text-red-300 backdrop-blur-sm; - } - - .banner-warning { - @apply flex items-center gap-3 rounded-xl border border-amber-500/30 bg-amber-500/10 px-5 py-3.5 - text-amber-200 backdrop-blur-sm; - } - - .progress-track { - @apply h-1.5 overflow-hidden rounded-full bg-surface-container-high/80; - } - - .progress-indicator { - @apply h-full rounded-full bg-accent transition-all duration-500 ease-emphasized; - } - - .top-app-bar { - @apply sticky top-0 z-20 flex h-[4.25rem] items-center justify-between - border-b border-white/[0.06] bg-surface/80 px-6 backdrop-blur-xl md:px-8; - } - - .nav-drawer { - @apply fixed inset-y-0 left-0 z-30 flex w-60 flex-col - border-r border-sidebar-border bg-sidebar text-sidebar-foreground; - } - - .segmented-control { - @apply inline-flex rounded-lg bg-surface-container/80 p-1 ring-1 ring-inset ring-white/[0.06]; - } - - .segmented-item { - @apply flex items-center gap-2 rounded-md px-3.5 py-2 text-sm font-medium - text-surface-on-variant transition-all duration-200 ease-standard - hover:text-surface-on; - } - - .segmented-item-active { - @apply bg-surface-bright text-surface-on shadow-sm ring-1 ring-white/[0.08]; - } - - .link-subtle { - @apply text-xs font-medium text-accent-foreground transition-colors hover:text-accent; - } - - .stat-inline { - @apply flex items-center gap-3; - } - - .stat-icon { - @apply flex h-9 w-9 shrink-0 items-center justify-center rounded-lg; - } - - .kanban-column { - @apply flex w-72 shrink-0 flex-col rounded-xl border border-white/[0.06] - bg-surface-container-low/60 p-3 backdrop-blur-sm; - } - - .page-shell { - @apply bg-radial-glow bg-grid-pattern bg-grid bg-surface; - } - - .util-cell { - @apply mx-auto flex h-10 w-[68px] flex-col items-center justify-center rounded-lg - text-sm font-semibold ring-1 ring-inset transition-all duration-200 - hover:scale-[1.02] hover:brightness-110 active:scale-[0.98]; - } -} - -::-webkit-scrollbar { - width: 6px; - height: 6px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - @apply rounded-full bg-zinc-700; -} - -::-webkit-scrollbar-thumb:hover { - @apply bg-zinc-600; -} diff --git a/apps/delta-command/src/app/layout.tsx b/apps/delta-command/src/app/layout.tsx deleted file mode 100644 index 64680f8..0000000 --- a/apps/delta-command/src/app/layout.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { Metadata } from "next"; -import { Inter } from "next/font/google"; -import { Sidebar } from "@/components/layout/Sidebar"; -import "./globals.css"; - -const inter = Inter({ - variable: "--font-inter", - subsets: ["latin"], - display: "swap", -}); - -export const metadata: Metadata = { - title: "Delta Command — Engineering Hub", - description: - "Track opportunities, team utilization, and project execution for delta engineering teams.", -}; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - - -
- -
{children}
-
- - - ); -} diff --git a/apps/delta-command/src/app/opportunities/page.tsx b/apps/delta-command/src/app/opportunities/page.tsx deleted file mode 100644 index 1ae604b..0000000 --- a/apps/delta-command/src/app/opportunities/page.tsx +++ /dev/null @@ -1,160 +0,0 @@ -"use client"; - -import { useEffect, useState, useCallback } from "react"; -import { Header } from "@/components/layout/Header"; -import { PipelineBoard } from "@/components/opportunities/PipelineBoard"; -import { OpportunityCard } from "@/components/opportunities/PipelineBoard"; -import type { Opportunity, OpportunityStage } from "@/core/types"; -import { OPPORTUNITY_STAGES } from "@/core/types"; -import { updateOpportunityStage } from "@/core/api"; -import { formatCurrency, cn } from "@/core/utils"; -import { LayoutGrid, List, Trophy, XCircle } from "lucide-react"; - -export default function OpportunitiesPage() { - const [opportunities, setOpportunities] = useState([]); - const [view, setView] = useState<"board" | "list">("board"); - const [loading, setLoading] = useState(true); - - const fetchOpportunities = useCallback(async () => { - const res = await fetch("/api/opportunities"); - const data = await res.json(); - setOpportunities(data); - setLoading(false); - }, []); - - useEffect(() => { - fetchOpportunities(); - }, [fetchOpportunities]); - - const handleStageChange = async (id: string, stage: OpportunityStage) => { - await updateOpportunityStage(id, stage); - await fetchOpportunities(); - }; - - const activeOpps = opportunities.filter( - (o) => !["won", "lost"].includes(o.stage) - ); - const wonOpps = opportunities.filter((o) => o.stage === "won"); - const lostOpps = opportunities.filter((o) => o.stage === "lost"); - const totalValue = activeOpps.reduce((sum, o) => sum + o.value, 0); - const weightedValue = activeOpps.reduce( - (sum, o) => sum + o.value * (o.probability / 100), - 0 - ); - - if (loading) { - return ( -
-
-
-
-
-
- ); - } - - return ( -
-
- -
-
-
-

Active Pipeline

-

- {formatCurrency(totalValue)} -

-
-
-

Weighted Value

-

- {formatCurrency(weightedValue)} -

-
-
-
- -

Won

-
-

- {wonOpps.length} · {formatCurrency(wonOpps.reduce((s, o) => s + o.value, 0))} -

-
-
-
- -

Lost

-
-

- {lostOpps.length} -

-
-
- -
-
- - -
- -
- {OPPORTUNITY_STAGES.filter((s) => - ["won", "lost"].includes(s.id) - ).map((stage) => { - const count = opportunities.filter((o) => o.stage === stage.id).length; - return ( - - - {stage.label}: {count} - - ); - })} -
-
- - {view === "board" ? ( - - ) : ( -
- {opportunities.map((opp) => ( - - ))} -
- )} -
-
- ); -} diff --git a/apps/delta-command/src/app/page.tsx b/apps/delta-command/src/app/page.tsx deleted file mode 100644 index a74cb27..0000000 --- a/apps/delta-command/src/app/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { redirect } from "next/navigation"; - -export default function Home() { - redirect("/dashboard"); -} diff --git a/apps/delta-command/src/app/projects/page.tsx b/apps/delta-command/src/app/projects/page.tsx deleted file mode 100644 index 0c851e4..0000000 --- a/apps/delta-command/src/app/projects/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { ProjectsPageClient } from "@/components/projects/ProjectsPageClient"; - -export default function ProjectsPage() { - return ; -} diff --git a/apps/delta-command/src/app/team/page.tsx b/apps/delta-command/src/app/team/page.tsx deleted file mode 100644 index 5b4dfed..0000000 --- a/apps/delta-command/src/app/team/page.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { getEngineers, getProjects, getUtilizationTimeline } from "@/core/api"; -import { TeamPageClient } from "@/components/team/TeamPageClient"; - -export const dynamic = "force-dynamic"; - -export default async function TeamPage() { - const [engineers, projects, timeline] = await Promise.all([ - getEngineers(), - getProjects(), - getUtilizationTimeline(), - ]); - - return ( - - ); -} diff --git a/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx b/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx deleted file mode 100644 index 3cc7c31..0000000 --- a/apps/delta-command/src/components/dashboard/ActionItemsPanel.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import Link from "next/link"; -import type { ActionItem, ActionSeverity } from "@/core/dashboard-analytics"; -import { cn } from "@/core/utils"; -import { - AlertCircle, - AlertTriangle, - Info, - ArrowRight, -} from "lucide-react"; - -const severityStyles: Record< - ActionSeverity, - { container: string; icon: typeof AlertCircle } -> = { - critical: { - container: "border-red-500/30 bg-red-500/10", - icon: AlertCircle, - }, - warning: { - container: "border-amber-500/30 bg-amber-500/10", - icon: AlertTriangle, - }, - info: { - container: "border-blue-500/30 bg-blue-500/10", - icon: Info, - }, -}; - -interface ActionItemsPanelProps { - items: ActionItem[]; -} - -export function ActionItemsPanel({ items }: ActionItemsPanelProps) { - if (items.length === 0) return null; - - const critical = items.filter((i) => i.severity === "critical").length; - const warning = items.filter((i) => i.severity === "warning").length; - - return ( -
-
-
-

Action Required

-

- {critical > 0 && `${critical} critical`} - {critical > 0 && warning > 0 && " · "} - {warning > 0 && `${warning} needs attention`} - {critical === 0 && warning === 0 && `${items.length} items`} -

-
-
-
    - {items.slice(0, 6).map((item) => { - const style = severityStyles[item.severity]; - const Icon = style.icon; - return ( -
  • - - -
    -

    {item.title}

    -

    {item.detail}

    -
    - - -
  • - ); - })} -
-
- ); -} diff --git a/apps/delta-command/src/components/dashboard/DeliveryOverviewPanel.tsx b/apps/delta-command/src/components/dashboard/DeliveryOverviewPanel.tsx deleted file mode 100644 index 9dbadc7..0000000 --- a/apps/delta-command/src/components/dashboard/DeliveryOverviewPanel.tsx +++ /dev/null @@ -1,164 +0,0 @@ -import Link from "next/link"; -import type { DeliveryInsight, TeamInsight } from "@/core/dashboard-analytics"; -import { formatCurrency, cn, getUtilizationTextColor } from "@/core/utils"; -import { Users, Wallet, Clock, UserCheck } from "lucide-react"; - -interface DeliveryOverviewPanelProps { - delivery: DeliveryInsight; -} - -export function DeliveryOverviewPanel({ delivery }: DeliveryOverviewPanelProps) { - const statusRows = [ - { label: "Active", count: delivery.activeCount, color: "bg-accent" }, - { label: "Planning", count: delivery.planningCount, color: "bg-zinc-300" }, - { label: "At risk", count: delivery.atRiskCount, color: "bg-red-500" }, - ]; - const total = statusRows.reduce((s, r) => s + r.count, 0) || 1; - - return ( -
-
-

Delivery Overview

- - View projects - -
- -
-
-
- - Budget burn -
-

{delivery.burnPercent}%

-

- {formatCurrency(delivery.totalSpent)} of {formatCurrency(delivery.totalBudget)} -

-
-
-
- - Due soon -
-

{delivery.milestonesDue14Days}

-

- milestones in 14 days - {delivery.overdueMilestones > 0 && - ` · ${delivery.overdueMilestones} overdue`} -

-
-
- -
- {statusRows.map((row) => - row.count > 0 ? ( -
- ) : null - )} -
-
- {statusRows.map((row) => ( - - - {row.label}: {row.count} - - ))} - {delivery.projectsEnding30Days > 0 && ( - - · {delivery.projectsEnding30Days} ending in 30d - - )} -
-
- ); -} - -interface TeamSnapshotPanelProps { - team: TeamInsight; - teamSize: number; - avgUtilization: number; -} - -export function TeamSnapshotPanel({ - team, - teamSize, - avgUtilization, -}: TeamSnapshotPanelProps) { - return ( -
-
-

Team Capacity

- - View team - -
- -
-
-

- {avgUtilization}% -

-

Avg util

-
-
-

{team.benchCapacityPercent}%

-

Bench

-
-
-

{team.available.length}

-

Available

-
-
- - {team.overallocated.length > 0 && ( -
-

Overallocated

-
    - {team.overallocated.slice(0, 8).map((e) => ( -
  • - - - {e.name.split(" ")[0]} - - {e.utilization}% -
  • - ))} -
- {team.overallocated.length > 8 && ( -

- + {team.overallocated.length - 8} more overallocated -

- )} -
- )} - - {team.unassigned.length > 0 && ( -
-

Ready for assignment

-
    - {team.unassigned.map((e) => ( -
  • - - {e.name.split(" ")[0]} -
  • - ))} -
-
- )} - - {team.overallocated.length === 0 && team.unassigned.length === 0 && ( -

- {teamSize} engineers actively allocated across delivery workstreams. -

- )} -
- ); -} diff --git a/apps/delta-command/src/components/dashboard/KPICard.tsx b/apps/delta-command/src/components/dashboard/KPICard.tsx deleted file mode 100644 index 287af2d..0000000 --- a/apps/delta-command/src/components/dashboard/KPICard.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { cn } from "@/core/utils"; -import type { LucideIcon } from "lucide-react"; -import { TrendingUp, TrendingDown, Minus } from "lucide-react"; - -interface KPICardProps { - label: string; - value: string; - context?: string; - change?: number; - changeLabel?: string; - icon: LucideIcon; - iconColor?: string; -} - -export function KPICard({ - label, - value, - context, - change, - changeLabel, - icon: Icon, - iconColor = "text-accent bg-accent-muted", -}: KPICardProps) { - const trendIcon = - change === undefined ? null : change > 0 ? TrendingUp : change < 0 ? TrendingDown : Minus; - const TrendIcon = trendIcon; - const trendColor = - change === undefined - ? "" - : change > 0 - ? "text-emerald-400" - : change < 0 - ? "text-red-400" - : "text-surface-on-variant"; - - return ( -
-
-

{label}

-
- -
-
-

{value}

- {context && ( -

{context}

- )} - {change !== undefined && TrendIcon && ( -
- - - {change > 0 ? "+" : ""} - {change}% - - {changeLabel && ( - {changeLabel} - )} -
- )} -
- ); -} diff --git a/apps/delta-command/src/components/dashboard/PipelineChart.tsx b/apps/delta-command/src/components/dashboard/PipelineChart.tsx deleted file mode 100644 index 35b4393..0000000 --- a/apps/delta-command/src/components/dashboard/PipelineChart.tsx +++ /dev/null @@ -1,84 +0,0 @@ -"use client"; - -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - Cell, -} from "recharts"; -import { OPPORTUNITY_STAGES } from "@/core/types"; -import type { Opportunity } from "@/core/types"; -import { formatCurrency, CHART_GRID, CHART_TICK, CHART_TOOLTIP_STYLE } from "@/core/utils"; - -interface PipelineChartProps { - opportunities: Opportunity[]; -} - -const STAGE_COLORS: Record = { - prospect: "#A1A1AA", - qualified: "#3B82F6", - proposal: "#8B5CF6", - negotiation: "#6366F1", - won: "#10B981", - lost: "#EF4444", -}; - -const CHART_GRID_COLOR = CHART_GRID; -const CHART_TICK_COLOR = CHART_TICK; - -export function PipelineChart({ opportunities }: PipelineChartProps) { - const data = OPPORTUNITY_STAGES.filter((s) => !["lost"].includes(s.id)).map( - (stage) => { - const opps = opportunities.filter((o) => o.stage === stage.id); - return { - stage: stage.label, - count: opps.length, - value: opps.reduce((sum, o) => sum + o.value, 0), - fill: STAGE_COLORS[stage.id], - }; - } - ); - - return ( -
-

Pipeline by Stage

-

- Opportunity count and value across the sales funnel -

-
- - - - - - { - if (name === "value") return [formatCurrency(value), "Total Value"]; - return [value, "Count"]; - }} - /> - - {data.map((entry, index) => ( - - ))} - - - -
-
- ); -} diff --git a/apps/delta-command/src/components/dashboard/PipelineHealthPanel.tsx b/apps/delta-command/src/components/dashboard/PipelineHealthPanel.tsx deleted file mode 100644 index 0dbca95..0000000 --- a/apps/delta-command/src/components/dashboard/PipelineHealthPanel.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import Link from "next/link"; -import type { MilestoneItem } from "@/core/dashboard-analytics"; -import type { PipelineInsight } from "@/core/dashboard-analytics"; -import { formatCurrency, formatShortDate, cn } from "@/core/utils"; -import { Handshake, FileText, CalendarClock, BarChart3 } from "lucide-react"; - -interface PipelineHealthPanelProps { - pipeline: PipelineInsight; -} - -export function PipelineHealthPanel({ pipeline }: PipelineHealthPanelProps) { - const stats = [ - { - icon: FileText, - label: "In proposal", - value: String(pipeline.inProposal), - detail: formatCurrency(pipeline.proposalValue), - }, - { - icon: Handshake, - label: "In negotiation", - value: String(pipeline.inNegotiation), - detail: formatCurrency(pipeline.negotiationValue), - }, - { - icon: CalendarClock, - label: "Closing in 30d", - value: String(pipeline.closingWithin30Days), - detail: formatCurrency(pipeline.closingValue30Days), - }, - { - icon: BarChart3, - label: "Avg deal / probability", - value: formatCurrency(pipeline.avgDealSize), - detail: `${pipeline.avgProbability}% avg probability`, - }, - ]; - - return ( -
-
-

Pipeline Health

- - View pipeline - -
-
- {stats.map((stat) => ( -
-
- - {stat.label} -
-

{stat.value}

-

{stat.detail}

-
- ))} -
-
- ); -} - -interface MilestonesPanelProps { - milestones: MilestoneItem[]; -} - -export function MilestonesPanel({ milestones }: MilestonesPanelProps) { - return ( -
-
-

Upcoming Milestones

- - All projects - -
- {milestones.length === 0 ? ( -

No open milestones

- ) : ( -
    - {milestones.map((m) => ( -
  • -
    -

    {m.title}

    -

    - {m.projectName} -

    -
    -
    - - {m.overdue - ? `${Math.abs(m.daysUntil)}d overdue` - : m.daysUntil === 0 - ? "Today" - : `${m.daysUntil}d`} - -

    - {formatShortDate(m.dueDate)} -

    -
    -
  • - ))} -
- )} -
- ); -} diff --git a/apps/delta-command/src/components/dashboard/UtilizationChart.tsx b/apps/delta-command/src/components/dashboard/UtilizationChart.tsx deleted file mode 100644 index 0f7ead2..0000000 --- a/apps/delta-command/src/components/dashboard/UtilizationChart.tsx +++ /dev/null @@ -1,90 +0,0 @@ -"use client"; - -import { - BarChart, - Bar, - XAxis, - YAxis, - CartesianGrid, - Tooltip, - ResponsiveContainer, - ReferenceLine, - Cell, -} from "recharts"; -import type { Engineer } from "@/core/types"; -import { CHART_GRID, CHART_TICK, CHART_TOOLTIP_STYLE } from "@/core/utils"; - -interface UtilizationChartProps { - engineers: Engineer[]; - maxVisible?: number; -} - -function getBarColor(utilization: number): string { - if (utilization >= 100) return "#EF4444"; - if (utilization >= 85) return "#F59E0B"; - if (utilization >= 60) return "#3B82F6"; - return "#10B981"; -} - -const CHART_GRID_COLOR = CHART_GRID; -const CHART_TICK_COLOR = CHART_TICK; - -export function UtilizationChart({ engineers, maxVisible = 30 }: UtilizationChartProps) { - const data = [...engineers] - .sort((a, b) => b.utilization - a.utilization) - .slice(0, maxVisible) - .map((e) => ({ - name: e.name.split(" ")[0], - utilization: e.utilization, - fill: getBarColor(e.utilization), - })); - - const chartHeight = Math.min(520, Math.max(256, data.length * 26)); - - return ( -
-

Team Utilization

-

- Current allocation across the delta engineering team - {engineers.length > maxVisible && ( - · top {maxVisible} by utilization - )} -

-
-
- - - - `${v}%`} - /> - - [`${value}%`, "Utilization"]} - /> - - - {data.map((entry, index) => ( - - ))} - - - -
-
-
- ); -} diff --git a/apps/delta-command/src/components/layout/Header.tsx b/apps/delta-command/src/components/layout/Header.tsx deleted file mode 100644 index c569ea4..0000000 --- a/apps/delta-command/src/components/layout/Header.tsx +++ /dev/null @@ -1,48 +0,0 @@ -"use client"; - -import { Bell, Search } from "lucide-react"; -import { format } from "date-fns"; - -interface HeaderProps { - title: string; - subtitle?: string; -} - -export function Header({ title, subtitle }: HeaderProps) { - const today = format(new Date(), "MMM d, yyyy"); - - return ( -
-
-

{title}

- {subtitle &&

{subtitle}

} -
- -
- - {today} - - -
- - -
- - - -
- NF -
-
-
- ); -} diff --git a/apps/delta-command/src/components/layout/Sidebar.tsx b/apps/delta-command/src/components/layout/Sidebar.tsx deleted file mode 100644 index 0e63768..0000000 --- a/apps/delta-command/src/components/layout/Sidebar.tsx +++ /dev/null @@ -1,71 +0,0 @@ -"use client"; - -import Link from "next/link"; -import { usePathname } from "next/navigation"; -import { - LayoutDashboard, - Target, - Users, - FolderKanban, - Zap, -} from "lucide-react"; -import { cn } from "@/core/utils"; - -const navigation = [ - { name: "Dashboard", href: "/dashboard", icon: LayoutDashboard }, - { name: "Opportunities", href: "/opportunities", icon: Target }, - { name: "Team", href: "/team", icon: Users }, - { name: "Projects", href: "/projects", icon: FolderKanban }, -]; - -export function Sidebar() { - const pathname = usePathname(); - - return ( - - ); -} diff --git a/apps/delta-command/src/components/opportunities/PipelineBoard.tsx b/apps/delta-command/src/components/opportunities/PipelineBoard.tsx deleted file mode 100644 index 6895954..0000000 --- a/apps/delta-command/src/components/opportunities/PipelineBoard.tsx +++ /dev/null @@ -1,157 +0,0 @@ -"use client"; - -import type { Opportunity, OpportunityStage } from "@/core/types"; -import { OPPORTUNITY_STAGES } from "@/core/types"; -import { formatCurrency, formatShortDate, cn } from "@/core/utils"; -import { Building2, Calendar, User } from "lucide-react"; - -interface OpportunityCardProps { - opportunity: Opportunity; - onStageChange?: (id: string, stage: OpportunityStage) => void; - compact?: boolean; -} - -export function OpportunityCard({ - opportunity, - onStageChange, - compact = false, -}: OpportunityCardProps) { - const weightedValue = opportunity.value * (opportunity.probability / 100); - - return ( -
-
-

- {opportunity.title} -

- - {formatCurrency(opportunity.value)} - -
- -
- - {opportunity.client} -
- - {!compact && ( -

- {opportunity.description} -

- )} - -
- {opportunity.tags.map((tag) => ( - - {tag} - - ))} -
- -
-
- Probability - - {opportunity.probability}% - -
-
-
-
-

- Weighted: {formatCurrency(weightedValue)} -

-
- -
-
- - {opportunity.owner.split(" ")[0]} -
-
- - {formatShortDate(opportunity.expectedClose)} -
-
- - {onStageChange && ( -
- -
- )} -
- ); -} - -interface PipelineBoardProps { - opportunities: Opportunity[]; - onStageChange?: (id: string, stage: OpportunityStage) => void; -} - -export function PipelineBoard({ opportunities, onStageChange }: PipelineBoardProps) { - const activeStages = OPPORTUNITY_STAGES.filter( - (s) => !["won", "lost"].includes(s.id) - ); - - return ( -
- {activeStages.map((stage) => { - const stageOpps = opportunities.filter((o) => o.stage === stage.id); - const stageValue = stageOpps.reduce((sum, o) => sum + o.value, 0); - - return ( -
-
-
-
-

- {stage.label} -

- - {stageOpps.length} - -
- - {formatCurrency(stageValue)} - -
- -
- {stageOpps.map((opp) => ( - - ))} - {stageOpps.length === 0 && ( -
-

No opportunities

-
- )} -
-
- ); - })} -
- ); -} diff --git a/apps/delta-command/src/components/projects/ProjectCard.tsx b/apps/delta-command/src/components/projects/ProjectCard.tsx deleted file mode 100644 index 6244795..0000000 --- a/apps/delta-command/src/components/projects/ProjectCard.tsx +++ /dev/null @@ -1,160 +0,0 @@ -import type { Project } from "@/core/types"; -import { PROJECT_STATUSES } from "@/core/types"; -import { - cn, - formatCurrency, - formatDate, - daysUntil, - getStatusBadgeColor, -} from "@/core/utils"; -import { Calendar, Users, AlertTriangle, CheckCircle2, Circle } from "lucide-react"; - -interface ProjectCardProps { - project: Project; - engineerNames?: Record; - onStatusChange?: (id: string, status: Project["status"]) => void; -} - -export function ProjectCard({ - project, - engineerNames = {}, - onStatusChange, -}: ProjectCardProps) { - const statusConfig = PROJECT_STATUSES.find((s) => s.id === project.status); - const daysLeft = daysUntil(project.endDate); - const budgetUsed = Math.round((project.spent / project.budget) * 100); - const teamNames = project.team.map((id) => engineerNames[id] ?? id); - const completedMilestones = project.milestones.filter((m) => m.completed).length; - - return ( -
-
-
-
-

{project.name}

-

{project.client}

-
- - {statusConfig?.label ?? project.status} - -
-
- -
-

{project.description}

- -
-
- Progress - {project.progress}% -
-
-
-
-
- -
-
-

Budget

-

- {formatCurrency(project.spent)} / {formatCurrency(project.budget)} -

-

90 ? "text-error" : "text-surface-on-variant/70" - )} - > - {budgetUsed}% utilized -

-
-
-

Timeline

-
- - {daysLeft > 0 ? `${daysLeft}d remaining` : "Past due"} -
-

- Due {formatDate(project.endDate)} -

-
-
- -
- - Lead: - - {project.leadEngineer} - - | - - {teamNames.length} team members - -
- - {onStatusChange && ( -
- - -
- )} - - {project.status === "at_risk" && ( -
- - Project flagged as at-risk — review milestones and budget -
- )} - -
-

- Milestones ({completedMilestones}/{project.milestones.length}) -

-
    - {project.milestones.map((milestone) => ( -
  • - {milestone.completed ? ( - - ) : ( - - )} - - {milestone.title} - - - {formatDate(milestone.dueDate)} - -
  • - ))} -
-
-
-
- ); -} diff --git a/apps/delta-command/src/components/projects/ProjectsPageClient.tsx b/apps/delta-command/src/components/projects/ProjectsPageClient.tsx deleted file mode 100644 index e63e81d..0000000 --- a/apps/delta-command/src/components/projects/ProjectsPageClient.tsx +++ /dev/null @@ -1,156 +0,0 @@ -"use client"; - -import { useCallback, useEffect, useState } from "react"; -import { Header } from "@/components/layout/Header"; -import { ProjectCard } from "@/components/projects/ProjectCard"; -import type { Engineer, Project, ProjectStatus } from "@/core/types"; -import { PROJECT_STATUSES } from "@/core/types"; -import { updateProjectStatus } from "@/core/api"; -import { formatCurrency, cn } from "@/core/utils"; -import { FolderKanban, AlertTriangle, CheckCircle2, PauseCircle } from "lucide-react"; - -export function ProjectsPageClient() { - const [projects, setProjects] = useState([]); - const [engineers, setEngineers] = useState([]); - const [loading, setLoading] = useState(true); - - const fetchData = useCallback(async () => { - const [projectsRes, engineersRes] = await Promise.all([ - fetch("/api/projects"), - fetch("/api/engineers"), - ]); - setProjects(await projectsRes.json()); - setEngineers(await engineersRes.json()); - setLoading(false); - }, []); - - useEffect(() => { - void fetchData(); - }, [fetchData]); - - const handleStatusChange = async (id: string, status: ProjectStatus) => { - await updateProjectStatus(id, status); - await fetchData(); - }; - - if (loading) { - return ( -
-
-
-
-
-
- ); - } - - const engineerNames = Object.fromEntries(engineers.map((e) => [e.id, e.name])); - const activeProjects = projects.filter((p) => p.status === "active"); - const atRiskProjects = projects.filter((p) => p.status === "at_risk"); - const planningProjects = projects.filter((p) => p.status === "planning"); - const totalBudget = projects.reduce((sum, p) => sum + p.budget, 0); - const totalSpent = projects.reduce((sum, p) => sum + p.spent, 0); - - const statusIcons: Record = { - active: FolderKanban, - at_risk: AlertTriangle, - planning: PauseCircle, - completed: CheckCircle2, - on_hold: PauseCircle, - }; - - const renderSection = (title: string, items: Project[]) => - items.length > 0 ? ( -
-

{title}

-
- {items.map((project) => ( - - ))} -
-
- ) : null; - - return ( -
-
- -
-
-
-

Total Projects

-

{projects.length}

-
-
-

In Delivery

-

- {activeProjects.length + atRiskProjects.length} -

-
-
-

Total Budget

-

{formatCurrency(totalBudget)}

-
-
-

Spent to Date

-

- {formatCurrency(totalSpent)} -

-

- {Math.round((totalSpent / totalBudget) * 100)}% of total budget -

-
-
- -
- {PROJECT_STATUSES.map((status) => { - const count = projects.filter((p) => p.status === status.id).length; - const Icon = statusIcons[status.id] ?? FolderKanban; - return ( -
- - - {status.label} - - {count} - -
- ); - })} -
- - {atRiskProjects.length > 0 && ( -
-

- - At Risk -

-
- {atRiskProjects.map((project) => ( - - ))} -
-
- )} - {renderSection("Active Delivery", activeProjects)} - {renderSection("In Planning", planningProjects)} -
-
- ); -} diff --git a/apps/delta-command/src/components/team/EngineerCard.tsx b/apps/delta-command/src/components/team/EngineerCard.tsx deleted file mode 100644 index b518fb4..0000000 --- a/apps/delta-command/src/components/team/EngineerCard.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import type { Engineer } from "@/core/types"; -import { - cn, - getInitials, - getUtilizationColor, - getUtilizationTextColor, - getStatusBadgeColor, -} from "@/core/utils"; -import { Mail, Briefcase } from "lucide-react"; - -interface EngineerCardProps { - engineer: Engineer; - projectNames?: Record; -} - -export function EngineerCard({ engineer, projectNames = {} }: EngineerCardProps) { - const projects = engineer.currentProjects.map( - (id) => projectNames[id] ?? id - ); - - return ( -
-
-
- {getInitials(engineer.name)} -
-
-

{engineer.name}

-

{engineer.role}

-
- - {engineer.email} -
-
- - {engineer.status} - -
- -
-
- Utilization - - {engineer.utilization}% - -
-
-
-
- {engineer.utilization > 100 && ( -

- {engineer.utilization - 100}% over capacity -

- )} -
- -
- {engineer.skills.map((skill) => ( - - {skill} - - ))} -
- -
-
- - Current Projects ({projects.length}) -
- {projects.length > 0 ? ( -
    - {projects.map((name) => ( -
  • - {name} -
  • - ))} -
- ) : ( -

Available for assignment

- )} -
-
- ); -} diff --git a/apps/delta-command/src/components/team/TeamFilters.tsx b/apps/delta-command/src/components/team/TeamFilters.tsx deleted file mode 100644 index c494a19..0000000 --- a/apps/delta-command/src/components/team/TeamFilters.tsx +++ /dev/null @@ -1,80 +0,0 @@ -"use client"; - -import { Search } from "lucide-react"; -import type { EngineerStatus } from "@/core/types"; - -export interface TeamFilterState { - search: string; - status: EngineerStatus | "all"; -} - -interface TeamFiltersProps { - filters: TeamFilterState; - onChange: (filters: TeamFilterState) => void; - resultCount: number; - totalCount: number; -} - -const STATUS_OPTIONS: { value: TeamFilterState["status"]; label: string }[] = [ - { value: "all", label: "All statuses" }, - { value: "available", label: "Available" }, - { value: "allocated", label: "Allocated" }, - { value: "overallocated", label: "Overallocated" }, -]; - -export function TeamFilters({ filters, onChange, resultCount, totalCount }: TeamFiltersProps) { - return ( -
-
- - onChange({ ...filters, search: e.target.value })} - className="text-field-outlined h-10 w-full pl-9 text-sm" - /> -
- - - {resultCount} of {totalCount} engineers - -
- ); -} - -export function filterEngineers( - engineers: T[], - filters: TeamFilterState -): T[] { - const query = filters.search.trim().toLowerCase(); - return engineers.filter((engineer) => { - const matchesStatus = filters.status === "all" || engineer.status === filters.status; - if (!matchesStatus) return false; - if (!query) return true; - return ( - engineer.name.toLowerCase().includes(query) || - engineer.role.toLowerCase().includes(query) || - engineer.email.toLowerCase().includes(query) - ); - }); -} - -export function filterTimelineRows( - rows: T[], - engineerIds: Set -): T[] { - return rows.filter((row) => engineerIds.has(row.engineerId)); -} diff --git a/apps/delta-command/src/components/team/TeamPageClient.tsx b/apps/delta-command/src/components/team/TeamPageClient.tsx deleted file mode 100644 index 59835a8..0000000 --- a/apps/delta-command/src/components/team/TeamPageClient.tsx +++ /dev/null @@ -1,216 +0,0 @@ -"use client"; - -import { useMemo, useState } from "react"; -import { Header } from "@/components/layout/Header"; -import { EngineerCard } from "@/components/team/EngineerCard"; -import { TeamFilters, filterEngineers } from "@/components/team/TeamFilters"; -import type { TeamFilterState } from "@/components/team/TeamFilters"; -import { UtilizationTimelineView } from "@/components/team/UtilizationTimeline"; -import type { Engineer, Project, UtilizationTimeline } from "@/core/types"; -import { formatNameList } from "@/core/team-utils"; -import { cn, getUtilizationColor } from "@/core/utils"; -import { Users, AlertTriangle, CheckCircle, Clock, CalendarRange, LayoutGrid } from "lucide-react"; - -type TeamView = "timeline" | "overview"; - -interface TeamPageClientProps { - engineers: Engineer[]; - projects: Project[]; - timeline: UtilizationTimeline; -} - -export function TeamPageClient({ - engineers, - projects, - timeline, -}: TeamPageClientProps) { - const [view, setView] = useState("timeline"); - const [filters, setFilters] = useState({ search: "", status: "all" }); - - const projectNames = Object.fromEntries(projects.map((p) => [p.id, p.name])); - const filteredEngineers = useMemo( - () => filterEngineers(engineers, filters), - [engineers, filters] - ); - const filteredEngineerIds = useMemo( - () => new Set(filteredEngineers.map((engineer) => engineer.id)), - [filteredEngineers] - ); - - const overallocated = engineers.filter((e) => e.status === "overallocated"); - const available = engineers.filter((e) => e.utilization < 70); - const avgUtil = Math.round( - engineers.reduce((sum, e) => sum + e.utilization, 0) / engineers.length - ); - const sortedEngineers = [...filteredEngineers].sort((a, b) => b.utilization - a.utilization); - - return ( -
-
- -
-
-
- - -
-

- {view === "timeline" - ? "Click any week cell to update utilization — changes save to data.json" - : "Current-week snapshot and team member details"} -

-
- - - -
-
-
-
- -
-
-

{engineers.length}

-

Team Members

-
-
-
-
-
-
- -
-
-

{avgUtil}%

-

This Week Avg

-
-
-
-
-
-
- -
-
-

{available.length}

-

Available Capacity

-
-
-
-
-
-
- -
-
-

{overallocated.length}

-

Overallocated

-
-
-
-
- - {overallocated.length > 0 && ( -
- -

- - {formatNameList(overallocated.map((e) => e.name.split(" ")[0]))} - {" "} - {overallocated.length === 1 ? "is" : "are"} overallocated this week. - Adjust the timeline to plan redistribution. -

-
- )} - - {view === "timeline" ? ( - - ) : ( - <> -
-

Current Week Capacity

-
- {sortedEngineers.map((engineer) => ( -
- - {engineer.name.split(" ")[0]} - -
-
-
- {engineer.utilization >= 30 && `${engineer.utilization}%`} -
-
-
- - {engineer.currentProjects.length} proj - -
- ))} - {sortedEngineers.length === 0 && ( -

No engineers match your filters.

- )} -
-
- -
-

Team Members

-
- {sortedEngineers.map((engineer) => ( - - ))} -
- {sortedEngineers.length === 0 && ( -

No engineers match your filters.

- )} -
- - )} -
-
- ); -} diff --git a/apps/delta-command/src/components/team/UtilizationTimeline.tsx b/apps/delta-command/src/components/team/UtilizationTimeline.tsx deleted file mode 100644 index 43c7a12..0000000 --- a/apps/delta-command/src/components/team/UtilizationTimeline.tsx +++ /dev/null @@ -1,262 +0,0 @@ -"use client"; - -import { useCallback, useState } from "react"; -import type { UtilizationTimeline } from "@/core/types"; -import { updateTimelineCell } from "@/core/api"; -import { - cn, - getUtilizationCellStyle, - getUtilizationColor, - getUtilizationTextColor, -} from "@/core/utils"; -import { CalendarRange, Pencil, Check, X } from "lucide-react"; - -interface UtilizationTimelineProps { - initialData: UtilizationTimeline; - visibleEngineerIds?: Set; - totalEngineers?: number; -} - -export function UtilizationTimelineView({ - initialData, - visibleEngineerIds, - totalEngineers, -}: UtilizationTimelineProps) { - const [timeline, setTimeline] = useState(initialData); - const [editing, setEditing] = useState<{ - engineerId: string; - weekStart: string; - } | null>(null); - const [draftValue, setDraftValue] = useState(""); - const [saving, setSaving] = useState(false); - - const startEdit = (engineerId: string, weekStart: string, value: number) => { - setEditing({ engineerId, weekStart }); - setDraftValue(String(value)); - }; - - const cancelEdit = () => { - setEditing(null); - setDraftValue(""); - }; - - const saveEdit = useCallback(async () => { - if (!editing) return; - const utilization = Math.max(0, Math.min(150, parseInt(draftValue, 10) || 0)); - setSaving(true); - try { - const updated = await updateTimelineCell( - editing.engineerId, - editing.weekStart, - utilization - ); - setTimeline(updated); - setEditing(null); - setDraftValue(""); - } finally { - setSaving(false); - } - }, [draftValue, editing]); - - const rowAverage = (cells: { utilization: number }[]) => - Math.round(cells.reduce((sum, c) => sum + c.utilization, 0) / cells.length); - - const visibleRows = visibleEngineerIds - ? timeline.rows.filter((row) => visibleEngineerIds.has(row.engineerId)) - : timeline.rows; - - return ( -
-
-
-

- - Utilization Timeline -

-

- Weekly capacity by engineer — click any cell to edit allocation - {totalEngineers !== undefined && ( - - · showing {visibleRows.length} of {totalEngineers} - - )} -

-
-
- - <60% - - - 60–84% - - - 85–99% - - - 100%+ - -
-
- -
- - - - - {timeline.weeks.map((week) => ( - - ))} - - - - - {visibleRows.map((row) => ( - - - {row.cells.map((cell) => { - const isEditing = - editing?.engineerId === row.engineerId && - editing.weekStart === cell.weekStart; - const weekMeta = timeline.weeks.find( - (w) => w.weekStart === cell.weekStart - ); - - return ( - - ); - })} - - - ))} - - - - - {timeline.weeks.map((week, weekIndex) => { - const values = visibleRows.map((row) => row.cells[weekIndex]?.utilization ?? 0); - const avg = Math.round( - values.reduce((sum, v) => sum + v, 0) / (values.length || 1) - ); - return ( - - ); - })} - - -
- Engineer - -
{week.label}
- {week.isCurrent && ( -
- This week -
- )} -
- Avg -
-

{row.name}

-

{row.role}

-
- {isEditing ? ( -
- setDraftValue(e.target.value)} - onKeyDown={(e) => { - if (e.key === "Enter") void saveEdit(); - if (e.key === "Escape") cancelEdit(); - }} - className="text-field-outlined h-9 w-14 px-1 text-center text-sm" - autoFocus - disabled={saving} - /> - - -
- ) : ( - - )} -
- - {rowAverage(row.cells)}% - -
- Team average - -
-
-
-

{avg}%

-
-
-
-
- ); -} diff --git a/apps/delta-command/src/core/api.ts b/apps/delta-command/src/core/api.ts deleted file mode 100644 index 8db6f1f..0000000 --- a/apps/delta-command/src/core/api.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** API client for Delta Command Python backend. */ - -import type { - DashboardMetrics, - Database, - Engineer, - Opportunity, - OpportunityStage, - Project, - ProjectStatus, - UtilizationTimeline, -} from "./types"; - -const API_BASE = process.env.DELTA_API_URL ?? "http://127.0.0.1:8000"; - -async function apiFetch(path: string, init?: RequestInit): Promise { - const response = await fetch(`${API_BASE}${path}`, { - ...init, - cache: "no-store", - headers: { - "Content-Type": "application/json", - ...init?.headers, - }, - }); - - if (!response.ok) { - throw new Error(`API request failed: ${response.status} ${response.statusText}`); - } - - return response.json() as Promise; -} - -export async function getDashboardMetrics(): Promise { - return apiFetch("/api/dashboard"); -} - -export async function getOpportunities(): Promise { - return apiFetch("/api/opportunities"); -} - -export async function getProjects(): Promise { - return apiFetch("/api/projects"); -} - -export async function getEngineers(): Promise { - return apiFetch("/api/engineers"); -} - -export async function getUtilizationTimeline(): Promise { - return apiFetch("/api/utilization/timeline"); -} - -export async function updateTimelineCell( - engineerId: string, - weekStart: string, - utilization: number, - note?: string -): Promise { - return apiFetch("/api/utilization/timeline", { - method: "PATCH", - body: JSON.stringify({ engineerId, weekStart, utilization, note }), - }); -} - -export async function getDatabase(): Promise { - const [engineers, opportunities, projects, dashboard] = await Promise.all([ - getEngineers(), - getOpportunities(), - getProjects(), - getDashboardMetrics(), - ]); - - return { - engineers, - opportunities, - projects, - lastUpdated: dashboard.lastUpdated, - }; -} - -export async function updateOpportunityStage( - id: string, - stage: OpportunityStage -): Promise { - return apiFetch("/api/opportunities", { - method: "PATCH", - body: JSON.stringify({ id, stage }), - }); -} - -export async function updateProjectStatus( - id: string, - status: ProjectStatus -): Promise { - return apiFetch("/api/projects", { - method: "PATCH", - body: JSON.stringify({ id, status }), - }); -} diff --git a/apps/delta-command/src/core/dashboard-analytics.ts b/apps/delta-command/src/core/dashboard-analytics.ts deleted file mode 100644 index 7765290..0000000 --- a/apps/delta-command/src/core/dashboard-analytics.ts +++ /dev/null @@ -1,262 +0,0 @@ -import type { Engineer, Opportunity, Project } from "./types"; -import { daysUntil } from "./utils"; - -export type ActionSeverity = "critical" | "warning" | "info"; - -export interface ActionItem { - id: string; - severity: ActionSeverity; - title: string; - detail: string; - href: string; -} - -export interface MilestoneItem { - id: string; - title: string; - projectName: string; - dueDate: string; - daysUntil: number; - overdue: boolean; -} - -export interface PipelineInsight { - inProposal: number; - proposalValue: number; - lateStage: number; - lateStageValue: number; - closingWithin30Days: number; - closingValue30Days: number; - inNegotiation: number; - negotiationValue: number; - avgDealSize: number; - avgProbability: number; -} - -export interface DeliveryInsight { - totalBudget: number; - totalSpent: number; - burnPercent: number; - activeCount: number; - planningCount: number; - atRiskCount: number; - milestonesDue14Days: number; - overdueMilestones: number; - projectsEnding30Days: number; -} - -export interface TeamInsight { - overallocated: Engineer[]; - available: Engineer[]; - benchCapacityPercent: number; - unassigned: Engineer[]; -} - -export interface DashboardInsights { - actions: ActionItem[]; - milestones: MilestoneItem[]; - pipeline: PipelineInsight; - delivery: DeliveryInsight; - team: TeamInsight; -} - -function isActiveOpportunity(o: Opportunity): boolean { - return !["won", "lost"].includes(o.stage); -} - -export function buildDashboardInsights( - engineers: Engineer[], - opportunities: Opportunity[], - projects: Project[] -): DashboardInsights { - const activeOpps = opportunities.filter(isActiveOpportunity); - const inProposal = activeOpps.filter((o) => o.stage === "proposal"); - const inNegotiation = activeOpps.filter((o) => o.stage === "negotiation"); - const lateStage = activeOpps.filter((o) => - ["proposal", "negotiation"].includes(o.stage) - ); - const closingSoon = activeOpps.filter((o) => { - const days = daysUntil(o.expectedClose); - return days >= 0 && days <= 30; - }); - - const activeProjects = projects.filter( - (p) => p.status === "active" || p.status === "at_risk" - ); - const totalBudget = activeProjects.reduce((s, p) => s + p.budget, 0); - const totalSpent = activeProjects.reduce((s, p) => s + p.spent, 0); - - const allMilestones: MilestoneItem[] = projects.flatMap((project) => - project.milestones - .filter((m) => !m.completed) - .map((m) => { - const d = daysUntil(m.dueDate); - return { - id: m.id, - title: m.title, - projectName: project.name, - dueDate: m.dueDate, - daysUntil: d, - overdue: d < 0, - }; - }) - ); - - const sortedMilestones = [...allMilestones].sort( - (a, b) => new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime() - ); - - const overdueMilestones = sortedMilestones.filter((m) => m.overdue); - const milestonesDue14 = sortedMilestones.filter( - (m) => !m.overdue && m.daysUntil <= 14 - ); - - const overallocated = engineers.filter((e) => e.status === "overallocated"); - const available = engineers.filter((e) => e.utilization < 70); - const unassigned = engineers.filter((e) => e.currentProjects.length === 0); - - const benchCapacity = engineers.reduce( - (sum, e) => sum + Math.max(0, 100 - e.utilization), - 0 - ); - const benchCapacityPercent = - engineers.length > 0 - ? Math.round(benchCapacity / engineers.length) - : 0; - - const actions: ActionItem[] = []; - - for (const project of projects.filter((p) => p.status === "at_risk")) { - actions.push({ - id: `risk-${project.id}`, - severity: "critical", - title: `${project.name} is at risk`, - detail: `${project.progress}% complete · ${Math.round((project.spent / project.budget) * 100)}% budget used`, - href: "/projects", - }); - } - - for (const eng of overallocated) { - actions.push({ - id: `over-${eng.id}`, - severity: "critical", - title: `${eng.name} is overallocated`, - detail: `${eng.utilization}% utilization across ${eng.currentProjects.length} projects`, - href: "/team", - }); - } - - for (const m of overdueMilestones) { - actions.push({ - id: `ms-over-${m.id}`, - severity: "critical", - title: `Overdue milestone: ${m.title}`, - detail: `${m.projectName} · due ${m.dueDate}`, - href: "/projects", - }); - } - - for (const opp of activeOpps.filter((o) => daysUntil(o.expectedClose) <= 7 && daysUntil(o.expectedClose) >= 0)) { - actions.push({ - id: `close-${opp.id}`, - severity: "warning", - title: `Close imminent: ${opp.client}`, - detail: `${formatCurrencyShort(opp.value)} · ${opp.probability}% probability · ${daysUntil(opp.expectedClose)}d left`, - href: "/opportunities", - }); - } - - for (const m of milestonesDue14) { - actions.push({ - id: `ms-soon-${m.id}`, - severity: "warning", - title: `Milestone due: ${m.title}`, - detail: `${m.projectName} · in ${m.daysUntil} day${m.daysUntil === 1 ? "" : "s"}`, - href: "/projects", - }); - } - - for (const project of activeProjects.filter( - (p) => p.spent / p.budget >= 0.9 - )) { - actions.push({ - id: `budget-${project.id}`, - severity: "warning", - title: `Budget nearly exhausted: ${project.name}`, - detail: `${Math.round((project.spent / project.budget) * 100)}% of ${formatCurrencyShort(project.budget)} spent`, - href: "/projects", - }); - } - - if (unassigned.length > 0) { - actions.push({ - id: "bench-available", - severity: "info", - title: `${unassigned.length} engineer${unassigned.length > 1 ? "s" : ""} available for assignment`, - detail: unassigned.map((e) => e.name.split(" ")[0]).join(", "), - href: "/team", - }); - } - - const severityOrder: Record = { - critical: 0, - warning: 1, - info: 2, - }; - actions.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]); - - return { - actions, - milestones: sortedMilestones.slice(0, 8), - pipeline: { - inProposal: inProposal.length, - proposalValue: inProposal.reduce((s, o) => s + o.value, 0), - lateStage: lateStage.length, - lateStageValue: lateStage.reduce((s, o) => s + o.value, 0), - closingWithin30Days: closingSoon.length, - closingValue30Days: closingSoon.reduce((s, o) => s + o.value, 0), - inNegotiation: inNegotiation.length, - negotiationValue: inNegotiation.reduce((s, o) => s + o.value, 0), - avgDealSize: - activeOpps.length > 0 - ? Math.round( - activeOpps.reduce((s, o) => s + o.value, 0) / activeOpps.length - ) - : 0, - avgProbability: - activeOpps.length > 0 - ? Math.round( - activeOpps.reduce((s, o) => s + o.probability, 0) / - activeOpps.length - ) - : 0, - }, - delivery: { - totalBudget, - totalSpent, - burnPercent: - totalBudget > 0 ? Math.round((totalSpent / totalBudget) * 100) : 0, - activeCount: projects.filter((p) => p.status === "active").length, - planningCount: projects.filter((p) => p.status === "planning").length, - atRiskCount: projects.filter((p) => p.status === "at_risk").length, - milestonesDue14Days: milestonesDue14.length, - overdueMilestones: overdueMilestones.length, - projectsEnding30Days: projects.filter((p) => { - const d = daysUntil(p.endDate); - return d >= 0 && d <= 30 && p.status !== "completed"; - }).length, - }, - team: { - overallocated, - available, - benchCapacityPercent, - unassigned, - }, - }; -} - -function formatCurrencyShort(value: number): string { - if (value >= 1_000_000) return `$${(value / 1_000_000).toFixed(1)}M`; - if (value >= 1_000) return `$${(value / 1_000).toFixed(0)}K`; - return `$${value.toLocaleString()}`; -} diff --git a/apps/delta-command/src/core/team-utils.ts b/apps/delta-command/src/core/team-utils.ts deleted file mode 100644 index ed8e477..0000000 --- a/apps/delta-command/src/core/team-utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function formatNameList(names: string[], limit = 5): string { - if (names.length <= limit) return names.join(", "); - const shown = names.slice(0, limit).join(", "); - return `${shown}, and ${names.length - limit} more`; -} diff --git a/apps/delta-command/src/core/types.ts b/apps/delta-command/src/core/types.ts deleted file mode 100644 index 4ef7cbe..0000000 --- a/apps/delta-command/src/core/types.ts +++ /dev/null @@ -1,144 +0,0 @@ -export type OpportunityStage = - | "prospect" - | "qualified" - | "proposal" - | "negotiation" - | "won" - | "lost"; - -export type ProjectStatus = - | "planning" - | "active" - | "on_hold" - | "completed" - | "at_risk"; - -export type EngineerStatus = "available" | "allocated" | "overallocated"; - -export interface UtilizationWeek { - weekStart: string; - utilization: number; - note?: string; -} - -export interface Engineer { - id: string; - name: string; - role: string; - email: string; - capacity: number; - utilization: number; - status: EngineerStatus; - skills: string[]; - currentProjects: string[]; - utilizationTimeline?: UtilizationWeek[]; - avatar?: string; -} - -export interface UtilizationTimelineWeek { - weekStart: string; - label: string; - isCurrent: boolean; -} - -export interface UtilizationTimelineCell { - weekStart: string; - utilization: number; - note?: string; -} - -export interface UtilizationTimelineRow { - engineerId: string; - name: string; - role: string; - cells: UtilizationTimelineCell[]; -} - -export interface UtilizationTimeline { - weeks: UtilizationTimelineWeek[]; - rows: UtilizationTimelineRow[]; -} - -export interface Opportunity { - id: string; - title: string; - client: string; - stage: OpportunityStage; - value: number; - probability: number; - owner: string; - expectedClose: string; - description: string; - tags: string[]; - createdAt: string; - updatedAt: string; -} - -export interface Project { - id: string; - name: string; - client: string; - status: ProjectStatus; - progress: number; - startDate: string; - endDate: string; - budget: number; - spent: number; - leadEngineer: string; - team: string[]; - description: string; - milestones: Milestone[]; - opportunityId?: string; -} - -export interface Milestone { - id: string; - title: string; - dueDate: string; - completed: boolean; -} - -export interface Database { - engineers: Engineer[]; - opportunities: Opportunity[]; - projects: Project[]; - lastUpdated: string; -} - -export interface DashboardMetrics { - pipelineValue: number; - totalPipeline: number; - activeOpportunities: number; - activeProjects: number; - atRiskProjects: number; - avgUtilization: number; - availableCapacity: number; - wonThisQuarter: number; - teamSize: number; - lastUpdated: string; -} - -export const OPPORTUNITY_STAGES: { - id: OpportunityStage; - label: string; - color: string; -}[] = [ - { id: "prospect", label: "Prospect", color: "bg-outline" }, - { id: "qualified", label: "Qualified", color: "bg-primary" }, - { id: "proposal", label: "Proposal", color: "bg-tertiary" }, - { id: "negotiation", label: "Negotiation", color: "bg-secondary" }, - { id: "won", label: "Won", color: "bg-primary" }, - { id: "lost", label: "Lost", color: "bg-error" }, -]; - -export const PROJECT_STATUSES: { - id: ProjectStatus; - label: string; - color: string; -}[] = [ - { id: "planning", label: "Planning", color: "bg-outline" }, - { id: "active", label: "Active", color: "bg-primary" }, - { id: "on_hold", label: "On Hold", color: "bg-tertiary" }, - { id: "at_risk", label: "At Risk", color: "bg-error" }, - { id: "completed", label: "Completed", color: "bg-secondary" }, -]; diff --git a/apps/delta-command/src/core/utils.ts b/apps/delta-command/src/core/utils.ts deleted file mode 100644 index 2d3bd48..0000000 --- a/apps/delta-command/src/core/utils.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; -import { format, parseISO, differenceInDays } from "date-fns"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} - -export function formatCurrency(value: number): string { - if (value >= 1_000_000) { - return `$${(value / 1_000_000).toFixed(1)}M`; - } - if (value >= 1_000) { - return `$${(value / 1_000).toFixed(0)}K`; - } - return `$${value.toLocaleString()}`; -} - -export function formatDate(dateStr: string): string { - return format(parseISO(dateStr), "MMM d, yyyy"); -} - -export function formatShortDate(dateStr: string): string { - return format(parseISO(dateStr), "MMM d"); -} - -export function daysUntil(dateStr: string): number { - return differenceInDays(parseISO(dateStr), new Date()); -} - -export function getInitials(name: string): string { - return name - .split(" ") - .map((n) => n[0]) - .join("") - .toUpperCase() - .slice(0, 2); -} - -export function getUtilizationColor(utilization: number): string { - if (utilization >= 100) return "bg-red-500"; - if (utilization >= 85) return "bg-amber-500"; - if (utilization >= 60) return "bg-accent"; - return "bg-emerald-500"; -} - -export function getUtilizationTextColor(utilization: number): string { - if (utilization >= 100) return "text-red-400"; - if (utilization >= 85) return "text-amber-400"; - if (utilization >= 60) return "text-accent-foreground"; - return "text-emerald-400"; -} - -export function getUtilizationCellStyle(utilization: number): string { - if (utilization >= 100) return "bg-red-500/15 text-red-300 ring-red-500/30"; - if (utilization >= 85) return "bg-amber-500/15 text-amber-300 ring-amber-500/30"; - if (utilization >= 60) return "bg-blue-500/15 text-blue-300 ring-blue-500/30"; - return "bg-emerald-500/15 text-emerald-300 ring-emerald-500/30"; -} - -export function getStatusBadgeColor(status: string): string { - const colors: Record = { - available: "bg-emerald-500/15 text-emerald-300 ring-1 ring-inset ring-emerald-500/30", - allocated: "bg-blue-500/15 text-blue-300 ring-1 ring-inset ring-blue-500/30", - overallocated: "bg-red-500/15 text-red-300 ring-1 ring-inset ring-red-500/30", - planning: "bg-zinc-500/15 text-zinc-300 ring-1 ring-inset ring-zinc-500/30", - active: "bg-blue-500/15 text-blue-300 ring-1 ring-inset ring-blue-500/30", - on_hold: "bg-amber-500/15 text-amber-300 ring-1 ring-inset ring-amber-500/30", - at_risk: "bg-red-500/15 text-red-300 ring-1 ring-inset ring-red-500/30", - completed: "bg-emerald-500/15 text-emerald-300 ring-1 ring-inset ring-emerald-500/30", - }; - return colors[status] ?? "bg-zinc-500/15 text-zinc-300 ring-1 ring-inset ring-zinc-500/30"; -} - -export const CHART_TOOLTIP_STYLE = { - borderRadius: "12px", - border: "1px solid rgb(255 255 255 / 0.08)", - backgroundColor: "#18181B", - color: "#FAFAFA", - boxShadow: "0 8px 24px -4px rgb(0 0 0 / 0.6)", - fontSize: "13px", -} as const; - -export const CHART_GRID = "#27272A"; -export const CHART_TICK = "#A1A1AA"; diff --git a/apps/delta-command/tailwind.config.ts b/apps/delta-command/tailwind.config.ts deleted file mode 100644 index 976df25..0000000 --- a/apps/delta-command/tailwind.config.ts +++ /dev/null @@ -1,109 +0,0 @@ -import type { Config } from "tailwindcss"; - -const config: Config = { - content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], - theme: { - extend: { - colors: { - accent: { - DEFAULT: "#3B82F6", - muted: "rgb(59 130 246 / 0.12)", - foreground: "#60A5FA", - }, - primary: { - DEFAULT: "#3B82F6", - container: "rgb(59 130 246 / 0.12)", - on: "#FFFFFF", - "on-container": "#93C5FD", - }, - secondary: { - DEFAULT: "#71717A", - container: "#27272A", - on: "#FAFAFA", - "on-container": "#A1A1AA", - }, - tertiary: { - DEFAULT: "#A855F7", - container: "rgb(168 85 247 / 0.12)", - on: "#FFFFFF", - "on-container": "#C4B5FD", - }, - error: { - DEFAULT: "#EF4444", - container: "rgb(239 68 68 / 0.12)", - on: "#FFFFFF", - "on-container": "#FCA5A5", - }, - surface: { - DEFAULT: "#09090B", - dim: "#0C0C0E", - bright: "#18181B", - container: { - DEFAULT: "#27272A", - low: "#141416", - high: "#3F3F46", - highest: "#52525B", - }, - on: "#FAFAFA", - "on-variant": "#A1A1AA", - }, - outline: { - DEFAULT: "#52525B", - variant: "#27272A", - }, - sidebar: { - DEFAULT: "#030712", - foreground: "#FAFAFA", - muted: "#71717A", - border: "#1F2937", - accent: "#3B82F6", - }, - brand: { - 50: "#EFF6FF", - 100: "#DBEAFE", - 500: "#3B82F6", - 600: "#2563EB", - 700: "#1D4ED8", - 900: "#1E3A8A", - }, - }, - fontFamily: { - sans: ["var(--font-inter)", "Inter", "system-ui", "sans-serif"], - }, - borderRadius: { - xs: "6px", - sm: "8px", - md: "12px", - lg: "16px", - xl: "20px", - full: "9999px", - }, - boxShadow: { - "elevation-0": "none", - "elevation-1": "0 1px 2px 0 rgb(0 0 0 / 0.4)", - "elevation-2": "0 4px 12px -2px rgb(0 0 0 / 0.5)", - "elevation-3": "0 12px 24px -4px rgb(0 0 0 / 0.6)", - card: "0 0 0 1px rgb(255 255 255 / 0.06), 0 1px 2px 0 rgb(0 0 0 / 0.4)", - elevated: - "0 0 0 1px rgb(255 255 255 / 0.08), 0 8px 24px -4px rgb(0 0 0 / 0.5)", - glow: "0 0 0 3px rgb(59 130 246 / 0.25), 0 0 20px rgb(59 130 246 / 0.15)", - }, - transitionTimingFunction: { - standard: "cubic-bezier(0.4, 0, 0.2, 1)", - emphasized: "cubic-bezier(0.16, 1, 0.3, 1)", - }, - backgroundImage: { - "grid-pattern": - "linear-gradient(to right, rgb(255 255 255 / 0.04) 1px, transparent 1px), linear-gradient(to bottom, rgb(255 255 255 / 0.04) 1px, transparent 1px)", - "radial-glow": - "radial-gradient(ellipse 80% 50% at 50% -20%, rgb(59 130 246 / 0.08), transparent)", - }, - backgroundSize: { - grid: "24px 24px", - }, - }, - }, - plugins: [], -}; - -export default config; diff --git a/apps/delta-command/tsconfig.json b/apps/delta-command/tsconfig.json deleted file mode 100644 index b8cdcc7..0000000 --- a/apps/delta-command/tsconfig.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [{ "name": "next" }], - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -}