diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/.gitignore b/use-cases/pritesh2564u/dealer-agreement-redline/.gitignore
new file mode 100644
index 00000000..ea4a3afb
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/.gitignore
@@ -0,0 +1,28 @@
+# Environment
+.env
+.env.*
+
+# Python
+__pycache__/
+*.py[cod]
+*.pyo
+.venv/
+venv/
+
+# Node
+node_modules/
+dist/
+build/
+
+# IDE
+.vscode/
+.idea/
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Logs
+*.log
+
+backend/uploads/
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/README.md b/use-cases/pritesh2564u/dealer-agreement-redline/README.md
new file mode 100644
index 00000000..ba9f0b19
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/README.md
@@ -0,0 +1,1276 @@
+# Dealer Agreement Redline Desk
+
+A contract-redlining workflow built with FastAPI, PostgreSQL, and the SuperDocs API.
+
+The application compares a dealer-returned agreement against an approved master agreement and a negotiation playbook, detects deviations, classifies them, and routes them through a human-in-the-loop approval process before applying redlines and exporting the final document.
+
+---
+
+## Current Status
+
+### Backend
+
+- [x] SuperDocs API integration
+- [x] API key configuration
+- [x] Dealer agreement upload
+- [x] Master agreement attachment upload
+- [x] Negotiation playbook attachment upload
+- [x] DOCX section extraction
+- [x] Agreement deviation detection
+- [x] Playbook-based classification
+- [x] Redline review persistence
+- [x] Finding persistence
+- [x] Human approve/reject workflow
+- [x] Apply approved redlines through SuperDocs
+- [x] Export final DOCX
+- [x] Duplicate apply protection
+- [x] Review-state validation
+- [x] Backend compilation verification
+- [x] End-to-end workflow verification
+
+### Frontend
+
+- [ ] React frontend
+- [ ] Review dashboard
+- [ ] Review summary
+- [ ] Finding cards
+- [ ] Master vs dealer comparison
+- [ ] Approve/reject controls
+- [ ] Apply approved changes
+- [ ] Export DOCX
+
+---
+
+## Architecture
+
+```text
+┌─────────────────┐
+│ React UI │
+│ (Frontend) │
+└─────────┬────────┘
+ │ HTTP
+ ▼
+┌─────────────────┐
+│ FastAPI Backend │
+└─────────┬────────┘
+ │
+ ┌──────┴──────┐
+ ▼ ▼
+```
+
+The frontend communicates only with the FastAPI backend.
+
+The SuperDocs API key remains server-side and is never exposed to the browser.
+
+## Workflow
+
+```
+Dealer Agreement
+ │
+ ▼
+Create SuperDocs Session
+ │
+ ▼
+Upload Dealer Agreement
+ │
+ ├── Master Agreement → Attachment
+ │
+ └── Negotiation Playbook → Attachment
+ │
+ ▼
+Local Agreement Analysis
+ │
+ ├── Extract sections
+ ├── Detect deviations
+ └── Classify against playbook
+ │
+ ▼
+Create Redline Review
+ │
+ ▼
+Human Review
+ │
+ ├── Approve finding
+ └── Reject finding
+ │
+ ▼
+All Findings Reviewed
+ │
+ ▼
+Apply Approved Findings
+ │
+ ▼
+SuperDocs Updates Active Document
+ │
+ ▼
+Export Final DOCX
+```
+
+---
+
+## Redline Classification
+
+Each detected deviation is classified into one of three categories:
+
+```
+PRE-APPROVED
+ESCALATE
+REFUSE
+```
+
+**PRE-APPROVED**
+The requested change falls within the limits defined by the negotiation playbook.
+
+**ESCALATE**
+The requested change requires human review or approval.
+
+**REFUSE**
+The requested change exceeds the limits defined by the negotiation playbook and should not be accepted.
+
+The classification is determined by the backend playbook classifier.
+
+---
+
+## Human Review
+
+Every detected deviation is persisted as a redline finding.
+
+The reviewer can make one of two decisions:
+
+```
+approve
+reject
+```
+
+Only findings with:
+
+```
+decision = approve
+```
+
+are sent to SuperDocs for application.
+
+Rejected findings are not applied to the document.
+
+A finding cannot be reviewed more than once.
+
+A completed or applied review cannot receive additional decisions.
+
+---
+
+## Review Status
+
+A review progresses through the following states:
+
+```
+pending
+ │
+ ▼
+in_review
+ │
+ ▼
+completed
+ │
+ ▼
+applied
+```
+
+**pending**
+The review has been created but human review has not started.
+
+**in_review**
+At least one finding has been reviewed, but pending findings remain.
+
+**completed**
+All findings have received a human decision.
+
+**applied**
+All approved findings have been sent to SuperDocs and applied to the active document.
+
+---
+
+## Database
+
+The backend uses PostgreSQL.
+
+### `redline_reviews`
+
+Stores the overall redline review.
+
+Fields:
+
+```
+id
+session_id
+status
+created_at
+updated_at
+```
+
+### `redline_findings`
+
+Stores individual deviations found during the analysis.
+
+Fields:
+
+```
+id
+review_id
+section
+master_text
+dealer_text
+deviation_type
+similarity
+classification
+reason
+counter_position
+decision
+created_at
+```
+
+Relationship:
+
+```
+RedlineReview
+ │
+ └── RedlineFinding
+ ├── Finding 1
+ ├── Finding 2
+ ├── Finding 3
+ └── ...
+```
+
+`review_id` references the parent review.
+
+Deleting a review cascades to its findings.
+
+---
+
+## Backend Structure
+
+```
+backend/
+├── app/
+│ ├── api/
+│ │ ├── __init__.py
+│ │ ├── poc.py
+│ │ ├── redline.py
+│ │ └── superdocs.py
+│ │
+│ ├── db/
+│ │ ├── base.py
+│ │ ├── init_db.py
+│ │ └── session.py
+│ │
+│ ├── models/
+│ │ └── redline_review.py
+│ │
+│ ├── services/
+│ │ ├── agreement_parser.py
+│ │ ├── deviation_analyzer.py
+│ │ ├── playbook_classifier.py
+│ │ ├── redline_service.py
+│ │ └── superdocs_redline.py
+│ │
+│ ├── superdocs/
+│ │ ├── __init__.py
+│ │ └── client.py
+│ │
+│ ├── config.py
+│ └── main.py
+│
+├── .env
+└── requirements.txt
+```
+
+`.env` is local-only and must never be committed.
+
+---
+
+## Test Data
+
+The project contains three DOCX files used by the redline workflow:
+
+```
+test-data/
+├── dealer-agreement.docx
+├── master-agreement.docx
+└── negotiation-playbook.docx
+```
+
+### Dealer Agreement
+
+The dealer-returned agreement contains four relevant deviations:
+
+```
+Section 4.2 — Payment Terms
+Section 7.1 — Agreement Term
+Section 9.3 — Territory
+Section 12.1 — Termination
+```
+
+### Master Agreement
+
+The master agreement provides the approved baseline language.
+
+### Negotiation Playbook
+
+The negotiation playbook defines the allowed ranges and escalation/refusal rules.
+
+---
+
+## Current Example Analysis
+
+For the provided test agreements, the backend produces:
+
+```
+Section 4.2 — Payment Terms
+→ ESCALATE
+
+Section 7.1 — Agreement Term
+→ REFUSE
+
+Section 9.3 — Territory
+→ ESCALATE
+
+Section 12.1 — Termination
+→ REFUSE
+```
+
+Summary:
+
+```json
+{
+ "total": 4,
+ "pre_approved": 0,
+ "escalate": 2,
+ "refuse": 2
+}
+```
+
+A human reviewer can approve the two escalation findings and reject the two refusal findings.
+
+The resulting workflow is:
+
+```
+Payment Terms
+→ APPROVE
+→ APPLY
+
+Agreement Term
+→ REJECT
+→ IGNORE
+
+Territory
+→ APPROVE
+→ APPLY
+
+Termination
+→ REJECT
+→ IGNORE
+```
+
+Only the two approved findings are sent to SuperDocs.
+
+---
+
+## SuperDocs Integration
+
+The backend contains a dedicated `SuperDocsClient`.
+
+The client supports:
+
+- API key authentication
+- API key verification
+- Document upload
+- Attachment upload
+- Chat
+- Human-in-the-loop approval
+- Document export
+
+### SuperDocs Authentication
+
+The SuperDocs API uses the `Authorization` header:
+
+```http
+Authorization: Bearer sk_YOUR_API_KEY
+```
+
+The API key is stored in the backend environment:
+
+```env
+SUPERDOCS_API_KEY=sk_YOUR_API_KEY
+```
+
+The browser never receives this key.
+
+### API Key Verification
+
+SuperDocs provides:
+
+```http
+GET /v1/sessions
+```
+
+as a safe way to verify an API key.
+
+The backend's SuperDocs client uses:
+
+```
+GET /v1/sessions
+```
+
+for verification.
+
+A successful `200` response confirms that the API key is valid.
+
+---
+
+## Documents vs Attachments
+
+SuperDocs provides two different ways to load files.
+
+### Active Document
+
+The dealer agreement is uploaded using:
+
+```
+/v1/documents/upload
+```
+
+This makes it the active editable document.
+
+### Attachments
+
+The master agreement and negotiation playbook are uploaded using:
+
+```
+/v1/attachments/upload
+```
+
+These provide reference material for the workflow.
+
+The distinction is:
+
+```
+Dealer Agreement
+→ Active editable document
+
+Master Agreement
+→ Reference attachment
+
+Negotiation Playbook
+→ Reference attachment
+```
+
+Attachments are useful as supporting context, while the document upload is used for the document that will actually be edited.
+
+---
+
+## SuperDocs Session
+
+A unique SuperDocs session is created for each redline analysis.
+
+The same `session_id` is persisted in `RedlineReview`.
+
+This connects the application review to the SuperDocs active document:
+
+```
+RedlineReview
+ │
+ └── session_id
+ │
+ ▼
+ SuperDocs Session
+ │
+ ▼
+ Active Dealer Document
+```
+
+When `/apply` is called, the backend uses the stored session ID to modify the correct active SuperDocs document.
+
+---
+
+## SuperDocs Chat
+
+The backend uses SuperDocs chat/document editing capabilities to apply approved counter-positions.
+
+Only human-approved findings are passed to the application service.
+
+The frontend does not communicate directly with the SuperDocs chat API.
+
+---
+
+## Human-in-the-Loop
+
+The application has its own human review layer.
+
+The workflow is:
+
+```
+AI / Backend Analysis
+ │
+ ▼
+Redline Findings
+ │
+ ▼
+Human Decision
+ ┌───┴───┐
+ │ │
+Approve Reject
+ │ │
+ ▼ ▼
+ Apply Ignore
+```
+
+SuperDocs also supports human-in-the-loop approval for document changes.
+
+For the tested workflow, SuperDocs returned the applied edits as:
+
+```
+status: auto_approved
+```
+
+with:
+
+```
+requires_approval: null
+pending_changes: null
+```
+
+Therefore, no additional SuperDocs approval call was required for the tested changes.
+
+The application does not artificially call the SuperDocs approval endpoint when SuperDocs reports that there are no pending changes requiring approval.
+
+---
+
+## Applied Changes
+
+For the tested review, two findings were approved.
+
+SuperDocs returned:
+
+```
+2 sections edited, rest untouched
+```
+
+### Section 4.2 — Payment Terms
+
+Original dealer language:
+
+```
+Dealer payments are due within 60 days of invoice.
+```
+
+Applied language:
+
+```
+Dealer payments are due within 30 days of invoice.
+Any request for 60-day terms must be escalated for approval.
+```
+
+### Section 9.3 — Territory
+
+Original dealer language:
+
+```
+Dealer shall operate within the assigned territory
+and may sell to customers outside the territory.
+```
+
+Applied language:
+
+```
+Dealer shall operate within the assigned territory.
+Expansion of territory is prohibited unless approved
+through escalation.
+```
+
+The rejected findings remained unchanged.
+
+---
+
+## API Endpoints
+
+### 1. Analyze Agreement
+
+```http
+POST /redline/analyze
+```
+
+Creates a SuperDocs session, uploads the required documents, analyzes the agreements, and persists a redline review.
+
+Example:
+
+```powershell
+curl -X POST http://localhost:8000/redline/analyze
+```
+
+Response includes:
+
+```
+review_id
+session_id
+dealer_document
+master_attachment
+playbook_attachment
+master_sections
+dealer_sections
+playbook_sections
+deviations
+summary
+```
+
+### 2. Get Review
+
+```http
+GET /redline/reviews/{review_id}
+```
+
+Returns:
+
+- review status
+- SuperDocs session ID
+- timestamps
+- all findings
+- classification
+- reason
+- counter-position
+- human decision
+
+Example:
+
+```powershell
+curl http://localhost:8000/redline/reviews/REVIEW_ID
+```
+
+### 3. Decide Finding
+
+```http
+POST /redline/reviews/{review_id}/findings/{finding_id}/decision
+```
+
+Approve:
+
+```json
+{
+ "decision": "approve"
+}
+```
+
+Reject:
+
+```json
+{
+ "decision": "reject"
+}
+```
+
+The backend normalizes the decision using:
+
+```
+strip()
+lower()
+```
+
+Therefore:
+
+```
+APPROVE
+Approve
+ approve
+```
+
+are normalized to:
+
+```
+approve
+```
+
+Only `approve` and `reject` are accepted.
+
+### 4. Apply Approved Findings
+
+```http
+POST /redline/reviews/{review_id}/apply
+```
+
+This endpoint:
+
+1. Loads the review.
+2. Checks that the review has not already been applied.
+3. Checks that no findings remain pending.
+4. Loads all findings.
+5. Passes approved findings to the SuperDocs redline service.
+6. Applies approved changes to the active document.
+7. Updates the review status to `applied`.
+
+Example:
+
+```powershell
+curl -X POST http://localhost:8000/redline/reviews/REVIEW_ID/apply
+```
+
+A review cannot be applied twice.
+
+Attempting to apply an already-applied review returns HTTP `409`.
+
+### 5. Export
+
+```http
+GET /redline/reviews/{review_id}/export
+```
+
+Exports the currently applied SuperDocs document.
+
+The generated file is:
+
+```
+dealer-agreement-redlined.docx
+```
+
+Example:
+
+```powershell
+curl -X GET http://localhost:8000/redline/reviews/REVIEW_ID/export -o dealer-agreement-redlined.docx
+```
+
+Export is blocked until the review status is:
+
+```
+applied
+```
+
+---
+
+## Validation Rules
+
+The backend currently validates:
+
+- Required test files exist.
+- Review exists before review operations.
+- Finding exists before a decision is made.
+- Finding belongs to the requested review.
+- Finding cannot be decided twice.
+- Completed reviews cannot receive new decisions.
+- Applied reviews cannot receive new decisions.
+- Pending findings prevent applying.
+- Already-applied reviews cannot be applied again.
+- Export requires an applied review.
+- SuperDocs API errors are handled by the backend.
+- Invalid decisions return HTTP `400`.
+- Missing reviews/findings return HTTP `404`.
+- Invalid workflow state returns HTTP `409`.
+- SuperDocs failures return HTTP `502`.
+
+---
+
+## Error Responses
+
+### Invalid Decision
+
+```json
+{
+ "detail": "Decision must be either 'approve' or 'reject'."
+}
+```
+
+HTTP: `400 Bad Request`
+
+### Review Not Found
+
+```json
+{
+ "detail": "Redline review not found"
+}
+```
+
+HTTP: `404 Not Found`
+
+### Finding Already Reviewed
+
+```json
+{
+ "detail": "This finding has already been reviewed."
+}
+```
+
+HTTP: `409 Conflict`
+
+### Pending Findings
+
+```json
+{
+ "detail": "2 finding(s) still require review."
+}
+```
+
+HTTP: `409 Conflict`
+
+### Review Already Applied
+
+```json
+{
+ "detail": "This review has already been applied."
+}
+```
+
+HTTP: `409 Conflict`
+
+### Export Before Apply
+
+```json
+{
+ "detail": "The review must be applied before exporting."
+}
+```
+
+HTTP: `409 Conflict`
+
+### SuperDocs Error
+
+SuperDocs failures are returned as:
+
+```
+502 Bad Gateway
+```
+
+---
+
+## Environment Variables
+
+Create:
+
+```
+backend/.env
+```
+
+Example:
+
+```env
+DATABASE_URL=postgresql+asyncpg://postgres:password@localhost:5432/dealer_redline
+SUPERDOCS_API_KEY=sk_YOUR_API_KEY
+```
+
+Never commit `.env`.
+
+The `.env` file contains secrets and must remain local.
+
+---
+
+## Backend Setup
+
+From the project root:
+
+```powershell
+cd backend
+```
+
+Create a virtual environment:
+
+```powershell
+python -m venv .venv
+```
+
+Activate it on Windows PowerShell:
+
+```powershell
+.\venv\Scripts\Activate.ps1
+```
+
+Install dependencies:
+
+```powershell
+pip install -r requirements.txt
+```
+
+Start the backend:
+
+```powershell
+uvicorn app.main:app --reload
+```
+
+The API runs at:
+
+```
+http://127.0.0.1:8000
+```
+
+Swagger documentation:
+
+```
+http://127.0.0.1:8000/docs
+```
+
+---
+
+## Backend Verification
+
+Python compilation can be checked with:
+
+```powershell
+python -m compileall app
+```
+
+A successful result finishes without syntax errors.
+
+The current backend has been verified through the following workflow:
+
+```
+POST /redline/analyze
+ ↓
+GET /redline/reviews/{review_id}
+ ↓
+POST /redline/reviews/{review_id}/findings/{finding_id}/decision
+ ↓
+remaining_findings = 0
+ ↓
+POST /redline/reviews/{review_id}/apply
+ ↓
+status = applied
+ ↓
+GET /redline/reviews/{review_id}/export
+ ↓
+DOCX successfully exported
+```
+
+The duplicate-apply protection was also tested successfully.
+
+Attempting to apply an already-applied review returns HTTP `409`.
+
+---
+
+## Backend Test Results
+
+The following functionality has been tested successfully:
+
+### Agreement Analysis
+
+- ✓ Master agreement parsed
+- ✓ Dealer agreement parsed
+- ✓ Negotiation playbook parsed
+- ✓ Deviations detected
+- ✓ Deviations classified
+
+### Database
+
+- ✓ Redline review persisted
+- ✓ Redline findings persisted
+- ✓ Review retrieved
+- ✓ Finding decisions persisted
+
+### Human Review
+
+- ✓ Finding approve
+- ✓ Finding reject
+- ✓ Pending finding count
+- ✓ Review transitions to completed
+- ✓ Duplicate decision prevented
+
+### SuperDocs
+
+- ✓ Dealer document uploaded
+- ✓ Master attachment uploaded
+- ✓ Playbook attachment uploaded
+- ✓ Approved redlines applied
+- ✓ Rejected redlines left unchanged
+- ✓ Final document exported
+
+### Workflow Protection
+
+- ✓ Duplicate apply prevented
+- ✓ Apply blocked while findings are pending
+- ✓ Decision blocked after review completion
+- ✓ Decision blocked after review application
+- ✓ Export blocked before apply
+
+---
+
+## Frontend
+
+The frontend is maintained separately from the backend.
+
+The frontend directory is:
+
+```
+frontend/
+```
+
+The frontend will be built using React and TypeScript with Vite.
+
+Planned structure:
+
+```
+frontend/
+├── package.json
+├── vite.config.ts
+├── tsconfig.json
+├── index.html
+└── src/
+ ├── main.tsx
+ ├── App.tsx
+ ├── api/
+ │ └── redline.ts
+ ├── components/
+ │ ├── ReviewSummary.tsx
+ │ ├── FindingCard.tsx
+ │ └── ReviewActions.tsx
+ └── types/
+ └── redline.ts
+```
+
+### Planned Frontend Workflow
+
+```
+Start Review
+ │
+ ▼
+POST /redline/analyze
+ │
+ ▼
+Review Dashboard
+ │
+ ├── View summary
+ ├── View master language
+ ├── View dealer language
+ ├── View classification
+ ├── View reason
+ └── View counter-position
+ │
+ ▼
+Approve / Reject findings
+ │
+ ▼
+All findings reviewed
+ │
+ ▼
+Apply Approved Changes
+ │
+ ▼
+Export DOCX
+```
+
+### Planned Frontend UI
+
+```
+┌────────────────────────────────────────────────────────────┐
+│ Dealer Agreement Redline │
+│ Review and approve contract changes │
+├────────────────────────────────────────────────────────────┤
+│ │
+│ Review Summary │
+│ │
+│ ┌─────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ │
+│ │ 4 │ │ 2 │ │ 2 │ │ 0 │ │
+│ │Total│ │Escalate │ │Refuse │ │Reviewed │ │
+│ └─────┘ └──────────┘ └────────┘ └──────────┘ │
+│ │
+├────────────────────────────────────────────────────────────┤
+│ │
+│ Section 4.2 — Payment Terms ESCALATE │
+│ │
+│ Master: │
+│ Dealer payments are due within 30 days of invoice. │
+│ │
+│ Dealer: │
+│ Dealer payments are due within 60 days of invoice. │
+│ │
+│ Reason: │
+│ Payment terms exceed the 45-day pre-approved limit. │
+│ │
+│ Counter-position: │
+│ Maintain the standard 30-day payment term or │
+│ escalate the requested 60-day term for approval. │
+│ │
+│ [ Reject ] [ Approve ] │
+│ │
+├────────────────────────────────────────────────────────────┤
+│ [ Apply Approved Changes ] │
+│ [ Export DOCX ] │
+└────────────────────────────────────────────────────────────┘
+```
+
+### Frontend API Flow
+
+The frontend will consume the following backend APIs:
+
+```
+React
+ │
+ ├── POST /redline/analyze
+ │
+ ├── GET /redline/reviews/{review_id}
+ │
+ ├── POST /redline/reviews/{review_id}/findings/{finding_id}/decision
+ │
+ ├── POST /redline/reviews/{review_id}/apply
+ │
+ └── GET /redline/reviews/{review_id}/export
+ │
+ ▼
+ FastAPI
+ │
+ ├── PostgreSQL
+ │
+ └── SuperDocs API
+```
+
+The frontend never calls:
+
+```
+https://api.superdocs.app
+```
+
+directly.
+
+---
+
+## Security
+
+The SuperDocs API key is server-side only.
+
+The frontend must never contain:
+
+```
+SUPERDOCS_API_KEY
+```
+
+The frontend must never make direct requests to:
+
+```
+https://api.superdocs.app
+```
+
+All SuperDocs operations must go through the FastAPI backend.
+
+The `.env` file must never be committed to Git.
+
+---
+
+## Git Ignore
+
+The repository should ignore local environment files and generated files:
+
+```gitignore
+# Environment
+.env
+.env.*
+
+# Python
+__pycache__/
+*.py[cod]
+.venv/
+venv/
+
+# Node
+node_modules/
+dist/
+
+# IDE
+.vscode/
+.idea/
+
+# Generated export
+dealer-agreement-redlined.docx
+```
+
+Do not use a blanket:
+
+```gitignore
+*.docx
+```
+
+rule.
+
+The test DOCX files under `test-data/` are required project files and should remain tracked:
+
+```
+test-data/
+├── dealer-agreement.docx
+├── master-agreement.docx
+└── negotiation-playbook.docx
+```
+
+---
+
+## Project Directory
+
+The current project structure is:
+
+```
+dealer-agreement-redline/
+│
+├── backend/
+│ ├── app/
+│ ├── .env
+│ └── requirements.txt
+│
+├── frontend/
+│
+├── test-data/
+│ ├── dealer-agreement.docx
+│ ├── master-agreement.docx
+│ └── negotiation-playbook.docx
+│
+├── .gitignore
+└── README.md
+```
+
+---
+
+## Development Notes
+
+This project is a focused proof of concept for the dealer-agreement redline workflow.
+
+The backend currently provides the complete functional workflow:
+
+```
+Analyze
+ ↓
+Persist Review
+ ↓
+Review Findings
+ ↓
+Approve / Reject
+ ↓
+Apply Approved Changes
+ ↓
+Export DOCX
+```
+
+The backend is complete and tested before starting frontend implementation.
+
+The frontend will consume the existing backend APIs and provide the user-facing review interface.
+
+The SuperDocs API key remains completely server-side.
+
+---
+
+## Current Milestone
+
+### Task 2 Backend
+
+```
+STATUS: COMPLETE
+```
+
+Completed:
+
+- ✓ SuperDocs integration
+- ✓ Document uploads
+- ✓ Attachment uploads
+- ✓ Agreement parsing
+- ✓ Deviation analysis
+- ✓ Playbook classification
+- ✓ PostgreSQL persistence
+- ✓ Human review
+- ✓ Approve/reject decisions
+- ✓ Apply approved changes
+- ✓ Export DOCX
+- ✓ Workflow validation
+- ✓ Duplicate apply protection
+- ✓ Backend verification
+
+### Next
+
+- Build the React frontend (dashboard, finding cards, comparison view, approve/reject controls, apply and export actions).
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/README_updated.md b/use-cases/pritesh2564u/dealer-agreement-redline/README_updated.md
new file mode 100644
index 00000000..21400e14
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/README_updated.md
@@ -0,0 +1,288 @@
+# Dealer Agreement Redline Desk
+
+A contract-redlining workflow built with FastAPI, PostgreSQL, and the SuperDocs API.
+
+The application compares a dealer-returned agreement against an approved master agreement and a negotiation playbook, detects deviations, classifies them, and routes them through a human-in-the-loop approval process before applying redlines and exporting the final document.
+
+---
+
+## Current Status
+
+### Backend
+
+- [x] SuperDocs API integration
+- [x] API key configuration
+- [x] Dealer agreement upload
+- [x] Master agreement attachment upload
+- [x] Negotiation playbook attachment upload
+- [x] DOCX section extraction
+- [x] Agreement deviation detection
+- [x] Playbook-based classification
+- [x] Redline review persistence
+- [x] Finding persistence
+- [x] Human approve/reject workflow
+- [x] Apply approved redlines through SuperDocs
+- [x] Export final DOCX
+- [x] Duplicate apply protection
+- [x] Review-state validation
+- [x] Backend compilation verification
+- [x] End-to-end workflow verification
+
+### Frontend
+
+The frontend is implemented with React, TypeScript, Vite, Tailwind CSS, and Lucide React icons.
+
+It provides the complete user-facing workflow:
+
+- Dynamic upload of dealer, master, and playbook DOCX files
+- Review summary
+- Finding classification badges
+- Collapsible finding cards
+- Master vs dealer comparison
+- Reason and counter-position display
+- Approve/reject controls
+- Review progress
+- Apply approved changes
+- Export final DOCX
+- Loading, success, and error states
+- Fixed header
+- Responsive layout
+- Lucide icons
+
+### Frontend Structure
+
+```text
+frontend/
+├── package.json
+├── vite.config.ts
+├── tsconfig.json
+├── index.html
+└── src/
+ ├── main.tsx
+ ├── App.tsx
+ ├── api/
+ │ └── redline.ts
+ ├── components/
+ │ ├── DocumentUpload.tsx
+ │ ├── EmptyState.tsx
+ │ ├── FindingCard.tsx
+ │ ├── FindingList.tsx
+ │ ├── Header.tsx
+ │ └── SuccessMessage.tsx
+ └── types/
+ └── redline.ts
+```
+
+### Frontend Workflow
+
+```text
+Upload Documents
+ │
+ ▼
+POST /redline/analyze
+ │
+ ▼
+Review Dashboard
+ │
+ ├── Summary
+ ├── Classification
+ ├── Master language
+ ├── Dealer language
+ ├── Reason
+ └── Counter-position
+ │
+ ▼
+Approve / Reject findings
+ │
+ ▼
+All findings reviewed
+ │
+ ▼
+Apply Approved Changes
+ │
+ ▼
+Export DOCX
+```
+
+### Finding UX
+
+Findings are collapsed by default so reviews with many deviations remain compact.
+
+The collapsed card shows the finding number, section, classification, and decision status. Expanding a card reveals the master text, dealer text, reason, counter-position, and approve/reject actions.
+
+### Frontend Development
+
+From the frontend directory:
+
+```powershell
+npm install
+npm run dev
+```
+
+The Vite development server runs at:
+
+```text
+http://localhost:5173
+```
+
+Production build:
+
+```powershell
+npm run build
+```
+
+The frontend communicates only with the FastAPI backend. It never receives or exposes the SuperDocs API key.
+
+## Security
+
+The SuperDocs API key is server-side only.
+
+The frontend must never contain:
+
+```
+SUPERDOCS_API_KEY
+```
+
+The frontend must never make direct requests to:
+
+```
+https://api.superdocs.app
+```
+
+All SuperDocs operations must go through the FastAPI backend.
+
+The `.env` file must never be committed to Git.
+
+---
+
+## Git Ignore
+
+The repository should ignore local environment files and generated files:
+
+```gitignore
+# Environment
+.env
+.env.*
+
+# Python
+__pycache__/
+*.py[cod]
+.venv/
+venv/
+
+# Node
+node_modules/
+dist/
+
+# IDE
+.vscode/
+.idea/
+
+# Generated export
+dealer-agreement-redlined.docx
+```
+
+Do not use a blanket:
+
+```gitignore
+*.docx
+```
+
+rule.
+
+The test DOCX files under `test-data/` are required project files and should remain tracked:
+
+```
+test-data/
+├── dealer-agreement.docx
+├── master-agreement.docx
+└── negotiation-playbook.docx
+```
+
+---
+
+## Project Directory
+
+The current project structure is:
+
+```
+dealer-agreement-redline/
+│
+├── backend/
+│ ├── app/
+│ ├── .env
+│ └── requirements.txt
+│
+├── frontend/
+│
+├── test-data/
+│ ├── dealer-agreement.docx
+│ ├── master-agreement.docx
+│ └── negotiation-playbook.docx
+│
+├── .gitignore
+└── README.md
+```
+
+---
+
+## Development Notes
+
+This project is a focused proof of concept for the dealer-agreement redline workflow.
+
+The backend currently provides the complete functional workflow:
+
+```
+Analyze
+ ↓
+Persist Review
+ ↓
+Review Findings
+ ↓
+Approve / Reject
+ ↓
+Apply Approved Changes
+ ↓
+Export DOCX
+```
+
+The backend is complete and tested before starting frontend implementation.
+
+The frontend will consume the existing backend APIs and provide the user-facing review interface.
+
+The SuperDocs API key remains completely server-side.
+
+---
+
+## Current Milestone
+
+### Task 2
+
+```text
+STATUS: COMPLETE
+```
+
+Completed:
+
+- ✓ SuperDocs integration
+- ✓ Dynamic dealer/master/playbook uploads
+- ✓ Dealer document loaded into the SuperDocs session
+- ✓ Agreement parsing
+- ✓ Deviation analysis
+- ✓ Playbook classification
+- ✓ PostgreSQL persistence
+- ✓ Human review
+- ✓ Approve/reject decisions
+- ✓ Apply approved changes
+- ✓ Export DOCX
+- ✓ Workflow validation
+- ✓ Duplicate apply protection
+- ✓ Responsive React frontend
+- ✓ Collapsible findings
+- ✓ Fixed header
+- ✓ Lucide icons
+- ✓ User-friendly loading/success/error states
+- ✓ End-to-end workflow verification
+- ✓ Backend compilation verification
+
+The complete Task 2 workflow is implemented and tested.
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/__init__.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/__init__.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/poc.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/poc.py
new file mode 100644
index 00000000..d6b838b9
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/poc.py
@@ -0,0 +1,142 @@
+import uuid
+from pathlib import Path
+
+from fastapi import APIRouter, HTTPException
+
+from app.superdocs.client import (
+ SuperDocsClient,
+ SuperDocsError,
+)
+
+
+router = APIRouter(
+ prefix="/poc",
+ tags=["poc"],
+)
+
+
+TEST_DATA = (
+ Path(__file__).resolve().parents[3]
+ / "test-data"
+)
+
+
+@router.post("/dealer-redline")
+async def dealer_redline_poc():
+ """
+ End-to-end SuperDocs POC.
+
+ Current flow:
+ 1. Upload dealer agreement as active document.
+ 2. Upload master agreement as attachment.
+ 3. Upload negotiation playbook as attachment.
+ 4. Ask SuperDocs to analyze the agreement.
+ 5. Return the raw chat response.
+
+ We intentionally do not approve or export yet.
+ First we inspect the exact proposed-change response.
+ """
+
+ dealer_file = (
+ TEST_DATA / "dealer-agreement.docx"
+ )
+
+ master_file = (
+ TEST_DATA / "master-agreement.docx"
+ )
+
+ playbook_file = (
+ TEST_DATA / "negotiation-playbook.docx"
+ )
+
+ for file in (
+ dealer_file,
+ master_file,
+ playbook_file,
+ ):
+ if not file.exists():
+ raise HTTPException(
+ status_code=404,
+ detail=f"Test file not found: {file}",
+ )
+
+ client = SuperDocsClient()
+
+ session_id = str(uuid.uuid4())
+
+ try:
+ # --------------------------------------------------
+ # 1. Upload dealer agreement as active document.
+ # --------------------------------------------------
+
+ dealer_document = (
+ await client.upload_document(
+ file_path=dealer_file,
+ session_id=session_id,
+ )
+ )
+
+ # --------------------------------------------------
+ # 2. Upload master agreement as reference.
+ # --------------------------------------------------
+
+ master_attachment = (
+ await client.upload_attachment(
+ file_path=master_file,
+ session_id=session_id,
+ )
+ )
+
+ # --------------------------------------------------
+ # 3. Upload negotiation playbook as reference.
+ # --------------------------------------------------
+
+ playbook_attachment = (
+ await client.upload_attachment(
+ file_path=playbook_file,
+ session_id=session_id,
+ )
+ )
+
+ # --------------------------------------------------
+ # 4. Ask SuperDocs to analyze the dealer agreement.
+ # --------------------------------------------------
+
+ instruction = """
+Compare the active dealer agreement against the approved
+master agreement and evaluate all substantive deviations
+using the negotiation playbook.
+
+For every deviation:
+
+1. Identify the agreement section.
+2. Describe the substantive change.
+3. Explain the difference between the master language
+ and dealer language.
+4. Determine whether the change is PRE-APPROVED,
+ ESCALATE, or REFUSE according to the playbook.
+5. Draft a concise counter-position.
+
+Do not make any final changes to the document yet.
+
+Return the proposed changes for human review.
+""".strip()
+
+ chat_response = await client.chat(
+ session_id=session_id,
+ message=instruction,
+ )
+
+ return {
+ "session_id": session_id,
+ "dealer_document": dealer_document,
+ "master_attachment": master_attachment,
+ "playbook_attachment": playbook_attachment,
+ "chat_response": chat_response,
+ }
+
+ except SuperDocsError as exc:
+ raise HTTPException(
+ status_code=502,
+ detail=str(exc),
+ )
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/redline.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/redline.py
new file mode 100644
index 00000000..ef20e320
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/redline.py
@@ -0,0 +1,629 @@
+import shutil
+import uuid
+from pathlib import Path
+from uuid import UUID
+
+from fastapi import (
+ APIRouter,
+ Depends,
+ File,
+ HTTPException,
+ UploadFile,
+)
+from fastapi.responses import Response
+from pydantic import BaseModel
+from sqlalchemy import select
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from app.db.session import get_db
+from app.models.redline_review import (
+ RedlineFinding,
+ RedlineReview,
+)
+from app.services.redline_service import (
+ analyze_agreements,
+ create_redline_review,
+)
+from app.services.superdocs_redline import (
+ apply_approved_redlines,
+)
+from app.superdocs.client import (
+ SuperDocsClient,
+ SuperDocsError,
+)
+
+
+router = APIRouter(
+ prefix="/redline",
+ tags=["redline"],
+)
+
+
+UPLOAD_DIR = (
+ Path(__file__).resolve().parents[2]
+ / "uploads"
+)
+
+
+ALLOWED_EXTENSIONS = {
+ ".docx",
+}
+
+
+class FindingDecisionRequest(BaseModel):
+ decision: str
+
+
+def validate_docx_file(
+ file: UploadFile,
+ field_name: str,
+) -> None:
+ if not file.filename:
+ raise HTTPException(
+ status_code=400,
+ detail=f"{field_name} is required.",
+ )
+
+ extension = Path(
+ file.filename
+ ).suffix.lower()
+
+ if extension not in ALLOWED_EXTENSIONS:
+ raise HTTPException(
+ status_code=400,
+ detail=(
+ f"{field_name} must be a DOCX file."
+ ),
+ )
+
+
+async def save_upload(
+ file: UploadFile,
+ destination: Path,
+) -> None:
+ destination.parent.mkdir(
+ parents=True,
+ exist_ok=True,
+ )
+
+ with destination.open("wb") as output:
+ shutil.copyfileobj(
+ file.file,
+ output,
+ )
+
+
+@router.post("/analyze")
+async def analyze_redline(
+ dealer_file: UploadFile = File(...),
+ master_file: UploadFile = File(...),
+ playbook_file: UploadFile = File(...),
+ db: AsyncSession = Depends(get_db),
+):
+ """
+ Analyze uploaded dealer, master, and playbook
+ documents.
+
+ The dealer agreement is also loaded into a
+ SuperDocs session so that the same session can
+ later be used for applying approved redlines
+ and exporting the updated document.
+ """
+
+ # --------------------------------------------------
+ # Validate uploaded files
+ # --------------------------------------------------
+
+ validate_docx_file(
+ dealer_file,
+ "dealer_file",
+ )
+
+ validate_docx_file(
+ master_file,
+ "master_file",
+ )
+
+ validate_docx_file(
+ playbook_file,
+ "playbook_file",
+ )
+
+ # --------------------------------------------------
+ # Create temporary upload directory
+ # --------------------------------------------------
+
+ request_id = uuid.uuid4()
+
+ request_upload_dir = (
+ UPLOAD_DIR / str(request_id)
+ )
+
+ dealer_path = (
+ request_upload_dir
+ / "dealer-agreement.docx"
+ )
+
+ master_path = (
+ request_upload_dir
+ / "master-agreement.docx"
+ )
+
+ playbook_path = (
+ request_upload_dir
+ / "negotiation-playbook.docx"
+ )
+
+ try:
+ # --------------------------------------------------
+ # Save uploaded documents temporarily
+ # --------------------------------------------------
+
+ await save_upload(
+ dealer_file,
+ dealer_path,
+ )
+
+ await save_upload(
+ master_file,
+ master_path,
+ )
+
+ await save_upload(
+ playbook_file,
+ playbook_path,
+ )
+
+ # --------------------------------------------------
+ # Analyze documents locally
+ # --------------------------------------------------
+
+ analysis = analyze_agreements(
+ master_path=master_path,
+ dealer_path=dealer_path,
+ playbook_path=playbook_path,
+ )
+
+ # --------------------------------------------------
+ # Create one SuperDocs session for this review
+ # --------------------------------------------------
+
+ session_id = str(uuid.uuid4())
+
+ client = SuperDocsClient()
+
+ # --------------------------------------------------
+ # Load dealer agreement into SuperDocs
+ #
+ # This is important because the same session is
+ # later used by apply and export.
+ # --------------------------------------------------
+
+ try:
+ dealer_document = (
+ await client.upload_document(
+ file_path=dealer_path,
+ session_id=session_id,
+ )
+ )
+
+ except SuperDocsError as exc:
+ raise HTTPException(
+ status_code=502,
+ detail=(
+ "SuperDocs document upload failed: "
+ f"{exc}"
+ ),
+ )
+
+ # --------------------------------------------------
+ # Create database review
+ # --------------------------------------------------
+
+ review = await create_redline_review(
+ db=db,
+ session_id=session_id,
+ analysis=analysis,
+ )
+
+ # --------------------------------------------------
+ # Return analysis + SuperDocs document information
+ # --------------------------------------------------
+
+ return {
+ "review_id": str(review.id),
+ "session_id": session_id,
+ "dealer_document": dealer_document,
+ **analysis,
+ }
+
+ except HTTPException:
+ raise
+
+ except Exception as exc:
+ raise HTTPException(
+ status_code=500,
+ detail=str(exc),
+ )
+
+ finally:
+ # --------------------------------------------------
+ # Delete temporary uploaded files
+ # --------------------------------------------------
+
+ shutil.rmtree(
+ request_upload_dir,
+ ignore_errors=True,
+ )
+
+
+@router.get("/reviews/{review_id}")
+async def get_redline_review(
+ review_id: UUID,
+ db: AsyncSession = Depends(get_db),
+):
+ result = await db.execute(
+ select(RedlineReview).where(
+ RedlineReview.id == review_id
+ )
+ )
+
+ review = result.scalar_one_or_none()
+
+ if review is None:
+ raise HTTPException(
+ status_code=404,
+ detail="Redline review not found",
+ )
+
+ result = await db.execute(
+ select(RedlineFinding)
+ .where(
+ RedlineFinding.review_id == review_id
+ )
+ .order_by(RedlineFinding.created_at)
+ )
+
+ findings = result.scalars().all()
+
+ return {
+ "review_id": str(review.id),
+ "session_id": review.session_id,
+ "status": review.status,
+ "created_at": review.created_at,
+ "updated_at": review.updated_at,
+ "findings": [
+ {
+ "id": str(finding.id),
+ "section": finding.section,
+ "master_text": finding.master_text,
+ "dealer_text": finding.dealer_text,
+ "deviation_type": finding.deviation_type,
+ "similarity": finding.similarity,
+ "classification": finding.classification,
+ "reason": finding.reason,
+ "counter_position": finding.counter_position,
+ "decision": finding.decision,
+ }
+ for finding in findings
+ ],
+ }
+
+
+@router.post(
+ "/reviews/{review_id}/findings/{finding_id}/decision"
+)
+async def decide_redline_finding(
+ review_id: UUID,
+ finding_id: UUID,
+ payload: FindingDecisionRequest,
+ db: AsyncSession = Depends(get_db),
+):
+ # --------------------------------------------------
+ # Validate decision
+ # --------------------------------------------------
+
+ if payload.decision not in {
+ "approve",
+ "reject",
+ }:
+ raise HTTPException(
+ status_code=400,
+ detail=(
+ "Decision must be either "
+ "'approve' or 'reject'."
+ ),
+ )
+
+ # --------------------------------------------------
+ # Verify review exists
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineReview).where(
+ RedlineReview.id == review_id
+ )
+ )
+
+ review = result.scalar_one_or_none()
+
+ if review is None:
+ raise HTTPException(
+ status_code=404,
+ detail="Redline review not found",
+ )
+
+ # --------------------------------------------------
+ # Find finding
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineFinding).where(
+ RedlineFinding.id == finding_id,
+ RedlineFinding.review_id == review_id,
+ )
+ )
+
+ finding = result.scalar_one_or_none()
+
+ if finding is None:
+ raise HTTPException(
+ status_code=404,
+ detail="Redline finding not found",
+ )
+
+ # --------------------------------------------------
+ # Prevent duplicate decisions
+ # --------------------------------------------------
+
+ if finding.decision != "pending":
+ raise HTTPException(
+ status_code=409,
+ detail=(
+ "This finding has already been "
+ "reviewed."
+ ),
+ )
+
+ finding.decision = payload.decision
+
+ # --------------------------------------------------
+ # Check remaining pending findings
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineFinding).where(
+ RedlineFinding.review_id == review_id,
+ RedlineFinding.decision == "pending",
+ )
+ )
+
+ remaining = result.scalars().all()
+
+ if remaining:
+ review.status = "in_review"
+ else:
+ review.status = "completed"
+
+ await db.commit()
+ await db.refresh(finding)
+
+ return {
+ "review_id": str(review_id),
+ "finding_id": str(finding_id),
+ "decision": finding.decision,
+ "review_status": review.status,
+ "remaining_findings": len(remaining),
+ }
+
+
+@router.post(
+ "/reviews/{review_id}/apply"
+)
+async def apply_review(
+ review_id: UUID,
+ db: AsyncSession = Depends(get_db),
+):
+ # --------------------------------------------------
+ # Get review
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineReview).where(
+ RedlineReview.id == review_id
+ )
+ )
+
+ review = result.scalar_one_or_none()
+
+ if review is None:
+ raise HTTPException(
+ status_code=404,
+ detail="Redline review not found",
+ )
+
+ # --------------------------------------------------
+ # Prevent duplicate apply
+ # --------------------------------------------------
+
+ if review.status == "applied":
+ raise HTTPException(
+ status_code=409,
+ detail=(
+ "This review has already been applied."
+ ),
+ )
+
+ # --------------------------------------------------
+ # Make sure all findings were reviewed
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineFinding).where(
+ RedlineFinding.review_id == review_id,
+ RedlineFinding.decision == "pending",
+ )
+ )
+
+ pending = result.scalars().all()
+
+ if pending:
+ raise HTTPException(
+ status_code=409,
+ detail=(
+ f"{len(pending)} finding(s) "
+ "still require review."
+ ),
+ )
+
+ # --------------------------------------------------
+ # Load findings
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineFinding)
+ .where(
+ RedlineFinding.review_id == review_id
+ )
+ .order_by(RedlineFinding.created_at)
+ )
+
+ findings = result.scalars().all()
+
+ finding_data = [
+ {
+ "id": str(finding.id),
+ "section": finding.section,
+ "dealer_text": finding.dealer_text,
+ "counter_position": finding.counter_position,
+ "decision": finding.decision,
+ "classification": finding.classification,
+ }
+ for finding in findings
+ ]
+
+ # --------------------------------------------------
+ # Apply approved redlines in SuperDocs
+ # --------------------------------------------------
+
+ client = SuperDocsClient()
+
+ try:
+ result = await apply_approved_redlines(
+ client=client,
+ session_id=review.session_id,
+ findings=finding_data,
+ )
+
+ except Exception as exc:
+ raise HTTPException(
+ status_code=502,
+ detail=f"SuperDocs error: {exc}",
+ )
+
+ # --------------------------------------------------
+ # Mark review as applied
+ # --------------------------------------------------
+
+ review.status = "applied"
+
+ await db.commit()
+
+ return {
+ "review_id": str(review_id),
+ "status": review.status,
+ **result,
+ }
+
+
+@router.post(
+ "/reviews/{review_id}/export"
+)
+async def export_review(
+ review_id: UUID,
+ db: AsyncSession = Depends(get_db),
+):
+ # --------------------------------------------------
+ # Get review
+ # --------------------------------------------------
+
+ result = await db.execute(
+ select(RedlineReview).where(
+ RedlineReview.id == review_id
+ )
+ )
+
+ review = result.scalar_one_or_none()
+
+ if review is None:
+ raise HTTPException(
+ status_code=404,
+ detail="Redline review not found",
+ )
+
+ # --------------------------------------------------
+ # Export only after apply
+ # --------------------------------------------------
+
+ if review.status != "applied":
+ raise HTTPException(
+ status_code=409,
+ detail=(
+ "The review must be applied "
+ "before it can be exported."
+ ),
+ )
+
+ # --------------------------------------------------
+ # Export updated document from SuperDocs
+ #
+ # The review.session_id is the same session used
+ # during /analyze to load the dealer document.
+ # --------------------------------------------------
+
+ client = SuperDocsClient()
+
+ filename = (
+ "dealer-agreement-redlined.docx"
+ )
+
+ try:
+ document_bytes = (
+ await client.export_document(
+ session_id=review.session_id,
+ filename=filename,
+ )
+ )
+
+ except SuperDocsError as exc:
+ raise HTTPException(
+ status_code=502,
+ detail=(
+ f"SuperDocs export failed: {exc}"
+ ),
+ )
+
+ except Exception as exc:
+ raise HTTPException(
+ status_code=502,
+ detail=(
+ f"SuperDocs export failed: {exc}"
+ ),
+ )
+
+ # --------------------------------------------------
+ # Return DOCX
+ # --------------------------------------------------
+
+ return Response(
+ content=document_bytes,
+ media_type=(
+ "application/vnd.openxmlformats-"
+ "officedocument.wordprocessingml.document"
+ ),
+ headers={
+ "Content-Disposition": (
+ f'attachment; filename="{filename}"'
+ ),
+ },
+ )
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/superdocs.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/superdocs.py
new file mode 100644
index 00000000..9d7d3272
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/api/superdocs.py
@@ -0,0 +1,32 @@
+from fastapi import APIRouter, HTTPException
+
+from app.superdocs.client import (
+ SuperDocsClient,
+ SuperDocsError,
+)
+
+
+router = APIRouter(
+ prefix="/superdocs",
+ tags=["superdocs"],
+)
+
+
+@router.get("/health")
+async def superdocs_health():
+ client = SuperDocsClient()
+
+ try:
+ sessions = await client.verify_key()
+
+ return {
+ "status": "ok",
+ "superdocs": "connected",
+ "sessions": sessions,
+ }
+
+ except SuperDocsError as exc:
+ raise HTTPException(
+ status_code=502,
+ detail=str(exc),
+ )
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/config.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/config.py
new file mode 100644
index 00000000..7bea1ca0
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/config.py
@@ -0,0 +1,18 @@
+from functools import lru_cache
+
+from pydantic_settings import BaseSettings, SettingsConfigDict
+
+
+class Settings(BaseSettings):
+ superdocs_api_key: str
+
+ model_config = SettingsConfigDict(
+ env_file=".env",
+ env_file_encoding="utf-8",
+ extra="ignore",
+ )
+
+
+@lru_cache
+def get_settings() -> Settings:
+ return Settings()
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/base.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/base.py
new file mode 100644
index 00000000..1c2dcc40
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/base.py
@@ -0,0 +1,5 @@
+from sqlalchemy.orm import DeclarativeBase
+
+
+class Base(DeclarativeBase):
+ pass
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/init_db.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/init_db.py
new file mode 100644
index 00000000..87e1281c
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/init_db.py
@@ -0,0 +1,14 @@
+from app.db.base import Base
+from app.db.session import engine
+
+from app.models.redline_review import (
+ RedlineReview,
+ RedlineFinding,
+)
+
+
+async def init_db():
+ async with engine.begin() as connection:
+ await connection.run_sync(
+ Base.metadata.create_all
+ )
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/session.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/session.py
new file mode 100644
index 00000000..830045f6
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/db/session.py
@@ -0,0 +1,37 @@
+import os
+
+from dotenv import load_dotenv
+from sqlalchemy.ext.asyncio import (
+ AsyncSession,
+ async_sessionmaker,
+ create_async_engine,
+)
+
+
+load_dotenv()
+
+
+DATABASE_URL = os.getenv("DATABASE_URL")
+
+if not DATABASE_URL:
+ raise RuntimeError(
+ "DATABASE_URL environment variable is not set"
+ )
+
+
+engine = create_async_engine(
+ DATABASE_URL,
+ echo=False,
+)
+
+
+AsyncSessionLocal = async_sessionmaker(
+ engine,
+ class_=AsyncSession,
+ expire_on_commit=False,
+)
+
+
+async def get_db():
+ async with AsyncSessionLocal() as session:
+ yield session
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/main.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/main.py
new file mode 100644
index 00000000..7630d171
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/main.py
@@ -0,0 +1,33 @@
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+
+from app.api.poc import router as poc_router
+from app.api.redline import router as redline_router
+from app.api.superdocs import router as superdocs_router
+
+
+app = FastAPI(
+ title="Dealer Agreement Redline",
+ version="1.0.0",
+)
+
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=[
+ "http://localhost:5173",
+ ],
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+app.include_router(poc_router)
+app.include_router(redline_router)
+app.include_router(superdocs_router)
+
+
+@app.get("/health")
+async def health():
+ return {
+ "status": "ok",
+ }
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/models/redline_review.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/models/redline_review.py
new file mode 100644
index 00000000..f70b3df0
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/models/redline_review.py
@@ -0,0 +1,114 @@
+from datetime import datetime
+from uuid import UUID, uuid4
+
+from sqlalchemy import DateTime, ForeignKey, String, Text, func
+from sqlalchemy.dialects.postgresql import UUID as PG_UUID
+from sqlalchemy.orm import Mapped, mapped_column
+
+from app.db.base import Base
+
+
+class RedlineReview(Base):
+ __tablename__ = "redline_reviews"
+
+ id: Mapped[UUID] = mapped_column(
+ PG_UUID(as_uuid=True),
+ primary_key=True,
+ default=uuid4,
+ )
+
+ session_id: Mapped[str] = mapped_column(
+ String(255),
+ nullable=False,
+ index=True,
+ )
+
+ status: Mapped[str] = mapped_column(
+ String(50),
+ nullable=False,
+ default="pending",
+ )
+
+ created_at: Mapped[datetime] = mapped_column(
+ DateTime(timezone=True),
+ server_default=func.now(),
+ nullable=False,
+ )
+
+ updated_at: Mapped[datetime] = mapped_column(
+ DateTime(timezone=True),
+ server_default=func.now(),
+ onupdate=func.now(),
+ nullable=False,
+ )
+
+
+class RedlineFinding(Base):
+ __tablename__ = "redline_findings"
+
+ id: Mapped[UUID] = mapped_column(
+ PG_UUID(as_uuid=True),
+ primary_key=True,
+ default=uuid4,
+ )
+
+ review_id: Mapped[UUID] = mapped_column(
+ PG_UUID(as_uuid=True),
+ ForeignKey(
+ "redline_reviews.id",
+ ondelete="CASCADE",
+ ),
+ nullable=False,
+ index=True,
+ )
+
+ section: Mapped[str] = mapped_column(
+ String(255),
+ nullable=False,
+ )
+
+ master_text: Mapped[str | None] = mapped_column(
+ Text,
+ nullable=True,
+ )
+
+ dealer_text: Mapped[str | None] = mapped_column(
+ Text,
+ nullable=True,
+ )
+
+ deviation_type: Mapped[str] = mapped_column(
+ String(50),
+ nullable=False,
+ )
+
+ similarity: Mapped[float | None] = mapped_column(
+ nullable=True,
+ )
+
+ classification: Mapped[str] = mapped_column(
+ String(50),
+ nullable=False,
+ )
+
+ reason: Mapped[str] = mapped_column(
+ Text,
+ nullable=False,
+ )
+
+ counter_position: Mapped[str] = mapped_column(
+ Text,
+ nullable=False,
+ )
+
+ decision: Mapped[str] = mapped_column(
+ String(50),
+ nullable=False,
+ default="pending",
+ )
+
+ created_at: Mapped[datetime] = mapped_column(
+ DateTime(timezone=True),
+ server_default=func.now(),
+ nullable=False,
+ )
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/__init__.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/agreement_parser.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/agreement_parser.py
new file mode 100644
index 00000000..5a70343b
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/agreement_parser.py
@@ -0,0 +1,44 @@
+from pathlib import Path
+
+from docx import Document
+
+
+def extract_docx_sections(file_path: str | Path) -> list[dict]:
+ path = Path(file_path)
+
+ if not path.exists():
+ raise FileNotFoundError(
+ f"Document not found: {path}"
+ )
+
+ document = Document(path)
+
+ sections: list[dict] = []
+ current_section: dict | None = None
+
+ for paragraph in document.paragraphs:
+ text = paragraph.text.strip()
+
+ if not text:
+ continue
+
+ # Our test documents use Heading 2 for sections.
+ if paragraph.style.name.startswith("Heading 2"):
+ if current_section:
+ sections.append(current_section)
+
+ current_section = {
+ "section": text,
+ "text": "",
+ }
+
+ elif current_section:
+ if current_section["text"]:
+ current_section["text"] += "\n"
+
+ current_section["text"] += text
+
+ if current_section:
+ sections.append(current_section)
+
+ return sections
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/deviation_analyzer.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/deviation_analyzer.py
new file mode 100644
index 00000000..f8a730bd
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/deviation_analyzer.py
@@ -0,0 +1,69 @@
+from difflib import SequenceMatcher
+
+
+def normalize(text: str) -> str:
+ return " ".join(text.lower().split())
+
+
+def analyze_deviations(
+ master_sections: list[dict],
+ dealer_sections: list[dict],
+) -> list[dict]:
+
+ master_by_section = {
+ item["section"]: item["text"]
+ for item in master_sections
+ }
+
+ dealer_by_section = {
+ item["section"]: item["text"]
+ for item in dealer_sections
+ }
+
+ deviations: list[dict] = []
+
+ for section, dealer_text in dealer_by_section.items():
+ master_text = master_by_section.get(section)
+
+ if master_text is None:
+ deviations.append(
+ {
+ "section": section,
+ "master_text": None,
+ "dealer_text": dealer_text,
+ "deviation_type": "added_section",
+ }
+ )
+ continue
+
+ if normalize(master_text) == normalize(dealer_text):
+ continue
+
+ similarity = SequenceMatcher(
+ None,
+ normalize(master_text),
+ normalize(dealer_text),
+ ).ratio()
+
+ deviations.append(
+ {
+ "section": section,
+ "master_text": master_text,
+ "dealer_text": dealer_text,
+ "deviation_type": "modified_section",
+ "similarity": round(similarity, 3),
+ }
+ )
+
+ for section, master_text in master_by_section.items():
+ if section not in dealer_by_section:
+ deviations.append(
+ {
+ "section": section,
+ "master_text": master_text,
+ "dealer_text": None,
+ "deviation_type": "removed_section",
+ }
+ )
+
+ return deviations
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/playbook_classifier.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/playbook_classifier.py
new file mode 100644
index 00000000..07ba1eb3
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/playbook_classifier.py
@@ -0,0 +1,210 @@
+import re
+
+
+def extract_section_number(section: str) -> str | None:
+ """
+ Extract the numeric section identifier.
+
+ Examples:
+ Section 7.1 — AgreementTerm -> 7.1
+ Section 9.3— Territory -> 9.3
+ Section 12.1 — Termination -> 12.1
+ """
+ match = re.search(
+ r"section\s+(\d+(?:\.\d+)*)",
+ section,
+ re.IGNORECASE,
+ )
+
+ if not match:
+ return None
+
+ return match.group(1)
+
+
+def classify_deviation(
+ deviation: dict,
+) -> dict:
+
+ section = deviation["section"]
+ dealer_text = (
+ deviation.get("dealer_text") or ""
+ ).lower()
+
+ section_number = extract_section_number(section)
+
+ classification = "ESCALATE"
+ reason = "The change requires human review."
+ counter_position = (
+ "Maintain the approved master agreement language."
+ )
+
+ # --------------------------------------------------
+ # Section 4.2 — Payment Terms
+ # --------------------------------------------------
+
+ if section_number == "4.2":
+
+ match = re.search(
+ r"(\d+)\s*days",
+ dealer_text,
+ )
+
+ if match:
+ days = int(match.group(1))
+
+ if days <= 45:
+ classification = "PRE-APPROVED"
+ reason = (
+ "The playbook permits payment terms "
+ "up to 45 days."
+ )
+ counter_position = (
+ f"Accept payment terms of {days} days."
+ )
+
+ else:
+ classification = "ESCALATE"
+ reason = (
+ "The dealer requested payment terms "
+ "above the 45-day pre-approved limit."
+ )
+ counter_position = (
+ "Maintain the standard 30-day payment "
+ "term or escalate the requested "
+ f"{days}-day term for approval."
+ )
+
+ # --------------------------------------------------
+ # Section 7.1 — Agreement Term
+ # --------------------------------------------------
+
+ elif section_number == "7.1":
+
+ year_match = re.search(
+ r"(\d+)\s*years?",
+ dealer_text,
+ )
+
+ if year_match:
+ years = int(year_match.group(1))
+
+ else:
+ word_to_number = {
+ "one": 1,
+ "two": 2,
+ "three": 3,
+ "four": 4,
+ "five": 5,
+ "six": 6,
+ "seven": 7,
+ "eight": 8,
+ "nine": 9,
+ "ten": 10,
+ "eleven": 11,
+ "twelve": 12,
+ "thirteen": 13,
+ "fourteen": 14,
+ "fifteen": 15,
+ }
+
+ years = None
+
+ for word, value in word_to_number.items():
+ if re.search(
+ rf"\b{word}\s+years?\b",
+ dealer_text,
+ ):
+ years = value
+ break
+
+ if years is not None:
+
+ if years <= 7:
+ classification = "PRE-APPROVED"
+
+ reason = (
+ "The playbook permits agreement terms "
+ "up to 7 years."
+ )
+
+ counter_position = (
+ f"Accept the {years}-year agreement term."
+ )
+
+ else:
+ classification = "REFUSE"
+
+ reason = (
+ "The requested agreement term exceeds "
+ "the 7-year playbook limit."
+ )
+
+ counter_position = (
+ "Maintain the approved five-year "
+ "initial agreement term."
+ )
+
+ # --------------------------------------------------
+ # Section 9.3 — Territory
+ # --------------------------------------------------
+
+ elif section_number == "9.3":
+
+ if (
+ "outside" in dealer_text
+ or "expand" in dealer_text
+ ):
+ classification = "ESCALATE"
+ reason = (
+ "The dealer requests an expansion "
+ "of territory rights."
+ )
+ counter_position = (
+ "Maintain the assigned territory unless "
+ "the requested expansion is approved "
+ "through escalation."
+ )
+
+ # --------------------------------------------------
+ # Section 12.1 — Termination
+ # --------------------------------------------------
+
+ elif section_number == "12.1":
+
+ match = re.search(
+ r"(\d+)\s*days",
+ dealer_text,
+ )
+
+ if match:
+ days = int(match.group(1))
+
+ if days > 60:
+ classification = "REFUSE"
+ reason = (
+ "The requested termination notice "
+ "period exceeds the 60-day limit."
+ )
+ counter_position = (
+ "Maintain the approved 30-day "
+ "termination notice period."
+ )
+
+ else:
+ classification = "ESCALATE"
+ reason = (
+ "The termination notice change "
+ "requires review."
+ )
+ counter_position = (
+ "Review the requested termination "
+ "notice period before acceptance."
+ )
+
+ return {
+ **deviation,
+ "classification": classification,
+ "reason": reason,
+ "counter_position": counter_position,
+ }
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/redline_service.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/redline_service.py
new file mode 100644
index 00000000..b26ac613
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/redline_service.py
@@ -0,0 +1,115 @@
+from pathlib import Path
+
+from app.services.agreement_parser import (
+ extract_docx_sections,
+)
+from app.services.deviation_analyzer import (
+ analyze_deviations,
+)
+from app.services.playbook_classifier import (
+ classify_deviation,
+)
+
+from uuid import UUID
+
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from app.models.redline_review import (
+ RedlineFinding,
+ RedlineReview,
+)
+
+
+def analyze_agreements(
+ master_path: str | Path,
+ dealer_path: str | Path,
+ playbook_path: str | Path,
+) -> dict:
+
+ master_sections = extract_docx_sections(
+ master_path
+ )
+
+ dealer_sections = extract_docx_sections(
+ dealer_path
+ )
+
+ playbook_sections = extract_docx_sections(
+ playbook_path
+ )
+
+ deviations = analyze_deviations(
+ master_sections=master_sections,
+ dealer_sections=dealer_sections,
+ )
+
+ classified = [
+ classify_deviation(deviation)
+ for deviation in deviations
+ ]
+
+ return {
+ "master_sections": master_sections,
+ "dealer_sections": dealer_sections,
+ "playbook_sections": playbook_sections,
+ "deviations": classified,
+ "summary": {
+ "total": len(classified),
+ "pre_approved": sum(
+ 1
+ for item in classified
+ if item["classification"]
+ == "PRE-APPROVED"
+ ),
+ "escalate": sum(
+ 1
+ for item in classified
+ if item["classification"]
+ == "ESCALATE"
+ ),
+ "refuse": sum(
+ 1
+ for item in classified
+ if item["classification"]
+ == "REFUSE"
+ ),
+ },
+ }
+
+async def create_redline_review(
+ db: AsyncSession,
+ session_id: str,
+ analysis: dict,
+) -> RedlineReview:
+
+ review = RedlineReview(
+ session_id=session_id,
+ status="pending",
+ )
+
+ db.add(review)
+
+ await db.flush()
+
+ for deviation in analysis["deviations"]:
+ finding = RedlineFinding(
+ review_id=review.id,
+ section=deviation["section"],
+ master_text=deviation.get("master_text"),
+ dealer_text=deviation.get("dealer_text"),
+ deviation_type=deviation["deviation_type"],
+ similarity=deviation.get("similarity"),
+ classification=deviation["classification"],
+ reason=deviation["reason"],
+ counter_position=deviation["counter_position"],
+ decision="pending",
+ )
+
+ db.add(finding)
+
+ await db.commit()
+
+ await db.refresh(review)
+
+ return review
+
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/superdocs_redline.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/superdocs_redline.py
new file mode 100644
index 00000000..afa662a5
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/services/superdocs_redline.py
@@ -0,0 +1,64 @@
+from app.superdocs.client import SuperDocsClient
+
+
+async def apply_approved_redlines(
+ client: SuperDocsClient,
+ session_id: str,
+ findings: list[dict],
+):
+ approved = [
+ finding
+ for finding in findings
+ if finding["decision"] == "approve"
+ ]
+
+ if not approved:
+ return {
+ "applied": False,
+ "message": "No approved findings to apply.",
+ }
+
+ instructions = []
+
+ for finding in approved:
+ instructions.append(
+ f"""
+Section: {finding["section"]}
+
+Current dealer language:
+{finding["dealer_text"]}
+
+Approved counter-position:
+{finding["counter_position"]}
+
+Human decision:
+APPROVED
+""".strip()
+ )
+
+ message = f"""
+Update the active dealer agreement using the
+human-approved redline decisions below.
+
+IMPORTANT:
+- Only modify the sections explicitly listed below.
+- Preserve all other document content.
+- Do not modify formatting unnecessarily.
+- Apply the approved counter-position as the
+ replacement language.
+- Do not invent additional changes.
+
+Approved redlines:
+
+{"\n\n---\n\n".join(instructions)}
+""".strip()
+
+ response = await client.chat(
+ session_id=session_id,
+ message=message,
+ )
+
+ return {
+ "applied": True,
+ "chat_response": response,
+ }
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/superdocs/__init__.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/superdocs/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/superdocs/client.py b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/superdocs/client.py
new file mode 100644
index 00000000..982c9ca5
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/app/superdocs/client.py
@@ -0,0 +1,289 @@
+from pathlib import Path
+from typing import Any
+
+import httpx
+
+from app.config import get_settings
+
+
+class SuperDocsError(Exception):
+ """Raised when the SuperDocs API returns an error."""
+
+
+class SuperDocsClient:
+ BASE_URL = "https://api.superdocs.app/v1"
+
+ def __init__(self) -> None:
+ settings = get_settings()
+
+ self.api_key = settings.superdocs_api_key
+
+ self.headers = {
+ "Authorization": f"Bearer {self.api_key}",
+ }
+
+ async def verify_key(self) -> Any:
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=30.0,
+ ) as client:
+ response = await client.get(
+ "/sessions",
+ headers=self.headers,
+ )
+
+ if response.is_error:
+ raise SuperDocsError(
+ f"SuperDocs authentication failed: "
+ f"{response.status_code} {response.text}"
+ )
+
+ return response.json()
+
+ async def upload_document(
+ self,
+ file_path: str | Path,
+ session_id: str,
+ ) -> dict[str, Any]:
+
+ path = Path(file_path)
+
+ if not path.exists():
+ raise FileNotFoundError(
+ f"Document not found: {path}"
+ )
+
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=120.0,
+ ) as client:
+
+ with path.open("rb") as file:
+ response = await client.post(
+ "/documents/upload",
+ headers=self.headers,
+ files={
+ "file": (
+ path.name,
+ file,
+ self._content_type(path),
+ )
+ },
+ data={
+ "session_id": session_id,
+ },
+ )
+
+ self._raise_for_error(response)
+
+ return response.json()
+
+ async def upload_attachment(
+ self,
+ file_path: str | Path,
+ session_id: str,
+ ) -> dict[str, Any]:
+
+ path = Path(file_path)
+
+ if not path.exists():
+ raise FileNotFoundError(
+ f"Attachment not found: {path}"
+ )
+
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=120.0,
+ ) as client:
+
+ with path.open("rb") as file:
+ response = await client.post(
+ "/attachments/upload",
+ headers=self.headers,
+ files={
+ "file": (
+ path.name,
+ file,
+ self._content_type(path),
+ )
+ },
+ data={
+ "session_id": session_id,
+ },
+ )
+
+ self._raise_for_error(response)
+
+ return response.json()
+
+ async def get_job(
+ self,
+ job_id: str,
+ ) -> dict[str, Any]:
+
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=30.0,
+ ) as client:
+
+ response = await client.get(
+ f"/jobs/{job_id}",
+ headers=self.headers,
+ )
+
+ self._raise_for_error(response)
+
+ return response.json()
+
+ async def chat(
+ self,
+ *,
+ session_id: str,
+ message: str,
+ document_html: str | None = None,
+ document_id: str | None = None,
+ approval_mode: str | None = None,
+ response_mode: str | None = None,
+ ) -> dict[str, Any]:
+
+ payload: dict[str, Any] = {
+ "message": message,
+ "session_id": session_id,
+ }
+
+ if document_html is not None:
+ payload["document_html"] = document_html
+
+ if document_id is not None:
+ payload["document_id"] = document_id
+
+ if approval_mode is not None:
+ payload["approval_mode"] = approval_mode
+
+ if response_mode is not None:
+ payload["response_mode"] = response_mode
+
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=180.0,
+ ) as client:
+
+ response = await client.post(
+ "/chat",
+ headers={
+ **self.headers,
+ "Content-Type": "application/json",
+ },
+ json=payload,
+ )
+
+ self._raise_for_error(response)
+
+ return response.json()
+
+ async def approve_change(
+ self,
+ *,
+ session_id: str,
+ job_id: str,
+ change_id: str,
+ approved: bool,
+ feedback: str | None = None,
+ ) -> dict[str, Any]:
+
+ payload: dict[str, Any] = {
+ "job_id": job_id,
+ "change_id": change_id,
+ "approved": approved,
+ }
+
+ if feedback:
+ payload["feedback"] = feedback
+
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=120.0,
+ ) as client:
+
+ response = await client.post(
+ f"/chat/{session_id}/approve",
+ headers={
+ **self.headers,
+ "Content-Type": "application/json",
+ },
+ json=payload,
+ )
+
+ self._raise_for_error(response)
+
+ return response.json()
+
+ async def export_document(
+ self,
+ *,
+ session_id: str,
+ filename: str,
+ ) -> bytes:
+
+ payload = {
+ "session_id": session_id,
+ "format": "docx",
+ "options": {
+ "filename": filename,
+ },
+ }
+
+ async with httpx.AsyncClient(
+ base_url=self.BASE_URL,
+ timeout=180.0,
+ ) as client:
+
+ response = await client.post(
+ "/documents/export",
+ headers={
+ **self.headers,
+ "Content-Type": "application/json",
+ },
+ json=payload,
+ )
+
+ self._raise_for_error(response)
+
+ return response.content
+
+ @staticmethod
+ def _content_type(path: Path) -> str:
+ suffix = path.suffix.lower()
+
+ mapping = {
+ ".pdf": "application/pdf",
+ ".docx": (
+ "application/vnd.openxmlformats-"
+ "officedocument.wordprocessingml.document"
+ ),
+ ".doc": "application/msword",
+ ".txt": "text/plain",
+ ".html": "text/html",
+ ".htm": "text/html",
+ ".md": "text/markdown",
+ ".rtf": "application/rtf",
+ }
+
+ return mapping.get(
+ suffix,
+ "application/octet-stream",
+ )
+
+ @staticmethod
+ def _raise_for_error(
+ response: httpx.Response,
+ ) -> None:
+
+ if response.is_success:
+ return
+
+ raise SuperDocsError(
+ f"SuperDocs API error "
+ f"{response.status_code}: "
+ f"{response.text}"
+ )
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/backend/requirements.txt b/use-cases/pritesh2564u/dealer-agreement-redline/backend/requirements.txt
new file mode 100644
index 00000000..6f69f070
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/backend/requirements.txt
@@ -0,0 +1,9 @@
+fastapi
+uvicorn[standard]
+httpx
+pydantic
+pydantic-settings
+python-dotenv
+python-multipart
+sqlalchemy
+asyncpg
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/.gitignore b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/.gitignore
new file mode 100644
index 00000000..a547bf36
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/README.md b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/README.md
new file mode 100644
index 00000000..c3001356
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/README.md
@@ -0,0 +1,75 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
+
+## React Compiler
+
+The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
+
+```js
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ // Other configs...
+
+ // Remove tseslint.configs.recommended and replace with this
+ tseslint.configs.recommendedTypeChecked,
+ // Alternatively, use this for stricter rules
+ tseslint.configs.strictTypeChecked,
+ // Optionally, add this for stylistic rules
+ tseslint.configs.stylisticTypeChecked,
+
+ // Other configs...
+ ],
+ languageOptions: {
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ // other options...
+ },
+ },
+])
+
+```
+
+You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
+
+```js
+// eslint.config.js
+import reactX from 'eslint-plugin-react-x'
+import reactDom from 'eslint-plugin-react-dom'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ // Other configs...
+ // Enable lint rules for React
+ reactX.configs['recommended-typescript'],
+ // Enable lint rules for React DOM
+ reactDom.configs.recommended,
+ ],
+ languageOptions: {
+ parserOptions: {
+ project: ['./tsconfig.node.json', './tsconfig.app.json'],
+ tsconfigRootDir: import.meta.dirname,
+ },
+ // other options...
+ },
+ },
+])
+
+```
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/eslint.config.js b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/eslint.config.js
new file mode 100644
index 00000000..ef614d25
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/eslint.config.js
@@ -0,0 +1,22 @@
+import js from '@eslint/js'
+import globals from 'globals'
+import reactHooks from 'eslint-plugin-react-hooks'
+import reactRefresh from 'eslint-plugin-react-refresh'
+import tseslint from 'typescript-eslint'
+import { defineConfig, globalIgnores } from 'eslint/config'
+
+export default defineConfig([
+ globalIgnores(['dist']),
+ {
+ files: ['**/*.{ts,tsx}'],
+ extends: [
+ js.configs.recommended,
+ tseslint.configs.recommended,
+ reactHooks.configs.flat.recommended,
+ reactRefresh.configs.vite,
+ ],
+ languageOptions: {
+ globals: globals.browser,
+ },
+ },
+])
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/index.html b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/index.html
new file mode 100644
index 00000000..0fca6f04
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ frontend
+
+
+
+
+
+
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/package-lock.json b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/package-lock.json
new file mode 100644
index 00000000..f6aebf6b
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/package-lock.json
@@ -0,0 +1,3561 @@
+{
+ "name": "frontend",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "frontend",
+ "version": "0.0.0",
+ "dependencies": {
+ "@tailwindcss/vite": "^4.3.3",
+ "axios": "^1.19.0",
+ "lucide-react": "^1.33.0",
+ "react": "^19.2.8",
+ "react-dom": "^19.2.8",
+ "tailwindcss": "^4.3.3"
+ },
+ "devDependencies": {
+ "@eslint/js": "^10.0.1",
+ "@types/node": "^24.13.3",
+ "@types/react": "^19.2.17",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^6.0.4",
+ "eslint": "^10.8.0",
+ "eslint-plugin-react-hooks": "^7.1.1",
+ "eslint-plugin-react-refresh": "^0.5.3",
+ "globals": "^17.7.0",
+ "typescript": "~6.0.2",
+ "typescript-eslint": "^8.65.0",
+ "vite": "^8.2.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
+ "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz",
+ "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
+ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.7",
+ "@babel/helper-compilation-targets": "^7.29.7",
+ "@babel/helper-module-transforms": "^7.29.7",
+ "@babel/helpers": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/template": "^7.29.7",
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
+ "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.29.8",
+ "@babel/types": "^7.29.8",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz",
+ "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.29.7",
+ "@babel/helper-validator-option": "^7.29.7",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz",
+ "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz",
+ "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz",
+ "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7",
+ "@babel/traverse": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz",
+ "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz",
+ "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
+ "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.29.8"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz",
+ "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/parser": "^7.29.7",
+ "@babel/types": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
+ "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.29.7",
+ "@babel/generator": "^7.29.8",
+ "@babel/helper-globals": "^7.29.7",
+ "@babel/parser": "^7.29.8",
+ "@babel/template": "^7.29.7",
+ "@babel/types": "^7.29.8",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.29.8",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
+ "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz",
+ "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+ }
+ },
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@eslint-community/regexpp": {
+ "version": "4.12.2",
+ "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+ "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@eslint/config-array": {
+ "version": "0.23.5",
+ "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz",
+ "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/object-schema": "^3.0.5",
+ "debug": "^4.3.1",
+ "minimatch": "^10.2.4"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/config-helpers": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz",
+ "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^1.2.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/core": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz",
+ "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/js": {
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz",
+ "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "eslint": "^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz",
+ "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@eslint/plugin-kit": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.2.tgz",
+ "integrity": "sha512-+CNAzxglkrpNf/kKywqQfk74QjtceuOE7Qm+AF8miRvPF/wmmK5+OJOgVh3AVTT3RP2mH3+FOaxlE5v72owk0A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@eslint/core": "^1.2.1",
+ "levn": "^0.4.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ }
+ },
+ "node_modules/@humanfs/core": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
+ "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/types": "^0.15.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/node": {
+ "version": "0.16.8",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz",
+ "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@humanfs/core": "^0.19.2",
+ "@humanfs/types": "^0.15.0",
+ "@humanwhocodes/retry": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanfs/types": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz",
+ "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
+ },
+ "node_modules/@humanwhocodes/module-importer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+ "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=12.22"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz",
+ "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@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==",
+ "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==",
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@oxc-project/types": {
+ "version": "0.146.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.146.0.tgz",
+ "integrity": "sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ }
+ },
+ "node_modules/@rolldown/binding-android-arm-eabi": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz",
+ "integrity": "sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-android-arm64": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz",
+ "integrity": "sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-darwin-arm64": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz",
+ "integrity": "sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-darwin-x64": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz",
+ "integrity": "sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-freebsd-x64": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz",
+ "integrity": "sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz",
+ "integrity": "sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm64-gnu": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz",
+ "integrity": "sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-arm64-musl": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz",
+ "integrity": "sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-ppc64-gnu": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz",
+ "integrity": "sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-s390x-gnu": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz",
+ "integrity": "sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-x64-gnu": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz",
+ "integrity": "sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-linux-x64-musl": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz",
+ "integrity": "sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-openharmony-arm64": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz",
+ "integrity": "sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-arm64-msvc": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz",
+ "integrity": "sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/binding-win32-x64-msvc": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz",
+ "integrity": "sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ }
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
+ "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
+ "license": "MIT"
+ },
+ "node_modules/@tailwindcss/node": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz",
+ "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "enhanced-resolve": "^5.24.1",
+ "jiti": "^2.7.0",
+ "lightningcss": "1.32.0",
+ "magic-string": "^0.30.21",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz",
+ "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 20"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-arm64": "4.3.3",
+ "@tailwindcss/oxide-darwin-x64": "4.3.3",
+ "@tailwindcss/oxide-freebsd-x64": "4.3.3",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.3.3",
+ "@tailwindcss/oxide-linux-x64-musl": "4.3.3",
+ "@tailwindcss/oxide-wasm32-wasi": "4.3.3",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.3.3"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz",
+ "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz",
+ "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz",
+ "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz",
+ "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz",
+ "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz",
+ "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz",
+ "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz",
+ "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz",
+ "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz",
+ "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.11.1",
+ "@emnapi/runtime": "^1.11.1",
+ "@emnapi/wasi-threads": "^1.2.2",
+ "@napi-rs/wasm-runtime": "^1.1.4",
+ "@tybys/wasm-util": "^0.10.2",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz",
+ "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz",
+ "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 20"
+ }
+ },
+ "node_modules/@tailwindcss/vite": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.3.tgz",
+ "integrity": "sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@tailwindcss/node": "4.3.3",
+ "@tailwindcss/oxide": "4.3.3",
+ "tailwindcss": "4.3.3"
+ },
+ "peerDependencies": {
+ "vite": "^5.2.0 || ^6 || ^7 || ^8"
+ }
+ },
+ "node_modules/@types/esrecurse": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz",
+ "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
+ "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.13.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
+ "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.18.0"
+ }
+ },
+ "node_modules/@types/react": {
+ "version": "19.2.18",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
+ "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.2.2"
+ }
+ },
+ "node_modules/@types/react-dom": {
+ "version": "19.2.4",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz",
+ "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.2.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.67.0.tgz",
+ "integrity": "sha512-Un7Heoyj65NREbKAyIrFxeM143NZpExWmy1Nep4DLeQOeLlTeumPjoNKnBrU5D5moWXbPJgRa5Uwcdu0faVNGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.12.2",
+ "@typescript-eslint/scope-manager": "8.67.0",
+ "@typescript-eslint/type-utils": "8.67.0",
+ "@typescript-eslint/utils": "8.67.0",
+ "@typescript-eslint/visitor-keys": "8.67.0",
+ "ignore": "^7.0.5",
+ "natural-compare": "^1.4.0",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^8.67.0",
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz",
+ "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.67.0.tgz",
+ "integrity": "sha512-fUBfTuuEulWqX6V8+O3PtScV01tzYYRUDTAirHFKoRAt7nOzoGiPt0M/bB47wWNy0coOOcgEwAMUtBpykMxl6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.67.0",
+ "@typescript-eslint/types": "8.67.0",
+ "@typescript-eslint/typescript-estree": "8.67.0",
+ "@typescript-eslint/visitor-keys": "8.67.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.67.0.tgz",
+ "integrity": "sha512-cvE8c7ulYeXN9fYuszhCeCsbzyVEXuhrRCybnBre7TUmqb5nRmBfQAwCj0O3WJFDeyAZt4VYv51vMCC9LHSdYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.67.0",
+ "@typescript-eslint/types": "^8.67.0",
+ "debug": "^4.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.67.0.tgz",
+ "integrity": "sha512-EgvsleTwS4E+WzzSvem8fAUubLwatMNF1B5hHSLQxcvs7q2dtRhGyujHwLJSYlG41niJ7GP24Aha2+0mb1b2kg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.67.0",
+ "@typescript-eslint/visitor-keys": "8.67.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/tsconfig-utils": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.67.0.tgz",
+ "integrity": "sha512-vV+LUSv5njUWsknE71fqKTlXUva+R76SaeORd6Zojcunk/6DvKFXONU3BrAs2H49mbygUXt6gbYunzwqNwlhdg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.67.0.tgz",
+ "integrity": "sha512-aVWDXbRmdXO9siTfX4ditQI1T9+zVcNazT48EJCD0v40/9RIFoUgZ05CmGEq9H2gixRpjUn/iplwvlcvutJW/Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.67.0",
+ "@typescript-eslint/typescript-estree": "8.67.0",
+ "@typescript-eslint/utils": "8.67.0",
+ "debug": "^4.4.3",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.67.0.tgz",
+ "integrity": "sha512-sBtgslww8nsMYUjhdPBiSyUqSzT8uR6g93A2QXnQC8+cGdjz0CyaOdqHDRJb1AtORbZCNUJBBeFA/tNR2uQmww==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.67.0.tgz",
+ "integrity": "sha512-EKQBCE9yNlRJYm7jdTW5AhDacDUmSwQb0FAJAmK2EKYrNXIsa2vxcSZx6PvJ/dEdI6lS+Y9W+EXckLj0iPFGcw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.67.0",
+ "@typescript-eslint/tsconfig-utils": "8.67.0",
+ "@typescript-eslint/types": "8.67.0",
+ "@typescript-eslint/visitor-keys": "8.67.0",
+ "debug": "^4.4.3",
+ "minimatch": "^10.2.2",
+ "semver": "^7.7.3",
+ "tinyglobby": "^0.2.15",
+ "ts-api-utils": "^2.5.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.8.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
+ "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.67.0.tgz",
+ "integrity": "sha512-U9D1FdwEWBwok3hxxSdhclMb0twvt9QnjIQ0VfQ1AiX2epnpSgv2ubVDsayOFyY8K6FX+AQ7E0FKWVG3iKsj1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.9.1",
+ "@typescript-eslint/scope-manager": "8.67.0",
+ "@typescript-eslint/types": "8.67.0",
+ "@typescript-eslint/typescript-estree": "8.67.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.67.0.tgz",
+ "integrity": "sha512-fkv8dHRDqfGtTHuJeebdrQ7cX6Ad4WAS00rgHh9UGvMycF1mjBfsxry1XsLIFhWZ6Judlh6UdzK+TYlbpCXgnA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.67.0",
+ "eslint-visitor-keys": "^5.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@vitejs/plugin-react": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.0.tgz",
+ "integrity": "sha512-qd2BzUBehkov86WFhg0JkEFEYyCLG9uPCe6qWTY/kRlss9OvJrOF2UbIWT7p+8IzZHkEu0DNGHc4HSv+JdDLsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rolldown/pluginutils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0",
+ "babel-plugin-react-compiler": "^1.0.0",
+ "oxc-transform-react": "^0.145.0",
+ "vite": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@rolldown/plugin-babel": {
+ "optional": true
+ },
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
+ "oxc-transform-react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
+ "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.15.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
+ "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/axios": {
+ "version": "1.19.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz",
+ "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.16.0",
+ "form-data": "^4.0.6",
+ "https-proxy-agent": "^5.0.1",
+ "proxy-from-env": "^2.1.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.11.15",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.15.tgz",
+ "integrity": "sha512-FwMjJJ7HnyZpWe+oWxegG0fezZyBZUagI5LZEoO3GCbtbKNwRfMH9Ue5d5v01PNePBy1QSfPSDTTeVL0Hb9EzA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.cjs"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "5.0.9",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "20 || >=22"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.28.8",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.8.tgz",
+ "integrity": "sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==",
+ "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.11.12",
+ "caniuse-lite": "^1.0.30001809",
+ "electron-to-chromium": "^1.5.402",
+ "node-releases": "^2.0.53",
+ "update-browserslist-db": "^1.3.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001809",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001809.tgz",
+ "integrity": "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==",
+ "dev": true,
+ "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/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "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",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.411",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.411.tgz",
+ "integrity": "sha512-gglkxzokjHfawpGxq75XdBV2/l3BAPzrsMs70qgaZdTW5rpV1tC4MdgJVP9fN126bODA4ZJQkn1wryEzJyQXIg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.24.5",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
+ "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.3.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz",
+ "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "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/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "10.8.1",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.8.1.tgz",
+ "integrity": "sha512-wqA7W2jbsC/BnV9Iv1UZpKVFkO1AdNoSmYW8NWG4HNOBbkAMvIqDZ27pI2f07dqn583NcIC44ckjAcOXDL1QbQ==",
+ "dev": true,
+ "license": "MIT",
+ "workspaces": [
+ "packages/*"
+ ],
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.8.0",
+ "@eslint-community/regexpp": "^4.12.2",
+ "@eslint/config-array": "^0.23.5",
+ "@eslint/config-helpers": "^0.7.0",
+ "@eslint/core": "^1.2.1",
+ "@eslint/plugin-kit": "^0.7.2",
+ "@humanfs/node": "^0.16.6",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.4.2",
+ "@types/estree": "^1.0.6",
+ "ajv": "^6.14.0",
+ "cross-spawn": "^7.0.6",
+ "debug": "^4.3.2",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^9.1.2",
+ "eslint-visitor-keys": "^5.0.1",
+ "espree": "^11.2.0",
+ "esquery": "^1.7.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^8.0.0",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "minimatch": "^10.2.5",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-plugin-react-hooks": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz",
+ "integrity": "sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.24.4",
+ "@babel/parser": "^7.24.4",
+ "hermes-parser": "^0.25.1",
+ "zod": "^3.25.0 || ^4.0.0",
+ "zod-validation-error": "^3.5.0 || ^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-react-refresh": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.5.4.tgz",
+ "integrity": "sha512-7bqTKz7T0r+HKWFarNXByDE9/5+73wI2ru+M3zuqGbR7s/b/5/pQJXZoufWlrngqGqoZto73ZkGumCdLxk+4rw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "eslint": "^9 || ^10"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz",
+ "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@types/esrecurse": "^4.3.1",
+ "@types/estree": "^1.0.8",
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz",
+ "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz",
+ "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.16.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^5.0.1"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.13.0 || >=24"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
+ "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz",
+ "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
+ "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
+ "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "hasown": "^2.0.4",
+ "mime-types": "^2.1.35"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "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==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "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/globals": {
+ "version": "17.11.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-17.11.0.tgz",
+ "integrity": "sha512-Z2I8hM+PbJDXQDq3Icgpzv+mPdwr68iZUU9d5WW4FuXfDUQfkZaZuvjMv42/5crNyw154+9+VWXbYrUgDXbxNw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/hermes-estree": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz",
+ "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/hermes-parser": {
+ "version": "0.25.1",
+ "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz",
+ "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hermes-estree": "0.25.1"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "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/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/jiti": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz",
+ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==",
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "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==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
+ "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.32.0",
+ "lightningcss-darwin-arm64": "1.32.0",
+ "lightningcss-darwin-x64": "1.32.0",
+ "lightningcss-freebsd-x64": "1.32.0",
+ "lightningcss-linux-arm-gnueabihf": "1.32.0",
+ "lightningcss-linux-arm64-gnu": "1.32.0",
+ "lightningcss-linux-arm64-musl": "1.32.0",
+ "lightningcss-linux-x64-gnu": "1.32.0",
+ "lightningcss-linux-x64-musl": "1.32.0",
+ "lightningcss-win32-arm64-msvc": "1.32.0",
+ "lightningcss-win32-x64-msvc": "1.32.0"
+ }
+ },
+ "node_modules/lightningcss-android-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
+ "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
+ "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
+ "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
+ "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
+ "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
+ "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
+ "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
+ "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
+ "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
+ "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.32.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
+ "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/lucide-react": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.33.0.tgz",
+ "integrity": "sha512-MTRwMy0ZlL8Ur/vOAiJ9XGHE+kFPC7brq6MxAm0GiGXEBj0qy0jA/pG4N675oSzciO/UCdX8T+5yUQdmDeTLxg==",
+ "license": "ISC",
+ "peerDependencies": {
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz",
+ "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.8"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.18",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz",
+ "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==",
+ "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/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.53",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz",
+ "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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": "4.0.5",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz",
+ "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.26",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz",
+ "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==",
+ "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.17",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz",
+ "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/react": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
+ "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-dom": {
+ "version": "19.2.8",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
+ "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
+ "license": "MIT",
+ "dependencies": {
+ "scheduler": "^0.27.0"
+ },
+ "peerDependencies": {
+ "react": "^19.2.8"
+ }
+ },
+ "node_modules/rolldown": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.5.tgz",
+ "integrity": "sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==",
+ "license": "MIT",
+ "dependencies": {
+ "@oxc-project/types": "=0.146.0",
+ "@rolldown/pluginutils": "^1.0.0"
+ },
+ "bin": {
+ "rolldown": "bin/cli.mjs"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "optionalDependencies": {
+ "@rolldown/binding-android-arm-eabi": "1.2.5",
+ "@rolldown/binding-android-arm64": "1.2.5",
+ "@rolldown/binding-darwin-arm64": "1.2.5",
+ "@rolldown/binding-darwin-x64": "1.2.5",
+ "@rolldown/binding-freebsd-x64": "1.2.5",
+ "@rolldown/binding-linux-arm-gnueabihf": "1.2.5",
+ "@rolldown/binding-linux-arm64-gnu": "1.2.5",
+ "@rolldown/binding-linux-arm64-musl": "1.2.5",
+ "@rolldown/binding-linux-ppc64-gnu": "1.2.5",
+ "@rolldown/binding-linux-s390x-gnu": "1.2.5",
+ "@rolldown/binding-linux-x64-gnu": "1.2.5",
+ "@rolldown/binding-linux-x64-musl": "1.2.5",
+ "@rolldown/binding-openharmony-arm64": "1.2.5",
+ "@rolldown/binding-win32-arm64-msvc": "1.2.5",
+ "@rolldown/binding-win32-x64-msvc": "1.2.5"
+ }
+ },
+ "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": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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/tailwindcss": {
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz",
+ "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==",
+ "license": "MIT"
+ },
+ "node_modules/tapable": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
+ "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.17",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
+ "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==",
+ "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/ts-api-utils": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
+ "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.12"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.8.4"
+ }
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
+ "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/typescript-eslint": {
+ "version": "8.67.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.67.0.tgz",
+ "integrity": "sha512-S2udFs8tCKEKffuJ4TB1idGUZiXdCPGi3IPBGWXarbLQ5UPXORV8QEVzJ4gCRduURMb5EkpNCdjbk0eDIuI8Yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "8.67.0",
+ "@typescript-eslint/parser": "8.67.0",
+ "@typescript-eslint/typescript-estree": "8.67.0",
+ "@typescript-eslint/utils": "8.67.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
+ "typescript": ">=4.8.4 <6.1.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz",
+ "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==",
+ "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/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz",
+ "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "lightningcss": "^1.33.0",
+ "picomatch": "^4.0.5",
+ "postcss": "^8.5.26",
+ "rolldown": "~1.2.4",
+ "tinyglobby": "^0.2.17"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "@vitejs/devtools": "^0.4.0 || ^0.5.0",
+ "esbuild": "^0.27.0 || ^0.28.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "@vitejs/devtools": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz",
+ "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==",
+ "license": "MPL-2.0",
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-android-arm64": "1.33.0",
+ "lightningcss-darwin-arm64": "1.33.0",
+ "lightningcss-darwin-x64": "1.33.0",
+ "lightningcss-freebsd-x64": "1.33.0",
+ "lightningcss-linux-arm-gnueabihf": "1.33.0",
+ "lightningcss-linux-arm64-gnu": "1.33.0",
+ "lightningcss-linux-arm64-musl": "1.33.0",
+ "lightningcss-linux-x64-gnu": "1.33.0",
+ "lightningcss-linux-x64-musl": "1.33.0",
+ "lightningcss-win32-arm64-msvc": "1.33.0",
+ "lightningcss-win32-x64-msvc": "1.33.0"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-android-arm64": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz",
+ "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-darwin-arm64": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz",
+ "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-darwin-x64": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz",
+ "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-freebsd-x64": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz",
+ "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz",
+ "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz",
+ "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz",
+ "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz",
+ "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz",
+ "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==",
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "musl"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz",
+ "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.33.0",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz",
+ "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/zod": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz",
+ "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-validation-error": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz",
+ "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "peerDependencies": {
+ "zod": "^3.25.0 || ^4.0.0"
+ }
+ }
+ }
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/package.json b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/package.json
new file mode 100644
index 00000000..0f39a215
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc -b && vite build",
+ "lint": "eslint .",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@tailwindcss/vite": "^4.3.3",
+ "axios": "^1.19.0",
+ "lucide-react": "^1.33.0",
+ "react": "^19.2.8",
+ "react-dom": "^19.2.8",
+ "tailwindcss": "^4.3.3"
+ },
+ "devDependencies": {
+ "@eslint/js": "^10.0.1",
+ "@types/node": "^24.13.3",
+ "@types/react": "^19.2.17",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^6.0.4",
+ "eslint": "^10.8.0",
+ "eslint-plugin-react-hooks": "^7.1.1",
+ "eslint-plugin-react-refresh": "^0.5.3",
+ "globals": "^17.7.0",
+ "typescript": "~6.0.2",
+ "typescript-eslint": "^8.65.0",
+ "vite": "^8.2.0"
+ }
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/public/favicon.svg b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/public/favicon.svg
new file mode 100644
index 00000000..6893eb13
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/public/favicon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/public/icons.svg b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/public/icons.svg
new file mode 100644
index 00000000..e9522193
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/public/icons.svg
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/App.css b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/App.css
new file mode 100644
index 00000000..8c99abd3
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/App.css
@@ -0,0 +1,3 @@
+#root {
+ min-height: 100vh;
+}
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/App.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/App.tsx
new file mode 100644
index 00000000..edf21e9d
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/App.tsx
@@ -0,0 +1,293 @@
+import { useState } from "react";
+
+import {
+ analyzeRedline,
+ applyReview,
+ decideFinding,
+ exportReview,
+ getRedlineReview,
+} from "./api/redline";
+
+import type { AnalyzeResponse, RedlineReview } from "./types/redline";
+
+import ActionBar from "./components/ActionBar";
+import EmptyState from "./components/EmptyState";
+import FindingList from "./components/FindingList";
+import Header from "./components/Header";
+import LoadingState from "./components/LoadingState";
+import ReviewProgress from "./components/ReviewProgress";
+import ReviewSummary from "./components/ReviewSummary";
+import StatusBadge from "./components/StatusBadge";
+import SuccessMessage from "./components/SuccessMessage";
+
+function App() {
+ const [analysis, setAnalysis] = useState(null);
+
+ const [review, setReview] = useState(null);
+
+ const [loading, setLoading] = useState(false);
+
+ const [processingFindingId, setProcessingFindingId] = useState<
+ string | null
+ >(null);
+
+ const [applying, setApplying] = useState(false);
+
+ const [exporting, setExporting] = useState(false);
+
+ const [error, setError] = useState(null);
+
+ const [success, setSuccess] = useState(null);
+
+ async function handleAnalyze(
+ dealerFile: File,
+ masterFile: File,
+ playbookFile: File,
+ ) {
+ setLoading(true);
+ setError(null);
+ setSuccess(null);
+
+ try {
+ const result = await analyzeRedline(
+ dealerFile,
+ masterFile,
+ playbookFile,
+ );
+
+ setAnalysis(result);
+
+ const reviewResult = await getRedlineReview(result.review_id);
+
+ setReview(reviewResult);
+
+ setSuccess("Agreement analysis completed successfully.");
+ } catch (err) {
+ console.error(err);
+
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Failed to analyze the agreement.",
+ );
+ } finally {
+ setLoading(false);
+ }
+ }
+
+ async function handleDecision(
+ findingId: string,
+ decision: "approve" | "reject",
+ ) {
+ if (!review) {
+ return;
+ }
+
+ setProcessingFindingId(findingId);
+ setError(null);
+ setSuccess(null);
+
+ try {
+ const result = await decideFinding(
+ review.review_id,
+ findingId,
+ decision,
+ );
+
+ setReview((current) => {
+ if (!current) {
+ return current;
+ }
+
+ return {
+ ...current,
+ status: result.review_status,
+ findings: current.findings.map((finding) =>
+ finding.id === findingId
+ ? {
+ ...finding,
+ decision: result.decision,
+ }
+ : finding,
+ ),
+ };
+ });
+
+ setSuccess(
+ decision === "approve"
+ ? "Finding approved successfully."
+ : "Finding rejected successfully.",
+ );
+ } catch (err) {
+ console.error(err);
+
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Failed to save the finding decision.",
+ );
+ } finally {
+ setProcessingFindingId(null);
+ }
+ }
+
+ async function handleApply() {
+ if (!review) {
+ return;
+ }
+
+ if (review.status !== "completed") {
+ return;
+ }
+
+ setApplying(true);
+ setError(null);
+ setSuccess(null);
+
+ try {
+ const result = await applyReview(review.review_id);
+
+ setReview((current) => {
+ if (!current) {
+ return current;
+ }
+
+ return {
+ ...current,
+ status: result.status,
+ };
+ });
+
+ setSuccess("Approved changes have been applied successfully.");
+ } catch (err) {
+ console.error(err);
+
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Failed to apply the approved changes.",
+ );
+ } finally {
+ setApplying(false);
+ }
+ }
+
+ async function handleExport() {
+ if (!review) {
+ return;
+ }
+
+ if (review.status !== "applied") {
+ return;
+ }
+
+ setExporting(true);
+ setError(null);
+ setSuccess(null);
+
+ try {
+ const blob = await exportReview(review.review_id);
+
+ const url = window.URL.createObjectURL(blob);
+
+ const link = document.createElement("a");
+
+ link.href = url;
+ link.download = "dealer-agreement-redlined.docx";
+
+ document.body.appendChild(link);
+
+ link.click();
+
+ link.remove();
+
+ window.URL.revokeObjectURL(url);
+
+ setSuccess("Redlined DOCX exported successfully.");
+ } catch (err) {
+ console.error(err);
+
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Failed to export the document.",
+ );
+ } finally {
+ setExporting(false);
+ }
+ }
+
+ const reviewedCount =
+ review?.findings.filter((finding) => finding.decision !== "pending")
+ .length ?? 0;
+
+ return (
+
+
+
+
+ {success && (
+ setSuccess(null)}
+ />
+ )}
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {!analysis && !loading && (
+
+ )}
+
+ {loading && }
+
+ {analysis && review && !loading && (
+
+
+
+
+
+ Review
+
+
+
+ Agreement Findings
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+ );
+}
+
+export default App;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/api/redline.ts b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/api/redline.ts
new file mode 100644
index 00000000..17e9bc91
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/api/redline.ts
@@ -0,0 +1,116 @@
+import type {
+ AnalyzeResponse,
+ ApplyResponse,
+ DecisionResponse,
+ RedlineReview,
+} from "../types/redline";
+
+const API_BASE_URL = "http://localhost:8000";
+
+async function handleResponse(response: Response): Promise {
+ if (!response.ok) {
+ let message = `Request failed with status ${response.status}`;
+
+ try {
+ const data = await response.json();
+
+ if (data.detail) {
+ message = data.detail;
+ }
+ } catch {
+ // Keep default error message.
+ }
+
+ throw new Error(message);
+ }
+
+ return response.json() as Promise;
+}
+
+export async function analyzeRedline(
+ dealerFile: File,
+ masterFile: File,
+ playbookFile: File,
+): Promise {
+ const formData = new FormData();
+
+ formData.append("dealer_file", dealerFile);
+
+ formData.append("master_file", masterFile);
+
+ formData.append("playbook_file", playbookFile);
+
+ const response = await fetch(`${API_BASE_URL}/redline/analyze`, {
+ method: "POST",
+ body: formData,
+ });
+
+ return handleResponse(response);
+}
+
+export async function getRedlineReview(
+ reviewId: string,
+): Promise {
+ const response = await fetch(`${API_BASE_URL}/redline/reviews/${reviewId}`);
+
+ return handleResponse(response);
+}
+
+export async function decideFinding(
+ reviewId: string,
+ findingId: string,
+ decision: "approve" | "reject",
+): Promise {
+ const response = await fetch(
+ `${API_BASE_URL}/redline/reviews/${reviewId}/findings/${findingId}/decision`,
+ {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ decision,
+ }),
+ },
+ );
+
+ return handleResponse(response);
+}
+
+export async function applyReview(reviewId: string): Promise {
+ const response = await fetch(
+ `${API_BASE_URL}/redline/reviews/${reviewId}/apply`,
+ {
+ method: "POST",
+ },
+ );
+
+ return handleResponse(response);
+}
+
+export async function exportReview(reviewId: string): Promise {
+ const response = await fetch(
+ `${API_BASE_URL}/redline/reviews/${reviewId}/export`,
+ {
+ method: "POST",
+ },
+ );
+
+ if (!response.ok) {
+ let message = "Failed to export the document.";
+
+ try {
+ const data = await response.json();
+
+ if (data.detail) {
+ message = data.detail;
+ }
+ } catch {
+ // Response was not JSON.
+ }
+
+ throw new Error(message);
+ }
+
+ return response.blob();
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ActionBar.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ActionBar.tsx
new file mode 100644
index 00000000..009d0db7
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ActionBar.tsx
@@ -0,0 +1,61 @@
+interface ActionBarProps {
+ reviewStatus: string;
+ applying: boolean;
+ exporting: boolean;
+ onApply: () => void;
+ onExport: () => void;
+}
+
+function ActionBar({
+ reviewStatus,
+ applying,
+ exporting,
+ onApply,
+ onExport,
+}: ActionBarProps) {
+ const canApply = reviewStatus === "completed";
+
+ const canExport = reviewStatus === "applied";
+
+ return (
+
+
+
+
+ Review Actions
+
+
+
+ {canApply
+ ? "All findings have been reviewed."
+ : canExport
+ ? "Changes have been applied."
+ : "Review all findings before applying changes."}
+
+
+
+
+
+ {applying ? "Applying..." : "Apply Approved Changes"}
+
+
+
+ {exporting ? "Exporting..." : "Export DOCX"}
+
+
+
+
+ );
+}
+
+export default ActionBar;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ClassificationBadge.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ClassificationBadge.tsx
new file mode 100644
index 00000000..30774250
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ClassificationBadge.tsx
@@ -0,0 +1,25 @@
+import type { Classification } from "../types/redline";
+
+interface ClassificationBadgeProps {
+ classification: Classification;
+}
+
+const classes: Record = {
+ "PRE-APPROVED": "bg-emerald-50 text-emerald-700 border-emerald-200",
+
+ ESCALATE: "bg-amber-50 text-amber-700 border-amber-200",
+
+ REFUSE: "bg-red-50 text-red-700 border-red-200",
+};
+
+function ClassificationBadge({ classification }: ClassificationBadgeProps) {
+ return (
+
+ {classification}
+
+ );
+}
+
+export default ClassificationBadge;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ComparisonBlock.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ComparisonBlock.tsx
new file mode 100644
index 00000000..80fe972f
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ComparisonBlock.tsx
@@ -0,0 +1,18 @@
+interface ComparisonBlockProps {
+ label: string;
+ text: string;
+}
+
+function ComparisonBlock({ label, text }: ComparisonBlockProps) {
+ return (
+
+
+ {label}
+
+
+
{text}
+
+ );
+}
+
+export default ComparisonBlock;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/DocumentUpload.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/DocumentUpload.tsx
new file mode 100644
index 00000000..327c0aae
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/DocumentUpload.tsx
@@ -0,0 +1,155 @@
+import { useState } from "react";
+
+interface DocumentUploadProps {
+ onAnalyze: (dealerFile: File, masterFile: File, playbookFile: File) => void;
+
+ loading: boolean;
+}
+
+interface FilePickerProps {
+ label: string;
+ description: string;
+ file: File | null;
+ onChange: (file: File | null) => void;
+ disabled: boolean;
+}
+
+function FilePicker({
+ label,
+ description,
+ file,
+ onChange,
+ disabled,
+}: FilePickerProps) {
+ function handleChange(event: React.ChangeEvent) {
+ const selectedFile = event.target.files?.[0] ?? null;
+
+ onChange(selectedFile);
+ }
+
+ return (
+
+
+
{label}
+
+
{description}
+
+
+
+
+ {file ? (
+ <>
+
+ {file.name}
+
+
+
+ {(file.size / 1024).toFixed(1)} KB
+
+ >
+ ) : (
+
+ Choose a DOCX file
+
+ )}
+
+
+
+ Browse
+
+
+
+
+
+ );
+}
+
+function DocumentUpload({ onAnalyze, loading }: DocumentUploadProps) {
+ const [dealerFile, setDealerFile] = useState(null);
+
+ const [masterFile, setMasterFile] = useState(null);
+
+ const [playbookFile, setPlaybookFile] = useState(null);
+
+ const canAnalyze =
+ dealerFile !== null &&
+ masterFile !== null &&
+ playbookFile !== null &&
+ !loading;
+
+ function handleAnalyze() {
+ if (!dealerFile || !masterFile || !playbookFile) {
+ return;
+ }
+
+ onAnalyze(dealerFile, masterFile, playbookFile);
+ }
+
+ return (
+
+
+
+ Document Setup
+
+
+
+ Upload agreement documents
+
+
+
+ Upload the dealer agreement, approved master agreement, and
+ negotiation playbook to begin the redline review.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {loading ? "Analyzing..." : "Analyze Agreement"}
+
+
+
+ );
+}
+
+export default DocumentUpload;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/EmptyState.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/EmptyState.tsx
new file mode 100644
index 00000000..4ccf7068
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/EmptyState.tsx
@@ -0,0 +1,28 @@
+import DocumentUpload from "./DocumentUpload";
+
+interface EmptyStateProps {
+ loading: boolean;
+
+ onAnalyze: (dealerFile: File, masterFile: File, playbookFile: File) => void;
+}
+
+function EmptyState({ loading, onAnalyze }: EmptyStateProps) {
+ return (
+
+
+
+ Start a new redline review
+
+
+
+ Provide the three documents required to compare and review
+ the dealer agreement.
+
+
+
+
+
+ );
+}
+
+export default EmptyState;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/FindingCard.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/FindingCard.tsx
new file mode 100644
index 00000000..e88b9312
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/FindingCard.tsx
@@ -0,0 +1,184 @@
+import { Check, ChevronDown, ChevronRight, X } from "lucide-react";
+import { useState } from "react";
+
+import type { FindingDecision, RedlineFinding } from "../types/redline";
+
+import ClassificationBadge from "./ClassificationBadge";
+import ComparisonBlock from "./ComparisonBlock";
+
+interface FindingCardProps {
+ finding: RedlineFinding;
+ index: number;
+ loading?: boolean;
+ onDecision?: (decision: "approve" | "reject") => void;
+}
+
+function FindingCard({
+ finding,
+ index,
+ loading = false,
+ onDecision,
+}: FindingCardProps) {
+ const [expanded, setExpanded] = useState(
+ index === 0 && finding.decision === "pending",
+ );
+
+ const decision: FindingDecision = finding.decision;
+
+ const reviewed = decision !== "pending";
+
+ return (
+
+ {/* Collapsed header */}
+ setExpanded((current) => !current)}
+ className="flex w-full items-center gap-4 px-5 py-4 text-left transition hover:bg-slate-50"
+ aria-expanded={expanded}
+ >
+
+ {expanded ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ Finding {index + 1}
+
+
+
+
+
+
+ {finding.section}
+
+
+
+
+ {decision === "approve" && (
+
+
+ Approved
+
+ )}
+
+ {decision === "reject" && (
+
+
+ Rejected
+
+ )}
+
+ {decision === "pending" && (
+
+ Pending
+
+ )}
+
+
+
+ {/* Expanded content */}
+ {expanded && (
+
+
+
+
+
+
+
+
+
+ Reason
+
+
+
+ {finding.reason}
+
+
+
+
+
+ Counter-position
+
+
+
+ {finding.counter_position}
+
+
+
+ {!reviewed && (
+
+
+ Review this finding before applying changes.
+
+
+
+ onDecision?.("reject")}
+ className="flex items-center justify-center gap-2 rounded-lg border border-red-200 px-4 py-2 text-sm font-medium text-red-700 transition hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-40"
+ >
+
+ Reject
+
+
+ onDecision?.("approve")}
+ className="flex items-center justify-center gap-2 rounded-lg bg-emerald-600 px-4 py-2 text-sm font-medium text-white transition hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-40"
+ >
+
+ {loading ? "Saving..." : "Approve"}
+
+
+
+ )}
+
+ {reviewed && (
+
+
+ {decision === "approve" ? (
+ <>
+
+ Finding approved
+ >
+ ) : (
+ <>
+
+ Finding rejected
+ >
+ )}
+
+
+ )}
+
+ )}
+
+ );
+}
+
+export default FindingCard;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/FindingList.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/FindingList.tsx
new file mode 100644
index 00000000..13a12d50
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/FindingList.tsx
@@ -0,0 +1,52 @@
+import type { RedlineFinding } from "../types/redline";
+
+import FindingCard from "./FindingCard";
+
+interface FindingListProps {
+ findings: RedlineFinding[];
+ processingFindingId?: string | null;
+ onDecision: (findingId: string, decision: "approve" | "reject") => void;
+}
+
+function FindingList({
+ findings,
+ processingFindingId,
+ onDecision,
+}: FindingListProps) {
+ return (
+
+
+
+
+ Findings
+
+
+
+ Expand a finding to review its details.
+
+
+
+
+ {findings.length}{" "}
+ {findings.length === 1 ? "finding" : "findings"}
+
+
+
+
+ {findings.map((finding, index) => (
+
+ onDecision(finding.id, decision)
+ }
+ />
+ ))}
+
+
+ );
+}
+
+export default FindingList;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/Header.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/Header.tsx
new file mode 100644
index 00000000..7c751b51
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/Header.tsx
@@ -0,0 +1,27 @@
+import { FileText } from "lucide-react";
+
+function Header() {
+ return (
+
+
+
+
+
+
+
+
+
+ Dealer Agreement Redline
+
+
+
+ Review and approve contract changes
+
+
+
+
+
+ );
+}
+
+export default Header;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/LoadingState.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/LoadingState.tsx
new file mode 100644
index 00000000..18ba3d99
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/LoadingState.tsx
@@ -0,0 +1,18 @@
+function LoadingState() {
+ return (
+
+
+
+
+ Analyzing agreement
+
+
+
+ Comparing the dealer agreement against the master agreement and
+ playbook.
+
+
+ );
+}
+
+export default LoadingState;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ReviewProgress.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ReviewProgress.tsx
new file mode 100644
index 00000000..94700d72
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ReviewProgress.tsx
@@ -0,0 +1,39 @@
+interface ReviewProgressProps {
+ total: number;
+ reviewed: number;
+}
+
+function ReviewProgress({ total, reviewed }: ReviewProgressProps) {
+ const percentage = total === 0 ? 0 : Math.round((reviewed / total) * 100);
+
+ return (
+
+
+
+
+ Review Progress
+
+
+
+ {reviewed} of {total} findings reviewed
+
+
+
+
+ {percentage}%
+
+
+
+
+
+ );
+}
+
+export default ReviewProgress;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ReviewSummary.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ReviewSummary.tsx
new file mode 100644
index 00000000..13a7b4b2
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/ReviewSummary.tsx
@@ -0,0 +1,22 @@
+import type { ReviewSummary as ReviewSummaryType } from "../types/redline";
+import SummaryCard from "./SummaryCard";
+
+interface ReviewSummaryProps {
+ summary: ReviewSummaryType;
+}
+
+function ReviewSummary({ summary }: ReviewSummaryProps) {
+ return (
+
+ );
+}
+
+export default ReviewSummary;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/StatusBadge.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/StatusBadge.tsx
new file mode 100644
index 00000000..e02220d3
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/StatusBadge.tsx
@@ -0,0 +1,34 @@
+import type { ReviewStatus } from "../types/redline";
+
+interface StatusBadgeProps {
+ status: ReviewStatus;
+}
+
+const styles: Record = {
+ pending: "bg-slate-100 text-slate-600 border-slate-200",
+
+ in_review: "bg-amber-50 text-amber-700 border-amber-200",
+
+ completed: "bg-blue-50 text-blue-700 border-blue-200",
+
+ applied: "bg-emerald-50 text-emerald-700 border-emerald-200",
+};
+
+const labels: Record = {
+ pending: "Pending",
+ in_review: "In Review",
+ completed: "Ready to Apply",
+ applied: "Applied",
+};
+
+function StatusBadge({ status }: StatusBadgeProps) {
+ return (
+
+ {labels[status]}
+
+ );
+}
+
+export default StatusBadge;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/SuccessMessage.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/SuccessMessage.tsx
new file mode 100644
index 00000000..04815bc6
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/SuccessMessage.tsx
@@ -0,0 +1,31 @@
+import { CheckCircle2, X } from "lucide-react";
+
+interface SuccessMessageProps {
+ message: string;
+ onDismiss?: () => void;
+}
+
+function SuccessMessage({ message, onDismiss }: SuccessMessageProps) {
+ return (
+
+
+
+ {onDismiss && (
+
+
+
+ )}
+
+ );
+}
+
+export default SuccessMessage;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/SummaryCard.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/SummaryCard.tsx
new file mode 100644
index 00000000..5bef9f90
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/components/SummaryCard.tsx
@@ -0,0 +1,18 @@
+interface SummaryCardProps {
+ label: string;
+ value: number;
+}
+
+function SummaryCard({ label, value }: SummaryCardProps) {
+ return (
+
+
{label}
+
+
+ {value}
+
+
+ );
+}
+
+export default SummaryCard;
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/index.css b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/index.css
new file mode 100644
index 00000000..82af602b
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/index.css
@@ -0,0 +1,33 @@
+@import "tailwindcss";
+
+:root {
+ font-family:
+ Inter,
+ ui-sans-serif,
+ system-ui,
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ sans-serif;
+
+ color: #111827;
+ background: #f8fafc;
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+html,
+body,
+#root {
+ min-height: 100%;
+ margin: 0;
+}
+
+body {
+ min-width: 320px;
+ background: #f8fafc;
+}
\ No newline at end of file
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/main.tsx b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/main.tsx
new file mode 100644
index 00000000..17cb9016
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/main.tsx
@@ -0,0 +1,11 @@
+import { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+
+import "./index.css";
+import App from "./App";
+
+createRoot(document.getElementById("root")!).render(
+
+
+ ,
+);
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/types/redline.ts b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/types/redline.ts
new file mode 100644
index 00000000..2a236267
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/src/types/redline.ts
@@ -0,0 +1,133 @@
+export type Classification = "PRE-APPROVED" | "ESCALATE" | "REFUSE";
+
+export type FindingDecision = "pending" | "approve" | "reject";
+
+export type ReviewStatus = "pending" | "in_review" | "completed" | "applied";
+
+export interface AgreementSection {
+ section: string;
+ text: string;
+}
+
+export interface Deviation {
+ section: string;
+ master_text: string;
+ dealer_text: string;
+ deviation_type: string;
+ similarity: number;
+ classification: Classification;
+ reason: string;
+ counter_position: string;
+}
+
+export interface ReviewSummary {
+ total: number;
+ pre_approved: number;
+ escalate: number;
+ refuse: number;
+}
+
+export interface AnalyzeResponse {
+ review_id: string;
+ session_id: string;
+
+ dealer_document?: {
+ html: string;
+ session_id: string;
+ filename: string;
+ chunks_count: number;
+ version_id: string;
+ document_id: string;
+ };
+
+ master_attachment?: {
+ job_id: string;
+ filename: string;
+ status: string;
+ message: string;
+ };
+
+ playbook_attachment?: {
+ job_id: string;
+ filename: string;
+ status: string;
+ message: string;
+ };
+
+ master_sections: AgreementSection[];
+ dealer_sections: AgreementSection[];
+ playbook_sections: AgreementSection[];
+ deviations: Deviation[];
+ summary: ReviewSummary;
+}
+
+export interface RedlineFinding extends Deviation {
+ id: string;
+ decision: FindingDecision;
+}
+
+export interface RedlineReview {
+ review_id: string;
+ session_id: string;
+ status: ReviewStatus;
+ created_at: string;
+ updated_at: string;
+ findings: RedlineFinding[];
+}
+
+export interface FindingDecisionRequest {
+ decision: "approve" | "reject";
+}
+
+export interface FindingDecisionResponse {
+ review_id: string;
+ finding_id: string;
+ decision: FindingDecision;
+ review_status: ReviewStatus;
+ remaining_findings: number;
+}
+
+export interface ApplyReviewResponse {
+ review_id: string;
+ status: "applied";
+ applied: boolean;
+ chat_response?: {
+ response?: string;
+ session_id?: string;
+ document_changes?: {
+ updated_html?: string;
+ version_id?: string;
+ changes_summary?: string;
+ requires_approval?: boolean | null;
+ pending_changes?: unknown;
+ changes?: unknown[];
+ chunk_diffs?: unknown;
+ concurrent_merges?: unknown;
+ focused_document_id?: string;
+ };
+ usage?: {
+ ops_charged?: number;
+ monthly_used?: number;
+ monthly_remaining?: number;
+ };
+ };
+}
+
+export interface ApiError {
+ detail: string;
+}
+
+export interface DecisionResponse {
+ review_id: string;
+ finding_id: string;
+ decision: "approve" | "reject";
+ review_status: ReviewStatus;
+ remaining_findings: number;
+}
+
+export interface ApplyResponse {
+ review_id: string;
+ status: "applied";
+ applied: boolean;
+ chat_response: unknown;
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.app.json b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.app.json
new file mode 100644
index 00000000..6830b6f7
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.app.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
+ "target": "es2023",
+ "lib": ["ES2023", "DOM"],
+ "module": "esnext",
+ "types": ["vite/client"],
+ "allowArbitraryExtensions": true,
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src"]
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.json b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.json
new file mode 100644
index 00000000..1ffef600
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "files": [],
+ "references": [
+ { "path": "./tsconfig.app.json" },
+ { "path": "./tsconfig.node.json" }
+ ]
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.node.json b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.node.json
new file mode 100644
index 00000000..8455dcbc
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/tsconfig.node.json
@@ -0,0 +1,23 @@
+{
+ "compilerOptions": {
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
+ "target": "es2023",
+ "lib": ["ES2023"],
+ "types": ["node"],
+ "skipLibCheck": true,
+
+ /* Bundler mode */
+ "module": "nodenext",
+ "allowImportingTsExtensions": true,
+ "verbatimModuleSyntax": true,
+ "moduleDetection": "force",
+ "noEmit": true,
+
+ /* Linting */
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "erasableSyntaxOnly": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/frontend/vite.config.ts b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/vite.config.ts
new file mode 100644
index 00000000..1f4caca4
--- /dev/null
+++ b/use-cases/pritesh2564u/dealer-agreement-redline/frontend/vite.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+import tailwindcss from "@tailwindcss/vite";
+
+export default defineConfig({
+ plugins: [react(), tailwindcss()],
+});
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/test-data/dealer-agreement.docx b/use-cases/pritesh2564u/dealer-agreement-redline/test-data/dealer-agreement.docx
new file mode 100644
index 00000000..398ac0ac
Binary files /dev/null and b/use-cases/pritesh2564u/dealer-agreement-redline/test-data/dealer-agreement.docx differ
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/test-data/master-agreement.docx b/use-cases/pritesh2564u/dealer-agreement-redline/test-data/master-agreement.docx
new file mode 100644
index 00000000..f37070cf
Binary files /dev/null and b/use-cases/pritesh2564u/dealer-agreement-redline/test-data/master-agreement.docx differ
diff --git a/use-cases/pritesh2564u/dealer-agreement-redline/test-data/negotiation-playbook.docx b/use-cases/pritesh2564u/dealer-agreement-redline/test-data/negotiation-playbook.docx
new file mode 100644
index 00000000..8bae9fc3
Binary files /dev/null and b/use-cases/pritesh2564u/dealer-agreement-redline/test-data/negotiation-playbook.docx differ