Spaces:
Sleeping
Sleeping
Merge branch 'genspark_ai_developer'
Browse files- .github/workflows/deploy.yml +22 -23
- .gitignore +50 -0
- README.md +59 -35
- backend/Dockerfile.hf +11 -1
- backend/__pycache__/main.cpython-312.pyc +0 -0
- backend/ai_router/__init__.py +4 -2
- backend/ai_router/key_pool.py +131 -0
- backend/ai_router/router_v8.py +308 -0
- backend/main.py +28 -4
- backend/main_v8.py +326 -0
- frontend/app/globals.css +289 -193
- frontend/app/layout.tsx +9 -7
- frontend/app/page.tsx +60 -58
- frontend/components/dashboard/ActivityFeed.tsx +45 -0
- frontend/components/dashboard/AgentFleetCard.tsx +76 -0
- frontend/components/dashboard/CommandCenter.tsx +81 -0
- frontend/components/dashboard/GodModeCard.tsx +48 -0
- frontend/components/dashboard/MetricCard.tsx +48 -0
- frontend/components/dashboard/MissionInput.tsx +125 -0
- frontend/components/dashboard/SystemResources.tsx +59 -0
- frontend/components/layout/AIRouterPanel.tsx +268 -0
- frontend/components/layout/Sidebar.tsx +2 -1
- frontend/components/pages/AgentsPage.tsx +157 -0
- frontend/components/pages/AnalyticsPage.tsx +121 -0
- frontend/components/pages/DashboardPage.tsx +113 -0
- frontend/components/pages/KnowledgePage.tsx +80 -0
- frontend/components/pages/MemoryPage.tsx +85 -0
- frontend/components/pages/SettingsPage.tsx +154 -0
- frontend/components/pages/TasksPage.tsx +124 -0
- frontend/components/pages/WorkflowsPage.tsx +77 -0
- frontend/components/shared/Sidebar.tsx +142 -0
- frontend/components/shared/TopBar.tsx +181 -0
- frontend/hooks/useAgentStore.ts +1 -1
- frontend/lib/utils.ts +34 -0
- frontend/package-lock.json +1111 -91
- frontend/package.json +9 -2
- frontend/store/useAppStore.ts +131 -0
- frontend/tailwind.config.js +48 -65
- frontend/vercel.json +4 -2
.github/workflows/deploy.yml
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
name: 🚀 God Agent OS
|
| 2 |
|
| 3 |
on:
|
| 4 |
push:
|
|
@@ -10,7 +10,7 @@ env:
|
|
| 10 |
VERCEL_PROJECT: god-agent-os
|
| 11 |
|
| 12 |
jobs:
|
| 13 |
-
# ── Build &
|
| 14 |
build-check:
|
| 15 |
name: ✅ Build Check
|
| 16 |
runs-on: ubuntu-latest
|
|
@@ -28,10 +28,12 @@ jobs:
|
|
| 28 |
cd backend
|
| 29 |
pip install -r requirements.txt
|
| 30 |
|
| 31 |
-
- name: Syntax check backend
|
| 32 |
run: |
|
| 33 |
cd backend
|
| 34 |
-
python -m py_compile
|
|
|
|
|
|
|
| 35 |
python -m py_compile agents/orchestrator_v7.py
|
| 36 |
python -m py_compile agents/browser_agent.py
|
| 37 |
python -m py_compile agents/file_agent.py
|
|
@@ -55,7 +57,7 @@ jobs:
|
|
| 55 |
env:
|
| 56 |
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL || 'https://PYAE1994-autonomous-coding-system.hf.space' }}
|
| 57 |
|
| 58 |
-
# ── Deploy to Hugging Face Spaces ────────────────────────────────────────
|
| 59 |
deploy-huggingface:
|
| 60 |
name: 🤗 Deploy to HF Spaces
|
| 61 |
runs-on: ubuntu-latest
|
|
@@ -72,23 +74,24 @@ jobs:
|
|
| 72 |
git config --global user.email "action@github.com"
|
| 73 |
git config --global user.name "God Agent CI"
|
| 74 |
|
| 75 |
-
- name: Deploy backend to HF Space
|
| 76 |
env:
|
| 77 |
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 78 |
run: |
|
| 79 |
-
# Install HF CLI
|
| 80 |
pip install huggingface_hub -q
|
| 81 |
|
| 82 |
-
# Clone HF space
|
| 83 |
git clone https://pyae1994:$HF_TOKEN@huggingface.co/spaces/PYAE1994/autonomous-coding-system /tmp/hf-space
|
| 84 |
-
|
| 85 |
# Copy backend files
|
| 86 |
cp -r backend/. /tmp/hf-space/
|
| 87 |
-
|
| 88 |
-
#
|
|
|
|
|
|
|
|
|
|
| 89 |
cat > /tmp/hf-space/README.md << 'EOF'
|
| 90 |
---
|
| 91 |
-
title: God Agent OS
|
| 92 |
emoji: 🤖
|
| 93 |
colorFrom: indigo
|
| 94 |
colorTo: purple
|
|
@@ -96,27 +99,23 @@ jobs:
|
|
| 96 |
app_port: 7860
|
| 97 |
pinned: true
|
| 98 |
license: mit
|
| 99 |
-
short_description: Autonomous Engineering OS —
|
| 100 |
---
|
| 101 |
|
| 102 |
-
# 🤖 God Agent OS
|
| 103 |
-
**
|
| 104 |
|
| 105 |
-
16-agent
|
| 106 |
EOF
|
| 107 |
|
| 108 |
-
# Use HF Dockerfile
|
| 109 |
-
cp backend/Dockerfile.hf /tmp/hf-space/Dockerfile
|
| 110 |
-
|
| 111 |
-
# Commit and push
|
| 112 |
cd /tmp/hf-space
|
| 113 |
git add -A
|
| 114 |
-
git diff --cached --quiet || git commit -m "🚀 God Agent OS
|
| 115 |
git push origin main || git push origin master || true
|
| 116 |
-
|
| 117 |
echo "✅ Deployed to HF Space: https://huggingface.co/spaces/PYAE1994/autonomous-coding-system"
|
| 118 |
|
| 119 |
-
# ── Deploy to Vercel ─────────────────────────────────────────────────────
|
| 120 |
deploy-vercel:
|
| 121 |
name: ▲ Deploy to Vercel
|
| 122 |
runs-on: ubuntu-latest
|
|
|
|
| 1 |
+
name: 🚀 God Agent OS v8 — Auto Deploy
|
| 2 |
|
| 3 |
on:
|
| 4 |
push:
|
|
|
|
| 10 |
VERCEL_PROJECT: god-agent-os
|
| 11 |
|
| 12 |
jobs:
|
| 13 |
+
# ── Build & Syntax Check ──────────────────────────────────────────────────
|
| 14 |
build-check:
|
| 15 |
name: ✅ Build Check
|
| 16 |
runs-on: ubuntu-latest
|
|
|
|
| 28 |
cd backend
|
| 29 |
pip install -r requirements.txt
|
| 30 |
|
| 31 |
+
- name: Syntax check backend (v8)
|
| 32 |
run: |
|
| 33 |
cd backend
|
| 34 |
+
python -m py_compile main_v8.py
|
| 35 |
+
python -m py_compile ai_router/router_v8.py
|
| 36 |
+
python -m py_compile ai_router/key_pool.py
|
| 37 |
python -m py_compile agents/orchestrator_v7.py
|
| 38 |
python -m py_compile agents/browser_agent.py
|
| 39 |
python -m py_compile agents/file_agent.py
|
|
|
|
| 57 |
env:
|
| 58 |
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL || 'https://PYAE1994-autonomous-coding-system.hf.space' }}
|
| 59 |
|
| 60 |
+
# ── Deploy to Hugging Face Spaces ────────────────────────────────────────
|
| 61 |
deploy-huggingface:
|
| 62 |
name: 🤗 Deploy to HF Spaces
|
| 63 |
runs-on: ubuntu-latest
|
|
|
|
| 74 |
git config --global user.email "action@github.com"
|
| 75 |
git config --global user.name "God Agent CI"
|
| 76 |
|
| 77 |
+
- name: Deploy backend to HF Space (v8)
|
| 78 |
env:
|
| 79 |
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 80 |
run: |
|
|
|
|
| 81 |
pip install huggingface_hub -q
|
| 82 |
|
|
|
|
| 83 |
git clone https://pyae1994:$HF_TOKEN@huggingface.co/spaces/PYAE1994/autonomous-coding-system /tmp/hf-space
|
| 84 |
+
|
| 85 |
# Copy backend files
|
| 86 |
cp -r backend/. /tmp/hf-space/
|
| 87 |
+
|
| 88 |
+
# Use v8 Dockerfile
|
| 89 |
+
cp backend/Dockerfile.hf /tmp/hf-space/Dockerfile
|
| 90 |
+
|
| 91 |
+
# Create HF README with v8 metadata
|
| 92 |
cat > /tmp/hf-space/README.md << 'EOF'
|
| 93 |
---
|
| 94 |
+
title: God Agent OS v8
|
| 95 |
emoji: 🤖
|
| 96 |
colorFrom: indigo
|
| 97 |
colorTo: purple
|
|
|
|
| 99 |
app_port: 7860
|
| 100 |
pinned: true
|
| 101 |
license: mit
|
| 102 |
+
short_description: Autonomous Engineering OS v8 — KeyPool Multi-API (Gemini + SambaNova)
|
| 103 |
---
|
| 104 |
|
| 105 |
+
# 🤖 God Agent OS v8
|
| 106 |
+
**KeyPool Multi-API Routing — Gemini + SambaNova Primary LLMs**
|
| 107 |
|
| 108 |
+
16-agent autonomous engineering OS with intelligent key pooling.
|
| 109 |
EOF
|
| 110 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
cd /tmp/hf-space
|
| 112 |
git add -A
|
| 113 |
+
git diff --cached --quiet || git commit -m "🚀 God Agent OS v8 deploy $(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
| 114 |
git push origin main || git push origin master || true
|
| 115 |
+
|
| 116 |
echo "✅ Deployed to HF Space: https://huggingface.co/spaces/PYAE1994/autonomous-coding-system"
|
| 117 |
|
| 118 |
+
# ── Deploy to Vercel ─────────────────────────────────────────────────────
|
| 119 |
deploy-vercel:
|
| 120 |
name: ▲ Deploy to Vercel
|
| 121 |
runs-on: ubuntu-latest
|
.gitignore
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dependencies
|
| 2 |
+
node_modules/
|
| 3 |
+
frontend/node_modules/
|
| 4 |
+
__pycache__/
|
| 5 |
+
*.pyc
|
| 6 |
+
*.pyo
|
| 7 |
+
*.pyd
|
| 8 |
+
.Python
|
| 9 |
+
|
| 10 |
+
# Build outputs
|
| 11 |
+
frontend/.next/
|
| 12 |
+
frontend/out/
|
| 13 |
+
dist/
|
| 14 |
+
build/
|
| 15 |
+
*.egg-info/
|
| 16 |
+
|
| 17 |
+
# Environment
|
| 18 |
+
.env
|
| 19 |
+
.env.local
|
| 20 |
+
.env.production
|
| 21 |
+
*.env
|
| 22 |
+
|
| 23 |
+
# Logs
|
| 24 |
+
*.log
|
| 25 |
+
logs/
|
| 26 |
+
|
| 27 |
+
# Database
|
| 28 |
+
*.db
|
| 29 |
+
*.sqlite
|
| 30 |
+
|
| 31 |
+
# OS
|
| 32 |
+
.DS_Store
|
| 33 |
+
Thumbs.db
|
| 34 |
+
|
| 35 |
+
# IDE
|
| 36 |
+
.vscode/
|
| 37 |
+
.idea/
|
| 38 |
+
*.swp
|
| 39 |
+
|
| 40 |
+
# Temporary
|
| 41 |
+
tmp/
|
| 42 |
+
temp/
|
| 43 |
+
/tmp/
|
| 44 |
+
|
| 45 |
+
# Python cache
|
| 46 |
+
backend/__pycache__/
|
| 47 |
+
backend/**/__pycache__/
|
| 48 |
+
backend/ai_router/__pycache__/
|
| 49 |
+
.env.keys
|
| 50 |
+
backend/.env.keys
|
README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
---
|
| 2 |
-
title: God Agent OS
|
| 3 |
emoji: 🤖
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: purple
|
|
@@ -7,24 +7,39 @@ sdk: docker
|
|
| 7 |
app_port: 7860
|
| 8 |
pinned: true
|
| 9 |
license: mit
|
| 10 |
-
short_description: Autonomous Engineering OS —
|
| 11 |
---
|
| 12 |
|
| 13 |
-
# 🤖 GOD AGENT OS
|
| 14 |
**Autonomous Engineering Operating System**
|
| 15 |
-
*Manus + Genspark + Devin (OneHand) —
|
| 16 |
|
| 17 |
[](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
|
| 18 |
-
[.
|
| 59 |
|
| 60 |
## 🌐 API Documentation
|
| 61 |
|
| 62 |
- Interactive docs: `/api/docs`
|
| 63 |
- Health check: `/health`
|
|
|
|
|
|
|
| 64 |
|
| 65 |
## 📦 Architecture
|
| 66 |
|
| 67 |
```
|
| 68 |
god-agent-os/
|
| 69 |
-
├── backend/
|
| 70 |
-
│ ├─
|
| 71 |
-
│ ├── ai_router/
|
| 72 |
-
│ ├──
|
| 73 |
-
│ ├──
|
| 74 |
-
│
|
| 75 |
-
│
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
```
|
| 78 |
|
| 79 |
## 🔄 Auto-Deploy Pipeline
|
| 80 |
|
| 81 |
GitHub Push → Build Check → HF Space Deploy + Vercel Deploy
|
| 82 |
-
|
| 83 |
-
All automatic via GitHub Actions!
|
|
|
|
| 1 |
---
|
| 2 |
+
title: God Agent OS v8
|
| 3 |
emoji: 🤖
|
| 4 |
colorFrom: indigo
|
| 5 |
colorTo: purple
|
|
|
|
| 7 |
app_port: 7860
|
| 8 |
pinned: true
|
| 9 |
license: mit
|
| 10 |
+
short_description: Autonomous Engineering OS v8 — KeyPool Multi-API (Gemini + SambaNova)
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# 🤖 GOD AGENT OS v8
|
| 14 |
**Autonomous Engineering Operating System**
|
| 15 |
+
*Manus + Genspark + Devin (OneHand) — KeyPool Multi-API Edition*
|
| 16 |
|
| 17 |
[](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
|
| 18 |
+
[](https://github.com/pyaesonegtckglay-dotcom/god-agent-os)
|
| 19 |
+
[](https://huggingface.co/spaces/PYAE1994/autonomous-coding-system)
|
| 20 |
|
| 21 |
+
## 🚀 What is God Agent OS v8?
|
| 22 |
|
| 23 |
+
God Agent OS v8 is a fully autonomous AI engineering platform with **KeyPool Multi-API Routing**:
|
| 24 |
+
- **Gemini** (6 keys) — Google Gemini 1.5 Flash primary LLM
|
| 25 |
+
- **SambaNova** (9 keys) — Meta Llama 3.3 70B primary LLM
|
| 26 |
+
- **GitHub API** (9 keys) — Pooled Git operations
|
| 27 |
+
- **Automatic failover** across 7 providers
|
| 28 |
|
| 29 |
+
## 🔑 v8 KeyPool System
|
| 30 |
+
|
| 31 |
+
```
|
| 32 |
+
Priority Chain:
|
| 33 |
+
SambaNova (9 keys) → Gemini (6 keys) → OpenAI → Groq → Cerebras → OpenRouter → Anthropic
|
| 34 |
+
|
| 35 |
+
Each key pool:
|
| 36 |
+
- Round-robin key selection
|
| 37 |
+
- Failure tracking per key
|
| 38 |
+
- Automatic cooldown (60s after 3 failures)
|
| 39 |
+
- Real-time status dashboard in UI
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## 🤖 16-Agent Fleet
|
| 43 |
|
| 44 |
| Agent | Capability | Status |
|
| 45 |
|-------|-----------|--------|
|
|
|
|
| 47 |
| 📋 Planner | Task decomposition & planning | Core |
|
| 48 |
| 💻 Coding | Production code generation | Core |
|
| 49 |
| 🐛 Debug | Self-healing error resolution | Core |
|
| 50 |
+
| 🌐 Browser | Web research & scraping | v7 |
|
| 51 |
+
| 📁 File | File system & project scaffold | v7 |
|
| 52 |
+
| 🔀 Git | Git ops & GitHub PR creation | v7 |
|
| 53 |
+
| 🧪 Test | Auto test generation & execution | v7 |
|
| 54 |
+
| 🎨 Vision | Design-to-code UI generation | v7 |
|
| 55 |
| 🖥️ Sandbox | Isolated code execution | Core |
|
| 56 |
| 🚀 Deploy | Auto-deploy to cloud | Core |
|
| 57 |
| 🔌 Connector | External integrations | Core |
|
| 58 |
| 🧠 Memory | Long-term context | Core |
|
| 59 |
| ⚙️ Workflow | n8n automation | Core |
|
| 60 |
+
| 🔍 Reasoning | Deep reasoning & analysis | Core |
|
| 61 |
+
| 🎨 UI | Real-time UI state | Core |
|
| 62 |
|
| 63 |
+
## 🔑 API Keys Configuration
|
| 64 |
|
| 65 |
+
Set these in Hugging Face Space → Settings → Variables:
|
| 66 |
|
| 67 |
+
| Variable | Description | Keys |
|
| 68 |
+
|----------|-------------|------|
|
| 69 |
+
| `GEMINI_API_KEYS` | Google Gemini (comma-separated) | 6 keys |
|
| 70 |
+
| `SAMBANOVA_API_KEYS` | SambaNova (comma-separated) | 9 keys |
|
| 71 |
+
| `GITHUB_API_KEYS` | GitHub API (comma-separated) | 9 keys |
|
| 72 |
| `OPENAI_API_KEY` | GPT-4o | Optional |
|
| 73 |
+
| `GROQ_API_KEY` | Llama 3.3 70B (Free) | Optional |
|
|
|
|
| 74 |
| `ANTHROPIC_API_KEY` | Claude 3.5 | Optional |
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
## 🌐 API Documentation
|
| 77 |
|
| 78 |
- Interactive docs: `/api/docs`
|
| 79 |
- Health check: `/health`
|
| 80 |
+
- AI Router stats: `/api/v1/ai/stats`
|
| 81 |
+
- Key pool status: `/api/v1/ai/pool-status`
|
| 82 |
|
| 83 |
## 📦 Architecture
|
| 84 |
|
| 85 |
```
|
| 86 |
god-agent-os/
|
| 87 |
+
├── backend/
|
| 88 |
+
│ ├─��� agents/ # 16 specialized agents
|
| 89 |
+
│ ├── ai_router/
|
| 90 |
+
│ │ ├── key_pool.py # KeyPool multi-key manager (NEW v8)
|
| 91 |
+
│ │ ├── router_v8.py # AIRouterV8 with KeyPool (NEW v8)
|
| 92 |
+
│ │ └── router.py # Legacy router (retained)
|
| 93 |
+
│ ├── api/ # REST + WebSocket endpoints
|
| 94 |
+
│ ├── core/ # Task engine & models
|
| 95 |
+
│ ├── memory/ # SQLite persistent memory
|
| 96 |
+
│ ├── connectors/ # External service connectors
|
| 97 |
+
│ ├── main_v8.py # v8 Entry point (NEW)
|
| 98 |
+
│ └── Dockerfile.hf # HF Spaces Docker
|
| 99 |
+
└── frontend/ # Next.js 14 UI
|
| 100 |
+
└── components/
|
| 101 |
+
└── layout/
|
| 102 |
+
└── AIRouterPanel.tsx # v8 Key pool status UI (NEW)
|
| 103 |
```
|
| 104 |
|
| 105 |
## 🔄 Auto-Deploy Pipeline
|
| 106 |
|
| 107 |
GitHub Push → Build Check → HF Space Deploy + Vercel Deploy
|
|
|
|
|
|
backend/Dockerfile.hf
CHANGED
|
@@ -22,6 +22,16 @@ ENV PORT=7860
|
|
| 22 |
ENV WORKSPACE_DIR=/tmp/god_workspace
|
| 23 |
ENV PYTHONPATH=/app
|
| 24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
EXPOSE 7860
|
| 26 |
|
| 27 |
-
CMD ["uvicorn", "
|
|
|
|
| 22 |
ENV WORKSPACE_DIR=/tmp/god_workspace
|
| 23 |
ENV PYTHONPATH=/app
|
| 24 |
|
| 25 |
+
# API Keys are configured via HF Space Secrets (Settings → Variables and Secrets)
|
| 26 |
+
# Set these in your HF Space:
|
| 27 |
+
# GEMINI_API_KEYS — comma-separated Gemini API keys
|
| 28 |
+
# SAMBANOVA_API_KEYS — comma-separated SambaNova API keys
|
| 29 |
+
# GITHUB_API_KEYS — comma-separated GitHub tokens
|
| 30 |
+
# GITHUB_TOKEN — primary GitHub token
|
| 31 |
+
# OPENAI_API_KEY — OpenAI API key (optional)
|
| 32 |
+
# GROQ_API_KEY — Groq API key (optional, free)
|
| 33 |
+
# ANTHROPIC_API_KEY — Anthropic API key (optional)
|
| 34 |
+
|
| 35 |
EXPOSE 7860
|
| 36 |
|
| 37 |
+
CMD ["uvicorn", "main_v8:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
|
backend/__pycache__/main.cpython-312.pyc
DELETED
|
Binary file (9.42 kB)
|
|
|
backend/ai_router/__init__.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
| 1 |
-
# Multi-Model AI Router
|
|
|
|
| 2 |
from .router import AIRouter
|
|
|
|
| 3 |
|
| 4 |
-
__all__ = ["AIRouter"]
|
|
|
|
| 1 |
+
# Multi-Model AI Router — GOD AGENT OS v8
|
| 2 |
+
# Primary: Gemini → Sambanova → GitHub Models (task-aware rotation)
|
| 3 |
from .router import AIRouter
|
| 4 |
+
from .router_v8 import GodModeRouter, get_router, classify_task, get_provider_order
|
| 5 |
|
| 6 |
+
__all__ = ["AIRouter", "GodModeRouter", "get_router", "classify_task", "get_provider_order"]
|
backend/ai_router/key_pool.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
KeyPool — Multi-API Key Manager with Failover & Cooldown
|
| 3 |
+
God Agent OS v8 — Supports Gemini, SambaNova, GitHub, OpenAI, Groq, etc.
|
| 4 |
+
Each provider can have multiple comma-separated keys.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import asyncio
|
| 8 |
+
import time
|
| 9 |
+
from collections import defaultdict
|
| 10 |
+
from typing import Dict, List, Optional
|
| 11 |
+
import structlog
|
| 12 |
+
|
| 13 |
+
log = structlog.get_logger()
|
| 14 |
+
|
| 15 |
+
COOLDOWN_SECONDS = 60 # Key cooling time after max failures
|
| 16 |
+
MAX_FAILURES = 3 # Max fails before cooldown
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
class KeyEntry:
|
| 20 |
+
def __init__(self, key: str):
|
| 21 |
+
self.key = key
|
| 22 |
+
self.failures = 0
|
| 23 |
+
self.cooldown_until = 0.0
|
| 24 |
+
self.calls = 0
|
| 25 |
+
self.last_used = 0.0
|
| 26 |
+
|
| 27 |
+
def is_available(self) -> bool:
|
| 28 |
+
if self.cooldown_until > time.time():
|
| 29 |
+
return False
|
| 30 |
+
return True
|
| 31 |
+
|
| 32 |
+
def mark_fail(self):
|
| 33 |
+
self.failures += 1
|
| 34 |
+
if self.failures >= MAX_FAILURES:
|
| 35 |
+
self.cooldown_until = time.time() + COOLDOWN_SECONDS
|
| 36 |
+
log.warning("Key cooldown activated", failures=self.failures)
|
| 37 |
+
|
| 38 |
+
def mark_success(self):
|
| 39 |
+
self.failures = max(0, self.failures - 1)
|
| 40 |
+
self.cooldown_until = 0.0
|
| 41 |
+
self.calls += 1
|
| 42 |
+
self.last_used = time.time()
|
| 43 |
+
|
| 44 |
+
def status(self) -> dict:
|
| 45 |
+
remaining = max(0, self.cooldown_until - time.time())
|
| 46 |
+
return {
|
| 47 |
+
"key_preview": self.key[:8] + "..." + self.key[-4:] if len(self.key) > 12 else "***",
|
| 48 |
+
"available": self.is_available(),
|
| 49 |
+
"failures": self.failures,
|
| 50 |
+
"calls": self.calls,
|
| 51 |
+
"cooldown_remaining_s": round(remaining, 1),
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
class KeyPool:
|
| 56 |
+
"""
|
| 57 |
+
Pool of API keys for a single provider.
|
| 58 |
+
Round-robins through available keys with failure tracking.
|
| 59 |
+
"""
|
| 60 |
+
|
| 61 |
+
def __init__(self, provider: str, keys: List[str]):
|
| 62 |
+
self.provider = provider
|
| 63 |
+
self._keys: List[KeyEntry] = [KeyEntry(k.strip()) for k in keys if k.strip()]
|
| 64 |
+
self._index = 0
|
| 65 |
+
|
| 66 |
+
def __len__(self) -> int:
|
| 67 |
+
return len(self._keys)
|
| 68 |
+
|
| 69 |
+
def pick(self) -> Optional[str]:
|
| 70 |
+
"""Pick the next available key (round-robin, skip cooling down keys)."""
|
| 71 |
+
if not self._keys:
|
| 72 |
+
return None
|
| 73 |
+
n = len(self._keys)
|
| 74 |
+
for _ in range(n):
|
| 75 |
+
entry = self._keys[self._index % n]
|
| 76 |
+
self._index = (self._index + 1) % n
|
| 77 |
+
if entry.is_available():
|
| 78 |
+
return entry.key
|
| 79 |
+
# All keys in cooldown — try the one with shortest cooldown
|
| 80 |
+
soonest = min(self._keys, key=lambda e: e.cooldown_until)
|
| 81 |
+
log.warning(
|
| 82 |
+
"All keys in cooldown, using soonest",
|
| 83 |
+
provider=self.provider,
|
| 84 |
+
cooldown_remaining=round(soonest.cooldown_until - time.time(), 1),
|
| 85 |
+
)
|
| 86 |
+
return soonest.key
|
| 87 |
+
|
| 88 |
+
def mark_fail(self, key: str):
|
| 89 |
+
for e in self._keys:
|
| 90 |
+
if e.key == key:
|
| 91 |
+
e.mark_fail()
|
| 92 |
+
return
|
| 93 |
+
|
| 94 |
+
def mark_success(self, key: str):
|
| 95 |
+
for e in self._keys:
|
| 96 |
+
if e.key == key:
|
| 97 |
+
e.mark_success()
|
| 98 |
+
return
|
| 99 |
+
|
| 100 |
+
def available_count(self) -> int:
|
| 101 |
+
return sum(1 for e in self._keys if e.is_available())
|
| 102 |
+
|
| 103 |
+
def status(self) -> dict:
|
| 104 |
+
return {
|
| 105 |
+
"provider": self.provider,
|
| 106 |
+
"total_keys": len(self._keys),
|
| 107 |
+
"available_keys": self.available_count(),
|
| 108 |
+
"keys": [e.status() for e in self._keys],
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# ─── Global Key Pool Registry ─────────────────────────────────────────────────
|
| 113 |
+
|
| 114 |
+
class KeyPoolRegistry:
|
| 115 |
+
"""Central registry for all provider key pools."""
|
| 116 |
+
|
| 117 |
+
def __init__(self):
|
| 118 |
+
self._pools: Dict[str, KeyPool] = {}
|
| 119 |
+
|
| 120 |
+
def register(self, provider: str, keys_csv: str):
|
| 121 |
+
"""Register comma-separated keys for a provider."""
|
| 122 |
+
keys = [k.strip() for k in keys_csv.split(",") if k.strip()]
|
| 123 |
+
if keys:
|
| 124 |
+
self._pools[provider] = KeyPool(provider, keys)
|
| 125 |
+
log.info("KeyPool registered", provider=provider, count=len(keys))
|
| 126 |
+
|
| 127 |
+
def get(self, provider: str) -> Optional[KeyPool]:
|
| 128 |
+
return self._pools.get(provider)
|
| 129 |
+
|
| 130 |
+
def all_status(self) -> dict:
|
| 131 |
+
return {name: pool.status() for name, pool in self._pools.items()}
|
backend/ai_router/router_v8.py
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
GOD AGENT OS — Multi-Provider AI Router v8
|
| 3 |
+
Primary Providers (in rotation): Gemini -> Sambanova -> GitHub Models
|
| 4 |
+
Task-aware routing with key pool management, failover, and streaming.
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import asyncio
|
| 8 |
+
import json
|
| 9 |
+
import os
|
| 10 |
+
import time
|
| 11 |
+
from typing import Any, Dict, List, Optional, Tuple
|
| 12 |
+
|
| 13 |
+
import httpx
|
| 14 |
+
import structlog
|
| 15 |
+
|
| 16 |
+
log = structlog.get_logger()
|
| 17 |
+
|
| 18 |
+
# ─── Provider Definitions ─────────────────────────────────────────────────────
|
| 19 |
+
|
| 20 |
+
PROVIDERS = {
|
| 21 |
+
"gemini": {
|
| 22 |
+
"name": "gemini",
|
| 23 |
+
"type": "gemini",
|
| 24 |
+
"base_url": "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent",
|
| 25 |
+
"key_env": "GEMINI_KEY",
|
| 26 |
+
"default_model": "gemini-2.0-flash",
|
| 27 |
+
"max_tokens": 8192,
|
| 28 |
+
"priority_tasks": ["language", "research", "content", "general"],
|
| 29 |
+
},
|
| 30 |
+
"sambanova": {
|
| 31 |
+
"name": "sambanova",
|
| 32 |
+
"type": "openai",
|
| 33 |
+
"base_url": "https://api.sambanova.ai/v1",
|
| 34 |
+
"key_env": "SAMBANOVA_KEY",
|
| 35 |
+
"default_model": "Meta-Llama-3.3-70B-Instruct",
|
| 36 |
+
"max_tokens": 8192,
|
| 37 |
+
"priority_tasks": ["reasoning", "engineering", "planning", "analysis"],
|
| 38 |
+
},
|
| 39 |
+
"github": {
|
| 40 |
+
"name": "github",
|
| 41 |
+
"type": "openai",
|
| 42 |
+
"base_url": "https://models.inference.ai.azure.com",
|
| 43 |
+
"key_env": "GITHUB_KEY",
|
| 44 |
+
"default_model": "gpt-4o",
|
| 45 |
+
"max_tokens": 4096,
|
| 46 |
+
"priority_tasks": ["planning", "engineering", "general"],
|
| 47 |
+
},
|
| 48 |
+
"groq": {
|
| 49 |
+
"name": "groq",
|
| 50 |
+
"type": "openai",
|
| 51 |
+
"base_url": "https://api.groq.com/openai/v1",
|
| 52 |
+
"key_env": "GROQ_API_KEY",
|
| 53 |
+
"default_model": "llama-3.3-70b-versatile",
|
| 54 |
+
"max_tokens": 8192,
|
| 55 |
+
"priority_tasks": ["general"],
|
| 56 |
+
},
|
| 57 |
+
"openai": {
|
| 58 |
+
"name": "openai",
|
| 59 |
+
"type": "openai",
|
| 60 |
+
"base_url": "https://api.openai.com/v1",
|
| 61 |
+
"key_env": "OPENAI_API_KEY",
|
| 62 |
+
"default_model": "gpt-4o",
|
| 63 |
+
"max_tokens": 4096,
|
| 64 |
+
"priority_tasks": ["general"],
|
| 65 |
+
},
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
PRIMARY_ORDER = ["gemini", "sambanova", "github"]
|
| 69 |
+
FALLBACK_ORDER = ["groq", "openai"]
|
| 70 |
+
|
| 71 |
+
MAX_RETRIES_PER_KEY = 2
|
| 72 |
+
KEY_COOLDOWN_SECONDS = 300
|
| 73 |
+
KEY_MAX_FAILS = 3
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
class KeyPool:
|
| 77 |
+
"""Manages a pool of API keys with fail tracking and cooldowns."""
|
| 78 |
+
|
| 79 |
+
def __init__(self, raw_keys: str):
|
| 80 |
+
self._keys: List[Dict] = []
|
| 81 |
+
for k in raw_keys.split(","):
|
| 82 |
+
k = k.strip()
|
| 83 |
+
if k:
|
| 84 |
+
self._keys.append({"key": k, "fails": 0, "cooldown_until": 0.0})
|
| 85 |
+
|
| 86 |
+
def pick(self) -> Optional[Dict]:
|
| 87 |
+
now = time.time()
|
| 88 |
+
available = [k for k in self._keys if k["cooldown_until"] < now]
|
| 89 |
+
if not available:
|
| 90 |
+
return None
|
| 91 |
+
available.sort(key=lambda x: x["fails"])
|
| 92 |
+
return available[0]
|
| 93 |
+
|
| 94 |
+
def mark_fail(self, key_obj: Dict):
|
| 95 |
+
key_obj["fails"] += 1
|
| 96 |
+
if key_obj["fails"] >= KEY_MAX_FAILS:
|
| 97 |
+
key_obj["cooldown_until"] = time.time() + KEY_COOLDOWN_SECONDS
|
| 98 |
+
log.warning("Key cooled down", key_prefix=key_obj["key"][:8])
|
| 99 |
+
|
| 100 |
+
def mark_success(self, key_obj: Dict):
|
| 101 |
+
key_obj["fails"] = 0
|
| 102 |
+
key_obj["cooldown_until"] = 0.0
|
| 103 |
+
|
| 104 |
+
def has_keys(self) -> bool:
|
| 105 |
+
return len(self._keys) > 0
|
| 106 |
+
|
| 107 |
+
def count(self) -> int:
|
| 108 |
+
return len(self._keys)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def classify_task(prompt: str = "") -> str:
|
| 112 |
+
p = prompt.lower()
|
| 113 |
+
if any(w in p for w in ["code", "function", "implement", "build", "develop", "api", "class", "debug"]):
|
| 114 |
+
return "engineering"
|
| 115 |
+
if any(w in p for w in ["plan", "strategy", "workflow", "json", "automate", "pipeline"]):
|
| 116 |
+
return "planning"
|
| 117 |
+
if any(w in p for w in ["analyze", "reasoning", "why", "explain", "evaluate", "compare"]):
|
| 118 |
+
return "reasoning"
|
| 119 |
+
if any(w in p for w in ["research", "find", "search", "discover", "investigate"]):
|
| 120 |
+
return "research"
|
| 121 |
+
if any(w in p for w in ["write", "content", "blog", "article", "copy", "generate text", "summarize"]):
|
| 122 |
+
return "content"
|
| 123 |
+
if any(w in p for w in ["translate", "language", "convert"]):
|
| 124 |
+
return "language"
|
| 125 |
+
if any(w in p for w in ["data", "csv", "metrics", "report", "insight"]):
|
| 126 |
+
return "analysis"
|
| 127 |
+
return "general"
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def get_provider_order(task_type: str) -> List[str]:
|
| 131 |
+
ordered = sorted(PRIMARY_ORDER, key=lambda p: (
|
| 132 |
+
0 if task_type in PROVIDERS[p]["priority_tasks"] else 1
|
| 133 |
+
))
|
| 134 |
+
return ordered + [f for f in FALLBACK_ORDER if os.environ.get(PROVIDERS[f]["key_env"], "")]
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
async def call_gemini(base_url: str, key: str, messages: List[Dict], max_tokens: int) -> Tuple[bool, str]:
|
| 138 |
+
url = f"{base_url}?key={key}"
|
| 139 |
+
parts = []
|
| 140 |
+
for msg in messages:
|
| 141 |
+
parts.append({"text": msg.get("content", "")})
|
| 142 |
+
body = {
|
| 143 |
+
"contents": [{"parts": parts}],
|
| 144 |
+
"generationConfig": {"maxOutputTokens": max_tokens, "temperature": 0.7},
|
| 145 |
+
}
|
| 146 |
+
try:
|
| 147 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
| 148 |
+
resp = await client.post(url, json=body)
|
| 149 |
+
if resp.status_code == 200:
|
| 150 |
+
data = resp.json()
|
| 151 |
+
text = data.get("candidates", [{}])[0].get("content", {}).get("parts", [{}])[0].get("text", "")
|
| 152 |
+
return True, text
|
| 153 |
+
else:
|
| 154 |
+
return False, f"HTTP {resp.status_code}: {resp.text[:200]}"
|
| 155 |
+
except Exception as e:
|
| 156 |
+
return False, str(e)
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
async def call_openai_compat(base_url: str, key: str, model: str, messages: List[Dict], max_tokens: int) -> Tuple[bool, str]:
|
| 160 |
+
url = f"{base_url}/chat/completions"
|
| 161 |
+
headers = {"Authorization": f"Bearer {key}", "Content-Type": "application/json"}
|
| 162 |
+
body = {"model": model, "messages": messages, "max_tokens": max_tokens, "temperature": 0.7}
|
| 163 |
+
try:
|
| 164 |
+
async with httpx.AsyncClient(timeout=60.0) as client:
|
| 165 |
+
resp = await client.post(url, json=body, headers=headers)
|
| 166 |
+
if resp.status_code == 200:
|
| 167 |
+
data = resp.json()
|
| 168 |
+
text = data["choices"][0]["message"]["content"]
|
| 169 |
+
return True, text
|
| 170 |
+
else:
|
| 171 |
+
return False, f"HTTP {resp.status_code}: {resp.text[:200]}"
|
| 172 |
+
except Exception as e:
|
| 173 |
+
return False, str(e)
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
class GodModeRouter:
|
| 177 |
+
"""
|
| 178 |
+
Task-aware multi-provider AI router.
|
| 179 |
+
Primary: Gemini, Sambanova, GitHub Models
|
| 180 |
+
Fallback: Groq, OpenAI
|
| 181 |
+
"""
|
| 182 |
+
|
| 183 |
+
def __init__(self, ws_manager=None):
|
| 184 |
+
self.ws = ws_manager
|
| 185 |
+
self._pools: Dict[str, KeyPool] = {}
|
| 186 |
+
self._stats: Dict[str, Dict] = {name: {"calls": 0, "errors": 0, "latency_ms": []} for name in PROVIDERS}
|
| 187 |
+
self._load_pools()
|
| 188 |
+
|
| 189 |
+
def _load_pools(self):
|
| 190 |
+
for name, cfg in PROVIDERS.items():
|
| 191 |
+
raw = os.environ.get(cfg["key_env"], "")
|
| 192 |
+
if raw:
|
| 193 |
+
self._pools[name] = KeyPool(raw)
|
| 194 |
+
log.info("Key pool loaded", provider=name, key_count=self._pools[name].count())
|
| 195 |
+
|
| 196 |
+
def reload_pools(self):
|
| 197 |
+
self._pools.clear()
|
| 198 |
+
self._load_pools()
|
| 199 |
+
|
| 200 |
+
def get_status(self) -> Dict[str, Any]:
|
| 201 |
+
return {
|
| 202 |
+
"providers": {
|
| 203 |
+
name: {
|
| 204 |
+
"available": name in self._pools and self._pools[name].has_keys(),
|
| 205 |
+
"keys": self._pools[name].count() if name in self._pools else 0,
|
| 206 |
+
"stats": self._stats.get(name, {}),
|
| 207 |
+
}
|
| 208 |
+
for name in PROVIDERS
|
| 209 |
+
},
|
| 210 |
+
"primary_order": PRIMARY_ORDER,
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
# Keep backwards compatibility with old AIRouter interface
|
| 214 |
+
def get_stats(self) -> Dict[str, Any]:
|
| 215 |
+
return {
|
| 216 |
+
name: {"available": name in self._pools, "calls": self._stats[name]["calls"]}
|
| 217 |
+
for name in PROVIDERS
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
async def complete(
|
| 221 |
+
self,
|
| 222 |
+
messages: List[Dict],
|
| 223 |
+
task_id: str = "",
|
| 224 |
+
session_id: str = "",
|
| 225 |
+
temperature: float = 0.7,
|
| 226 |
+
max_tokens: int = 4096,
|
| 227 |
+
preferred_provider: str = "",
|
| 228 |
+
stream: bool = False,
|
| 229 |
+
) -> str:
|
| 230 |
+
user_msg = next((m.get("content", "") for m in reversed(messages) if m.get("role") == "user"), "")
|
| 231 |
+
task_type = classify_task(user_msg)
|
| 232 |
+
|
| 233 |
+
if preferred_provider and preferred_provider in PROVIDERS:
|
| 234 |
+
order = [preferred_provider] + [p for p in get_provider_order(task_type) if p != preferred_provider]
|
| 235 |
+
else:
|
| 236 |
+
order = get_provider_order(task_type)
|
| 237 |
+
|
| 238 |
+
log.info("Routing request", task_type=task_type, order=order[:3], task_id=task_id)
|
| 239 |
+
|
| 240 |
+
last_error = "No providers available"
|
| 241 |
+
|
| 242 |
+
for provider_name in order:
|
| 243 |
+
if provider_name not in self._pools:
|
| 244 |
+
continue
|
| 245 |
+
|
| 246 |
+
pool = self._pools[provider_name]
|
| 247 |
+
cfg = PROVIDERS[provider_name]
|
| 248 |
+
|
| 249 |
+
for attempt in range(MAX_RETRIES_PER_KEY):
|
| 250 |
+
key_obj = pool.pick()
|
| 251 |
+
if key_obj is None:
|
| 252 |
+
break
|
| 253 |
+
|
| 254 |
+
t0 = time.time()
|
| 255 |
+
try:
|
| 256 |
+
if cfg["type"] == "gemini":
|
| 257 |
+
ok, text = await call_gemini(cfg["base_url"], key_obj["key"], messages, max_tokens)
|
| 258 |
+
else:
|
| 259 |
+
ok, text = await call_openai_compat(
|
| 260 |
+
cfg["base_url"], key_obj["key"],
|
| 261 |
+
cfg["default_model"], messages, max_tokens
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
elapsed = int((time.time() - t0) * 1000)
|
| 265 |
+
|
| 266 |
+
if ok and text.strip():
|
| 267 |
+
pool.mark_success(key_obj)
|
| 268 |
+
self._stats[provider_name]["calls"] += 1
|
| 269 |
+
self._stats[provider_name]["latency_ms"].append(elapsed)
|
| 270 |
+
log.info("LLM success", provider=provider_name, ms=elapsed, task_id=task_id)
|
| 271 |
+
return text
|
| 272 |
+
else:
|
| 273 |
+
pool.mark_fail(key_obj)
|
| 274 |
+
last_error = text
|
| 275 |
+
log.warning("LLM fail", provider=provider_name, error=text[:80])
|
| 276 |
+
|
| 277 |
+
except Exception as e:
|
| 278 |
+
pool.mark_fail(key_obj)
|
| 279 |
+
last_error = str(e)
|
| 280 |
+
self._stats[provider_name]["errors"] += 1
|
| 281 |
+
log.error("LLM exception", provider=provider_name, error=str(e)[:120])
|
| 282 |
+
|
| 283 |
+
log.error("All providers failed, using demo response", last_error=last_error)
|
| 284 |
+
return await self._demo_response(messages, task_type)
|
| 285 |
+
|
| 286 |
+
async def _demo_response(self, messages: List[Dict], task_type: str) -> str:
|
| 287 |
+
user_msg = next((m.get("content", "") for m in reversed(messages) if m.get("role") == "user"), "Hello")
|
| 288 |
+
return (
|
| 289 |
+
f"[GOD AGENT OS — Demo Mode]\n\n"
|
| 290 |
+
f"Task type detected: {task_type}\n"
|
| 291 |
+
f"Your request: '{user_msg[:100]}'\n\n"
|
| 292 |
+
f"Configure API keys in environment:\n"
|
| 293 |
+
f"GEMINI_KEY, SAMBANOVA_KEY, GITHUB_KEY"
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
_router_instance: Optional[GodModeRouter] = None
|
| 298 |
+
|
| 299 |
+
|
| 300 |
+
def get_router(ws_manager=None) -> GodModeRouter:
|
| 301 |
+
global _router_instance
|
| 302 |
+
if _router_instance is None:
|
| 303 |
+
_router_instance = GodModeRouter(ws_manager)
|
| 304 |
+
return _router_instance
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
# Backwards compat alias
|
| 308 |
+
AIRouterV8 = GodModeRouter
|
backend/main.py
CHANGED
|
@@ -1,9 +1,31 @@
|
|
| 1 |
"""
|
| 2 |
-
🚀 GOD
|
| 3 |
-
|
| 4 |
-
|
| 5 |
"""
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
import asyncio
|
| 8 |
import json
|
| 9 |
import logging
|
|
@@ -30,6 +52,7 @@ from memory.db import init_db
|
|
| 30 |
|
| 31 |
# ─── God Mode Agents ───────────────────────────────────────────────────────────
|
| 32 |
from ai_router.router import AIRouter
|
|
|
|
| 33 |
from agents.orchestrator import GodAgentOrchestrator
|
| 34 |
from agents.chat_agent import ChatAgent
|
| 35 |
from agents.planner_agent import PlannerAgent
|
|
@@ -61,6 +84,7 @@ limiter = Limiter(key_func=get_remote_address)
|
|
| 61 |
ws_manager = WebSocketManager()
|
| 62 |
task_engine = TaskEngine(ws_manager)
|
| 63 |
ai_router = AIRouter(ws_manager)
|
|
|
|
| 64 |
connector_manager = ConnectorManager()
|
| 65 |
|
| 66 |
# ─── Build God Agent Ecosystem ────────────────────────────────────────────────
|
|
@@ -94,7 +118,7 @@ async def lifespan(app: FastAPI):
|
|
| 94 |
asyncio.create_task(ws_manager.heartbeat_loop())
|
| 95 |
log.info("✅ GOD MODE+ Platform ready — All agents online")
|
| 96 |
log.info("🤖 Agents: Chat, Planner, Coding, Debug, Memory, Connector, Deploy, Workflow, Sandbox, UI")
|
| 97 |
-
log.info("🌐 AI Router:
|
| 98 |
yield
|
| 99 |
log.info("🛑 Shutting down...")
|
| 100 |
await task_engine.stop()
|
|
|
|
| 1 |
"""
|
| 2 |
+
🚀 GOD AGENT OS — Autonomous AI Operating System v8
|
| 3 |
+
Gemini + Sambanova + GitHub Models — Primary Provider Rotation
|
| 4 |
+
Task-aware routing: research→Gemini, code→Sambanova, plan→GitHub
|
| 5 |
"""
|
| 6 |
|
| 7 |
+
# ─── Inject bundled API keys (env vars take precedence) ───────────────────────
|
| 8 |
+
import os as _os
|
| 9 |
+
|
| 10 |
+
def _inject_key(env_var: str, value: str):
|
| 11 |
+
"""Set env var only if not already configured."""
|
| 12 |
+
if not _os.environ.get(env_var):
|
| 13 |
+
_os.environ[env_var] = value
|
| 14 |
+
|
| 15 |
+
# Keys are loaded from HF Space Secrets / Docker env vars.
|
| 16 |
+
# Set GEMINI_KEY, SAMBANOVA_KEY, GITHUB_KEY as comma-separated lists.
|
| 17 |
+
# Fallback: read from .env.keys file if present (not committed to git).
|
| 18 |
+
_keys_file = _os.path.join(_os.path.dirname(__file__), ".env.keys")
|
| 19 |
+
if _os.path.exists(_keys_file):
|
| 20 |
+
with open(_keys_file) as _f:
|
| 21 |
+
for _line in _f:
|
| 22 |
+
_line = _line.strip()
|
| 23 |
+
if _line and "=" in _line and not _line.startswith("#"):
|
| 24 |
+
_k, _v = _line.split("=", 1)
|
| 25 |
+
_inject_key(_k.strip(), _v.strip())
|
| 26 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
| 27 |
+
|
| 28 |
+
|
| 29 |
import asyncio
|
| 30 |
import json
|
| 31 |
import logging
|
|
|
|
| 52 |
|
| 53 |
# ─── God Mode Agents ───────────────────────────────────────────────────────────
|
| 54 |
from ai_router.router import AIRouter
|
| 55 |
+
from ai_router.router_v8 import GodModeRouter, get_router as get_god_router
|
| 56 |
from agents.orchestrator import GodAgentOrchestrator
|
| 57 |
from agents.chat_agent import ChatAgent
|
| 58 |
from agents.planner_agent import PlannerAgent
|
|
|
|
| 84 |
ws_manager = WebSocketManager()
|
| 85 |
task_engine = TaskEngine(ws_manager)
|
| 86 |
ai_router = AIRouter(ws_manager)
|
| 87 |
+
god_router = get_god_router(ws_manager) # v8 primary router
|
| 88 |
connector_manager = ConnectorManager()
|
| 89 |
|
| 90 |
# ─── Build God Agent Ecosystem ────────────────────────────────────────────────
|
|
|
|
| 118 |
asyncio.create_task(ws_manager.heartbeat_loop())
|
| 119 |
log.info("✅ GOD MODE+ Platform ready — All agents online")
|
| 120 |
log.info("🤖 Agents: Chat, Planner, Coding, Debug, Memory, Connector, Deploy, Workflow, Sandbox, UI")
|
| 121 |
+
log.info("🌐 AI Router v8: Gemini → Sambanova → GitHub Models (task-aware rotation)")
|
| 122 |
yield
|
| 123 |
log.info("🛑 Shutting down...")
|
| 124 |
await task_engine.stop()
|
backend/main_v8.py
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
🚀 GOD AGENT OS v8 — Autonomous Engineering Operating System
|
| 3 |
+
Manus + Genspark + Devin (OneHand) Combined
|
| 4 |
+
Version: 8.0.0 — KeyPool Multi-API Routing (Gemini + SambaNova Primary LLMs)
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import asyncio
|
| 8 |
+
import json
|
| 9 |
+
import os
|
| 10 |
+
import time
|
| 11 |
+
import uuid
|
| 12 |
+
from contextlib import asynccontextmanager
|
| 13 |
+
from typing import Optional
|
| 14 |
+
|
| 15 |
+
import structlog
|
| 16 |
+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, Request
|
| 17 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 18 |
+
from fastapi.middleware.gzip import GZipMiddleware
|
| 19 |
+
from fastapi.responses import JSONResponse
|
| 20 |
+
from slowapi import Limiter, _rate_limit_exceeded_handler
|
| 21 |
+
from slowapi.util import get_remote_address
|
| 22 |
+
from slowapi.errors import RateLimitExceeded
|
| 23 |
+
|
| 24 |
+
from api.routes import tasks, chat, memory, github, health
|
| 25 |
+
from api.routes import connectors, agents as agents_router
|
| 26 |
+
from api.websocket_manager import WebSocketManager
|
| 27 |
+
from core.task_engine import TaskEngine
|
| 28 |
+
from memory.db import init_db
|
| 29 |
+
|
| 30 |
+
# ─── v8 AI Router (KeyPool-based) ─────────────────────────────────────────────
|
| 31 |
+
from ai_router.router_v8 import AIRouterV8
|
| 32 |
+
|
| 33 |
+
# ─── Agent Ecosystem ──────────────────────────────────────────────────────────
|
| 34 |
+
from agents.orchestrator_v7 import GodAgentOrchestratorV7
|
| 35 |
+
from agents.chat_agent import ChatAgent
|
| 36 |
+
from agents.planner_agent import PlannerAgent
|
| 37 |
+
from agents.coding_agent import CodingAgent
|
| 38 |
+
from agents.debug_agent import DebugAgent
|
| 39 |
+
from agents.memory_agent import MemoryAgent
|
| 40 |
+
from agents.connector_agent import ConnectorAgent
|
| 41 |
+
from agents.deploy_agent import DeployAgent
|
| 42 |
+
from agents.workflow_agent import WorkflowAgent
|
| 43 |
+
from agents.sandbox_agent import SandboxAgent
|
| 44 |
+
from agents.ui_agent import UIAgent
|
| 45 |
+
from agents.reasoning_agent import ReasoningAgent
|
| 46 |
+
from agents.browser_agent import BrowserAgent
|
| 47 |
+
from agents.file_agent import FileAgent
|
| 48 |
+
from agents.git_agent import GitAgent
|
| 49 |
+
from agents.test_agent import TestAgent
|
| 50 |
+
from agents.vision_agent import VisionAgent
|
| 51 |
+
from connectors.manager import ConnectorManager
|
| 52 |
+
|
| 53 |
+
# ─── Structured Logging ───────────────────────────────────────────────────────
|
| 54 |
+
structlog.configure(
|
| 55 |
+
processors=[
|
| 56 |
+
structlog.processors.TimeStamper(fmt="iso"),
|
| 57 |
+
structlog.stdlib.add_log_level,
|
| 58 |
+
structlog.processors.StackInfoRenderer(),
|
| 59 |
+
structlog.dev.ConsoleRenderer(),
|
| 60 |
+
]
|
| 61 |
+
)
|
| 62 |
+
log = structlog.get_logger()
|
| 63 |
+
|
| 64 |
+
limiter = Limiter(key_func=get_remote_address)
|
| 65 |
+
|
| 66 |
+
# ─── Global Managers ──────────────────────────────────────────────────────────
|
| 67 |
+
ws_manager = WebSocketManager()
|
| 68 |
+
task_engine = TaskEngine(ws_manager)
|
| 69 |
+
ai_router = AIRouterV8(ws_manager)
|
| 70 |
+
connector_manager = ConnectorManager()
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def build_orchestrator() -> GodAgentOrchestratorV7:
|
| 74 |
+
orchestrator = GodAgentOrchestratorV7(ws_manager=ws_manager, ai_router=ai_router)
|
| 75 |
+
orchestrator.register_agent("chat", ChatAgent(ws_manager, ai_router))
|
| 76 |
+
orchestrator.register_agent("planner", PlannerAgent(ws_manager, ai_router))
|
| 77 |
+
orchestrator.register_agent("coding", CodingAgent(ws_manager, ai_router))
|
| 78 |
+
orchestrator.register_agent("debug", DebugAgent(ws_manager, ai_router))
|
| 79 |
+
orchestrator.register_agent("memory", MemoryAgent(ws_manager, ai_router))
|
| 80 |
+
orchestrator.register_agent("connector", ConnectorAgent(ws_manager, ai_router))
|
| 81 |
+
orchestrator.register_agent("deploy", DeployAgent(ws_manager, ai_router))
|
| 82 |
+
orchestrator.register_agent("workflow", WorkflowAgent(ws_manager, ai_router))
|
| 83 |
+
orchestrator.register_agent("sandbox", SandboxAgent(ws_manager, ai_router))
|
| 84 |
+
orchestrator.register_agent("ui", UIAgent(ws_manager, ai_router))
|
| 85 |
+
orchestrator.register_agent("reasoning", ReasoningAgent(ws_manager, ai_router))
|
| 86 |
+
orchestrator.register_agent("browser", BrowserAgent(ws_manager, ai_router))
|
| 87 |
+
orchestrator.register_agent("file", FileAgent(ws_manager, ai_router))
|
| 88 |
+
orchestrator.register_agent("git", GitAgent(ws_manager, ai_router))
|
| 89 |
+
orchestrator.register_agent("test", TestAgent(ws_manager, ai_router))
|
| 90 |
+
orchestrator.register_agent("vision", VisionAgent(ws_manager, ai_router))
|
| 91 |
+
log.info("🤖 GOD AGENT v8 Ecosystem initialized", agents=16)
|
| 92 |
+
return orchestrator
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
orchestrator = build_orchestrator()
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
@asynccontextmanager
|
| 99 |
+
async def lifespan(app: FastAPI):
|
| 100 |
+
log.info("🚀 Starting GOD AGENT OS v8 — KeyPool Multi-API Edition...")
|
| 101 |
+
await init_db()
|
| 102 |
+
await task_engine.start()
|
| 103 |
+
asyncio.create_task(ws_manager.heartbeat_loop())
|
| 104 |
+
# Print router status
|
| 105 |
+
stats = ai_router.get_stats()
|
| 106 |
+
active = [name for name, s in stats.items() if s["available"]]
|
| 107 |
+
log.info("✅ GOD AGENT v8 — 16 agents online")
|
| 108 |
+
log.info(f"🔑 Active AI providers: {active}")
|
| 109 |
+
log.info("🌐 AI Routing: SambaNova → Gemini → OpenAI → Groq → Cerebras → OpenRouter → Anthropic")
|
| 110 |
+
yield
|
| 111 |
+
log.info("🛑 Shutting down GOD AGENT v8...")
|
| 112 |
+
await task_engine.stop()
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
app = FastAPI(
|
| 116 |
+
title="🤖 GOD AGENT OS v8",
|
| 117 |
+
description="Autonomous Engineering OS — Gemini + SambaNova KeyPool Multi-API Routing",
|
| 118 |
+
version="8.0.0",
|
| 119 |
+
lifespan=lifespan,
|
| 120 |
+
docs_url="/api/docs",
|
| 121 |
+
redoc_url="/api/redoc",
|
| 122 |
+
)
|
| 123 |
+
|
| 124 |
+
app.state.limiter = limiter
|
| 125 |
+
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
| 126 |
+
app.state.ws_manager = ws_manager
|
| 127 |
+
app.state.task_engine = task_engine
|
| 128 |
+
app.state.ai_router = ai_router
|
| 129 |
+
app.state.orchestrator = orchestrator
|
| 130 |
+
app.state.connector_manager = connector_manager
|
| 131 |
+
|
| 132 |
+
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
|
| 133 |
+
app.add_middleware(GZipMiddleware, minimum_size=1000)
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
@app.middleware("http")
|
| 137 |
+
async def log_requests(request: Request, call_next):
|
| 138 |
+
start = time.time()
|
| 139 |
+
response = await call_next(request)
|
| 140 |
+
ms = round((time.time() - start) * 1000, 2)
|
| 141 |
+
log.info("HTTP", method=request.method, path=request.url.path, status=response.status_code, ms=ms)
|
| 142 |
+
return response
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
# ─── REST Routers ─────────────────────────────────────────────────────────────
|
| 146 |
+
app.include_router(health.router, prefix="/api/v1", tags=["health"])
|
| 147 |
+
app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"])
|
| 148 |
+
app.include_router(chat.router, prefix="/api/v1", tags=["chat"])
|
| 149 |
+
app.include_router(memory.router, prefix="/api/v1/memory", tags=["memory"])
|
| 150 |
+
app.include_router(github.router, prefix="/api/v1/github", tags=["github"])
|
| 151 |
+
app.include_router(connectors.router, prefix="/api/v1/connectors", tags=["connectors"])
|
| 152 |
+
app.include_router(agents_router.router, prefix="/api/v1/agents", tags=["agents"])
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
# ─── WebSocket Endpoints ──────────────────────────────────────────────────────
|
| 156 |
+
@app.websocket("/ws/tasks/{task_id}")
|
| 157 |
+
async def ws_task(websocket: WebSocket, task_id: str):
|
| 158 |
+
await ws_manager.connect(websocket, room=f"task:{task_id}")
|
| 159 |
+
try:
|
| 160 |
+
while True:
|
| 161 |
+
data = await websocket.receive_text()
|
| 162 |
+
msg = json.loads(data)
|
| 163 |
+
if msg.get("type") == "ping":
|
| 164 |
+
await websocket.send_json({"type": "pong", "timestamp": time.time()})
|
| 165 |
+
except WebSocketDisconnect:
|
| 166 |
+
ws_manager.disconnect(websocket, room=f"task:{task_id}")
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
@app.websocket("/ws/logs")
|
| 170 |
+
async def ws_logs(websocket: WebSocket):
|
| 171 |
+
await ws_manager.connect(websocket, room="logs")
|
| 172 |
+
try:
|
| 173 |
+
while True:
|
| 174 |
+
data = await websocket.receive_text()
|
| 175 |
+
msg = json.loads(data)
|
| 176 |
+
if msg.get("type") == "ping":
|
| 177 |
+
await websocket.send_json({"type": "pong", "timestamp": time.time()})
|
| 178 |
+
except WebSocketDisconnect:
|
| 179 |
+
ws_manager.disconnect(websocket, room="logs")
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
@app.websocket("/ws/chat/{session_id}")
|
| 183 |
+
async def ws_chat(websocket: WebSocket, session_id: str):
|
| 184 |
+
await ws_manager.connect(websocket, room=f"chat:{session_id}")
|
| 185 |
+
try:
|
| 186 |
+
while True:
|
| 187 |
+
data = await websocket.receive_text()
|
| 188 |
+
msg = json.loads(data)
|
| 189 |
+
if msg.get("type") == "ping":
|
| 190 |
+
await websocket.send_json({"type": "pong", "timestamp": time.time()})
|
| 191 |
+
elif msg.get("type") == "chat_message":
|
| 192 |
+
asyncio.create_task(orchestrator.orchestrate(
|
| 193 |
+
user_message=msg.get("content", ""),
|
| 194 |
+
session_id=session_id,
|
| 195 |
+
context=msg.get("context", {}),
|
| 196 |
+
))
|
| 197 |
+
elif msg.get("type") == "task_message":
|
| 198 |
+
from core.models import TaskCreateRequest
|
| 199 |
+
req = TaskCreateRequest(goal=msg.get("content", ""), session_id=session_id)
|
| 200 |
+
asyncio.create_task(task_engine.submit(req))
|
| 201 |
+
except WebSocketDisconnect:
|
| 202 |
+
ws_manager.disconnect(websocket, room=f"chat:{session_id}")
|
| 203 |
+
|
| 204 |
+
|
| 205 |
+
@app.websocket("/ws/agent/status")
|
| 206 |
+
async def ws_agent_status(websocket: WebSocket):
|
| 207 |
+
await ws_manager.connect(websocket, room="agent_status")
|
| 208 |
+
try:
|
| 209 |
+
while True:
|
| 210 |
+
data = await websocket.receive_text()
|
| 211 |
+
msg = json.loads(data)
|
| 212 |
+
if msg.get("type") == "ping":
|
| 213 |
+
await websocket.send_json({"type": "pong", "timestamp": time.time()})
|
| 214 |
+
elif msg.get("type") == "get_status":
|
| 215 |
+
await websocket.send_json({"type": "agent_status", "data": orchestrator.get_status()})
|
| 216 |
+
except WebSocketDisconnect:
|
| 217 |
+
ws_manager.disconnect(websocket, room="agent_status")
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
@app.websocket("/ws/sandbox/{session_id}")
|
| 221 |
+
async def ws_sandbox(websocket: WebSocket, session_id: str):
|
| 222 |
+
await ws_manager.connect(websocket, room=f"sandbox:{session_id}")
|
| 223 |
+
sandbox = orchestrator.get_agent("sandbox")
|
| 224 |
+
try:
|
| 225 |
+
while True:
|
| 226 |
+
data = await websocket.receive_text()
|
| 227 |
+
msg = json.loads(data)
|
| 228 |
+
if msg.get("type") == "ping":
|
| 229 |
+
await websocket.send_json({"type": "pong", "timestamp": time.time()})
|
| 230 |
+
elif msg.get("type") == "execute" and sandbox:
|
| 231 |
+
cmd = msg.get("command", "")
|
| 232 |
+
result = await sandbox.execute(cmd, session_id=session_id)
|
| 233 |
+
await websocket.send_json({"type": "terminal_output", "command": cmd, "output": result, "timestamp": time.time()})
|
| 234 |
+
except WebSocketDisconnect:
|
| 235 |
+
ws_manager.disconnect(websocket, room=f"sandbox:{session_id}")
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
# ─── v8 Key Pool & AI Router Status Endpoints ─────────────────────────────────
|
| 239 |
+
@app.get("/api/v1/ai/stats")
|
| 240 |
+
async def get_ai_stats():
|
| 241 |
+
return {"stats": ai_router.get_stats()}
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
@app.get("/api/v1/ai/pool-status")
|
| 245 |
+
async def get_pool_status():
|
| 246 |
+
return {"pools": ai_router.get_pool_status()}
|
| 247 |
+
|
| 248 |
+
|
| 249 |
+
@app.post("/api/v1/browser/research")
|
| 250 |
+
async def browser_research(request: Request):
|
| 251 |
+
body = await request.json()
|
| 252 |
+
browser = orchestrator.get_agent("browser")
|
| 253 |
+
if not browser:
|
| 254 |
+
raise HTTPException(status_code=503, detail="BrowserAgent not available")
|
| 255 |
+
result = await browser.run(body.get("query", ""), session_id=body.get("session_id", ""))
|
| 256 |
+
return {"result": result}
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
@app.get("/api/v1/files/workspace")
|
| 260 |
+
async def list_workspace():
|
| 261 |
+
file_agent = orchestrator.get_agent("file")
|
| 262 |
+
if not file_agent:
|
| 263 |
+
return {"workspace": "/tmp/god_workspace", "files": [], "total": 0}
|
| 264 |
+
return file_agent.list_workspace()
|
| 265 |
+
|
| 266 |
+
|
| 267 |
+
@app.post("/api/v1/git/pr")
|
| 268 |
+
async def create_pr(request: Request):
|
| 269 |
+
body = await request.json()
|
| 270 |
+
git_agent = orchestrator.get_agent("git")
|
| 271 |
+
if not git_agent:
|
| 272 |
+
raise HTTPException(status_code=503, detail="GitAgent not available")
|
| 273 |
+
result = await git_agent.create_github_pr(
|
| 274 |
+
repo_owner=body.get("owner", ""),
|
| 275 |
+
repo_name=body.get("repo", ""),
|
| 276 |
+
title=body.get("title", ""),
|
| 277 |
+
body=body.get("body", ""),
|
| 278 |
+
head_branch=body.get("head_branch", "main"),
|
| 279 |
+
base_branch=body.get("base_branch", "main"),
|
| 280 |
+
)
|
| 281 |
+
return result
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
@app.post("/api/v1/vision/generate")
|
| 285 |
+
async def generate_ui(request: Request):
|
| 286 |
+
body = await request.json()
|
| 287 |
+
vision = orchestrator.get_agent("vision")
|
| 288 |
+
if not vision:
|
| 289 |
+
raise HTTPException(status_code=503, detail="VisionAgent not available")
|
| 290 |
+
result = await vision.run(body.get("prompt", ""), context=body.get("context", {}), session_id=body.get("session_id", ""))
|
| 291 |
+
return {"result": result}
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
# ─── Root ─────────────────────────────────────────────────────────────────────
|
| 295 |
+
@app.get("/")
|
| 296 |
+
async def root():
|
| 297 |
+
cs = connector_manager.get_summary()
|
| 298 |
+
status = orchestrator.get_status()
|
| 299 |
+
stats = ai_router.get_stats()
|
| 300 |
+
active_providers = [name for name, s in stats.items() if s["available"]]
|
| 301 |
+
return {
|
| 302 |
+
"name": "🤖 GOD AGENT OS v8",
|
| 303 |
+
"version": "8.0.0",
|
| 304 |
+
"status": "operational",
|
| 305 |
+
"mode": "autonomous_engineering_os",
|
| 306 |
+
"description": "KeyPool Multi-API Routing — Gemini + SambaNova Primary LLMs",
|
| 307 |
+
"agents": status["agents"],
|
| 308 |
+
"total_agents": status["total_agents"],
|
| 309 |
+
"ai_providers": active_providers,
|
| 310 |
+
"connectors": {"connected": cs["connected"], "total": cs["total"]},
|
| 311 |
+
"docs": "/api/docs",
|
| 312 |
+
"v8_features": [
|
| 313 |
+
"🔑 KeyPool multi-key management (Gemini 6 keys + SambaNova 9 keys)",
|
| 314 |
+
"🔄 Automatic key failover with cooldown tracking",
|
| 315 |
+
"⚡ SambaNova → Gemini → OpenAI → Groq → Cerebras chain",
|
| 316 |
+
"📊 Per-key usage stats & health monitoring",
|
| 317 |
+
"🤖 16-agent autonomous fleet",
|
| 318 |
+
"🌐 Real-time streaming via WebSocket",
|
| 319 |
+
],
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
|
| 323 |
+
if __name__ == "__main__":
|
| 324 |
+
import uvicorn
|
| 325 |
+
port = int(os.environ.get("PORT", 8000))
|
| 326 |
+
uvicorn.run("main_v8:app", host="0.0.0.0", port=port, reload=False, workers=1)
|
frontend/app/globals.css
CHANGED
|
@@ -2,235 +2,331 @@
|
|
| 2 |
@tailwind components;
|
| 3 |
@tailwind utilities;
|
| 4 |
|
| 5 |
-
|
|
|
|
| 6 |
|
| 7 |
-
/* ─── CSS Variables
|
| 8 |
:root {
|
| 9 |
-
--
|
| 10 |
-
--
|
| 11 |
-
--
|
| 12 |
-
--
|
| 13 |
-
--
|
| 14 |
-
--
|
| 15 |
-
--
|
| 16 |
-
--
|
| 17 |
-
--text-
|
| 18 |
-
--
|
| 19 |
-
--
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
--
|
| 24 |
-
--
|
| 25 |
-
--
|
| 26 |
-
--
|
| 27 |
-
--
|
| 28 |
-
--
|
| 29 |
-
--
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
[data-theme="amoled"] {
|
| 37 |
-
--bg-0: #000000;
|
| 38 |
-
--bg-1: #000000;
|
| 39 |
-
--bg-2: #0a0a0a;
|
| 40 |
-
--bg-3: #111111;
|
| 41 |
-
--bg-4: #161616;
|
| 42 |
-
--border: #222222;
|
| 43 |
-
--text-primary: #ffffff;
|
| 44 |
-
--text-secondary: #aaaaaa;
|
| 45 |
-
--text-muted: #555555;
|
| 46 |
-
--brand: #7c3aed;
|
| 47 |
-
--brand-glow: rgba(124,58,237,0.4);
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
-
[data-theme="neon"] {
|
| 51 |
-
--bg-0: #000510;
|
| 52 |
-
--bg-1: #010a1a;
|
| 53 |
-
--bg-2: #020d20;
|
| 54 |
-
--bg-3: #031226;
|
| 55 |
-
--bg-4: #04162c;
|
| 56 |
-
--border: #0d3060;
|
| 57 |
-
--text-primary: #e0f0ff;
|
| 58 |
-
--text-secondary: #7ab8f5;
|
| 59 |
-
--text-muted: #2a5a8a;
|
| 60 |
-
--brand: #00d4ff;
|
| 61 |
-
--brand-glow: rgba(0,212,255,0.4);
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
-
[data-theme="glass"] {
|
| 65 |
-
--bg-0: #0d0d1a;
|
| 66 |
-
--bg-1: #111122;
|
| 67 |
-
--bg-2: #161630;
|
| 68 |
-
--bg-3: rgba(255,255,255,0.04);
|
| 69 |
-
--bg-4: rgba(255,255,255,0.06);
|
| 70 |
-
--border: rgba(255,255,255,0.08);
|
| 71 |
-
--text-primary: #f0f0ff;
|
| 72 |
-
--text-secondary: #9090c0;
|
| 73 |
-
--text-muted: #5050a0;
|
| 74 |
-
--brand: #818cf8;
|
| 75 |
-
--brand-glow: rgba(129,140,248,0.3);
|
| 76 |
-
}
|
| 77 |
-
|
| 78 |
-
/* ─── Base ────────────────────────────────────────────────────────────────── */
|
| 79 |
-
* { box-sizing: border-box; }
|
| 80 |
-
|
| 81 |
-
html { font-family: 'Inter', system-ui, sans-serif; }
|
| 82 |
|
| 83 |
body {
|
| 84 |
-
background: var(--
|
| 85 |
color: var(--text-primary);
|
| 86 |
-
|
| 87 |
-
padding: 0;
|
| 88 |
overflow: hidden;
|
| 89 |
height: 100vh;
|
|
|
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
/* ─── Scrollbar ───────────────────────────────────────────────────────────── */
|
| 93 |
-
::-webkit-scrollbar { width:
|
| 94 |
::-webkit-scrollbar-track { background: transparent; }
|
| 95 |
-
::-webkit-scrollbar-thumb { background:
|
| 96 |
-
::-webkit-scrollbar-thumb:hover { background:
|
| 97 |
|
| 98 |
-
/* ───
|
| 99 |
code, pre, .font-mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
|
| 100 |
|
| 101 |
-
/* ───
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
.typing-dot {
|
| 103 |
-
width: 6px;
|
| 104 |
-
|
| 105 |
border-radius: 50%;
|
| 106 |
-
background: var(--brand);
|
| 107 |
display: inline-block;
|
| 108 |
-
animation:
|
| 109 |
}
|
| 110 |
-
.typing-dot:nth-child(2) { animation-delay: 0.16s; }
|
| 111 |
-
.typing-dot:nth-child(3) { animation-delay: 0.32s; }
|
| 112 |
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
}
|
| 117 |
|
| 118 |
-
/* ───
|
| 119 |
-
.
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
-
|
| 123 |
-
border: 1px solid var(--border);
|
| 124 |
}
|
| 125 |
|
| 126 |
-
.
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
.agent-chat { color: #22d3ee; }
|
| 133 |
-
.agent-planner { color: #a78bfa; }
|
| 134 |
-
.agent-coding { color: #34d399; }
|
| 135 |
-
.agent-debug { color: #f87171; }
|
| 136 |
-
.agent-memory { color: #fbbf24; }
|
| 137 |
-
.agent-connector { color: #60a5fa; }
|
| 138 |
-
.agent-deploy { color: #f472b6; }
|
| 139 |
-
.agent-workflow { color: #fb923c; }
|
| 140 |
-
.agent-sandbox { color: #4ade80; }
|
| 141 |
-
.agent-ui { color: #e879f9; }
|
| 142 |
-
|
| 143 |
-
/* ─── Neon Glow ───────────────────────────────────────────────────────────── */
|
| 144 |
-
.glow-brand { box-shadow: 0 0 12px var(--brand-glow); }
|
| 145 |
-
.glow-green { box-shadow: 0 0 12px rgba(52,211,153,0.4); }
|
| 146 |
-
.glow-red { box-shadow: 0 0 12px rgba(248,113,113,0.4); }
|
| 147 |
-
|
| 148 |
-
/* ─── Shimmer Loader ──────────────────────────────────────────────────────── */
|
| 149 |
-
.shimmer {
|
| 150 |
-
background: linear-gradient(90deg, var(--bg-3) 25%, var(--bg-4) 50%, var(--bg-3) 75%);
|
| 151 |
-
background-size: 200% 100%;
|
| 152 |
-
animation: shimmer 1.5s infinite;
|
| 153 |
}
|
| 154 |
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
|
|
|
|
|
|
| 158 |
}
|
| 159 |
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
.status-error { background: #ef4444; box-shadow: 0 0 8px rgba(239,68,68,0.6); }
|
| 165 |
|
| 166 |
-
/* ───
|
| 167 |
-
.
|
| 168 |
-
|
| 169 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
}
|
| 171 |
-
|
|
|
|
|
|
|
| 172 |
color: var(--text-primary);
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
.prose-god ul { margin: 0.5em 0; padding-left: 1.4em; }
|
| 178 |
-
.prose-god li { margin: 0.2em 0; }
|
| 179 |
-
.prose-god a { color: var(--brand); text-decoration: none; }
|
| 180 |
-
.prose-god a:hover { text-decoration: underline; }
|
| 181 |
-
.prose-god strong { color: #fff; font-weight: 600; }
|
| 182 |
-
.prose-god code {
|
| 183 |
-
background: var(--bg-2);
|
| 184 |
-
border: 1px solid var(--border);
|
| 185 |
-
border-radius: 4px;
|
| 186 |
-
padding: 1px 6px;
|
| 187 |
-
font-size: 0.85em;
|
| 188 |
-
font-family: 'JetBrains Mono', monospace;
|
| 189 |
color: #a78bfa;
|
|
|
|
| 190 |
}
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
.prose-god pre code {
|
| 200 |
-
background: none;
|
| 201 |
-
border: none;
|
| 202 |
-
padding: 0;
|
| 203 |
-
color: inherit;
|
| 204 |
-
font-size: 0.8rem;
|
| 205 |
-
}
|
| 206 |
-
.prose-god table { width: 100%; border-collapse: collapse; margin: 0.8em 0; font-size: 0.85em; }
|
| 207 |
-
.prose-god th { background: var(--bg-3); padding: 8px 12px; text-align: left; border: 1px solid var(--border); color: var(--text-secondary); }
|
| 208 |
-
.prose-god td { padding: 6px 12px; border: 1px solid var(--border); }
|
| 209 |
-
.prose-god tr:hover td { background: var(--bg-4); }
|
| 210 |
-
.prose-god blockquote {
|
| 211 |
-
border-left: 3px solid var(--brand);
|
| 212 |
-
padding-left: 1em;
|
| 213 |
-
margin: 0.8em 0;
|
| 214 |
-
color: var(--text-secondary);
|
| 215 |
-
font-style: italic;
|
| 216 |
}
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
}
|
| 222 |
|
| 223 |
-
/* ───
|
| 224 |
-
|
| 225 |
-
|
|
|
|
|
|
|
| 226 |
}
|
| 227 |
|
| 228 |
-
|
| 229 |
-
.
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
/* ───
|
| 232 |
-
.
|
| 233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
@tailwind components;
|
| 3 |
@tailwind utilities;
|
| 4 |
|
| 5 |
+
/* ─── Fonts ──────────────────────────────────────────────────────────────── */
|
| 6 |
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
|
| 7 |
|
| 8 |
+
/* ─── CSS Variables ───────────────────────────────────────────────────────── */
|
| 9 |
:root {
|
| 10 |
+
--void: #05060d;
|
| 11 |
+
--surface-1: #0a0c16;
|
| 12 |
+
--surface-2: #0e1121;
|
| 13 |
+
--surface-3: #131729;
|
| 14 |
+
--surface-4: #191e32;
|
| 15 |
+
--surface-5: #1f263b;
|
| 16 |
+
--border: rgba(255,255,255,0.06);
|
| 17 |
+
--border-hover: rgba(255,255,255,0.12);
|
| 18 |
+
--text-primary: #e8eaf0;
|
| 19 |
+
--text-secondary: #8892a4;
|
| 20 |
+
--text-muted: #4a5568;
|
| 21 |
+
--purple: #7c3aed;
|
| 22 |
+
--purple-bright: #8b5cf6;
|
| 23 |
+
--purple-glow: rgba(124,58,237,0.25);
|
| 24 |
+
--blue: #3b82f6;
|
| 25 |
+
--blue-bright: #60a5fa;
|
| 26 |
+
--cyan: #22d3ee;
|
| 27 |
+
--green: #22c55e;
|
| 28 |
+
--amber: #f59e0b;
|
| 29 |
+
--pink: #ec4899;
|
| 30 |
+
--red: #ef4444;
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
/* ─── Base Reset ──────────────────────────────────────────────────────────── */
|
| 34 |
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
| 35 |
+
|
| 36 |
+
html { font-size: 16px; scroll-behavior: smooth; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
body {
|
| 39 |
+
background: var(--void);
|
| 40 |
color: var(--text-primary);
|
| 41 |
+
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
|
|
|
| 42 |
overflow: hidden;
|
| 43 |
height: 100vh;
|
| 44 |
+
-webkit-font-smoothing: antialiased;
|
| 45 |
+
-moz-osx-font-smoothing: grayscale;
|
| 46 |
}
|
| 47 |
|
| 48 |
/* ─── Scrollbar ───────────────────────────────────────────────────────────── */
|
| 49 |
+
::-webkit-scrollbar { width: 3px; height: 3px; }
|
| 50 |
::-webkit-scrollbar-track { background: transparent; }
|
| 51 |
+
::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 8px; }
|
| 52 |
+
::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.15); }
|
| 53 |
|
| 54 |
+
/* ─── Mono Font ───────────────────────────────────────────────────────────── */
|
| 55 |
code, pre, .font-mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
|
| 56 |
|
| 57 |
+
/* ─── Glass Morphism ──────────────────────────────────────────────────────── */
|
| 58 |
+
.glass {
|
| 59 |
+
background: rgba(255,255,255,0.04);
|
| 60 |
+
backdrop-filter: blur(20px);
|
| 61 |
+
-webkit-backdrop-filter: blur(20px);
|
| 62 |
+
border: 1px solid rgba(255,255,255,0.07);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
.glass-hover:hover {
|
| 66 |
+
background: rgba(255,255,255,0.06);
|
| 67 |
+
border-color: rgba(255,255,255,0.12);
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
.glass-purple {
|
| 71 |
+
background: rgba(124,58,237,0.08);
|
| 72 |
+
backdrop-filter: blur(20px);
|
| 73 |
+
border: 1px solid rgba(124,58,237,0.2);
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
.glass-card {
|
| 77 |
+
background: linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%);
|
| 78 |
+
backdrop-filter: blur(24px);
|
| 79 |
+
border: 1px solid rgba(255,255,255,0.07);
|
| 80 |
+
border-radius: 16px;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
/* ─── Neon Glows ──────────────────────────────────────────────────────────── */
|
| 84 |
+
.glow-purple { box-shadow: 0 0 20px rgba(124,58,237,0.3), 0 0 60px rgba(124,58,237,0.1); }
|
| 85 |
+
.glow-blue { box-shadow: 0 0 20px rgba(59,130,246,0.3), 0 0 60px rgba(59,130,246,0.1); }
|
| 86 |
+
.glow-cyan { box-shadow: 0 0 20px rgba(34,211,238,0.3), 0 0 60px rgba(34,211,238,0.1); }
|
| 87 |
+
.glow-green { box-shadow: 0 0 12px rgba(34,197,94,0.4); }
|
| 88 |
+
|
| 89 |
+
.text-glow-purple { text-shadow: 0 0 20px rgba(139,92,246,0.6); }
|
| 90 |
+
.text-glow-cyan { text-shadow: 0 0 20px rgba(34,211,238,0.6); }
|
| 91 |
+
|
| 92 |
+
/* ─── Gradient Text ───────────────────────────────────────────────────────── */
|
| 93 |
+
.gradient-text {
|
| 94 |
+
background: linear-gradient(135deg, #a78bfa 0%, #60a5fa 50%, #34d399 100%);
|
| 95 |
+
-webkit-background-clip: text;
|
| 96 |
+
-webkit-text-fill-color: transparent;
|
| 97 |
+
background-clip: text;
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
.gradient-text-purple {
|
| 101 |
+
background: linear-gradient(135deg, #c084fc 0%, #818cf8 100%);
|
| 102 |
+
-webkit-background-clip: text;
|
| 103 |
+
-webkit-text-fill-color: transparent;
|
| 104 |
+
background-clip: text;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/* ─── Animations ──────────────────────────────────────────────────────────── */
|
| 108 |
+
@keyframes fadeInUp {
|
| 109 |
+
from { opacity: 0; transform: translateY(12px); }
|
| 110 |
+
to { opacity: 1; transform: translateY(0); }
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
@keyframes fadeIn {
|
| 114 |
+
from { opacity: 0; }
|
| 115 |
+
to { opacity: 1; }
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
@keyframes slideInLeft {
|
| 119 |
+
from { opacity: 0; transform: translateX(-16px); }
|
| 120 |
+
to { opacity: 1; transform: translateX(0); }
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
@keyframes pulseGlow {
|
| 124 |
+
0%, 100% { opacity: 0.6; }
|
| 125 |
+
50% { opacity: 1; }
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
@keyframes spin {
|
| 129 |
+
from { transform: rotate(0deg); }
|
| 130 |
+
to { transform: rotate(360deg); }
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
@keyframes shimmer {
|
| 134 |
+
0% { background-position: -200% center; }
|
| 135 |
+
100% { background-position: 200% center; }
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
@keyframes typingDot {
|
| 139 |
+
0%, 80%, 100% { transform: scale(0); opacity: 0.3; }
|
| 140 |
+
40% { transform: scale(1); opacity: 1; }
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
@keyframes orbFloat {
|
| 144 |
+
0%, 100% { transform: translateY(0px) rotate(0deg); }
|
| 145 |
+
33% { transform: translateY(-8px) rotate(5deg); }
|
| 146 |
+
66% { transform: translateY(4px) rotate(-3deg); }
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
@keyframes progressPulse {
|
| 150 |
+
0%, 100% { opacity: 1; }
|
| 151 |
+
50% { opacity: 0.7; }
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
.animate-fade-in-up { animation: fadeInUp 0.4s ease-out forwards; }
|
| 155 |
+
.animate-fade-in { animation: fadeIn 0.3s ease-out forwards; }
|
| 156 |
+
.animate-slide-left { animation: slideInLeft 0.3s ease-out forwards; }
|
| 157 |
+
.animate-pulse-glow { animation: pulseGlow 2s ease-in-out infinite; }
|
| 158 |
+
.animate-spin-slow { animation: spin 8s linear infinite; }
|
| 159 |
+
.animate-orb-float { animation: orbFloat 6s ease-in-out infinite; }
|
| 160 |
+
.animate-progress-pulse { animation: progressPulse 2s ease-in-out infinite; }
|
| 161 |
+
|
| 162 |
+
.shimmer-text {
|
| 163 |
+
background: linear-gradient(90deg, #a78bfa, #60a5fa, #34d399, #a78bfa);
|
| 164 |
+
background-size: 200% auto;
|
| 165 |
+
-webkit-background-clip: text;
|
| 166 |
+
-webkit-text-fill-color: transparent;
|
| 167 |
+
background-clip: text;
|
| 168 |
+
animation: shimmer 3s linear infinite;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
.typing-dot {
|
| 172 |
+
width: 6px; height: 6px;
|
| 173 |
+
background: var(--purple-bright);
|
| 174 |
border-radius: 50%;
|
|
|
|
| 175 |
display: inline-block;
|
| 176 |
+
animation: typingDot 1.4s ease-in-out infinite;
|
| 177 |
}
|
|
|
|
|
|
|
| 178 |
|
| 179 |
+
/* ─── Cosmic Orb ──────────────────────────────────────────────────────────── */
|
| 180 |
+
.cosmic-orb {
|
| 181 |
+
width: 120px; height: 120px;
|
| 182 |
+
border-radius: 50%;
|
| 183 |
+
background: radial-gradient(circle at 30% 30%, #c084fc, #7c3aed, #3b82f6, #1e1b4b);
|
| 184 |
+
box-shadow:
|
| 185 |
+
0 0 40px rgba(124,58,237,0.5),
|
| 186 |
+
0 0 80px rgba(124,58,237,0.2),
|
| 187 |
+
inset 0 0 30px rgba(192,132,252,0.3);
|
| 188 |
+
animation: orbFloat 6s ease-in-out infinite;
|
| 189 |
}
|
| 190 |
|
| 191 |
+
/* ─── Active Dot ──────────────────────────────────────────────────────────── */
|
| 192 |
+
.active-dot {
|
| 193 |
+
width: 8px; height: 8px; border-radius: 50%;
|
| 194 |
+
background: var(--green);
|
| 195 |
+
box-shadow: 0 0 8px rgba(34,197,94,0.6);
|
|
|
|
| 196 |
}
|
| 197 |
|
| 198 |
+
.active-dot::after {
|
| 199 |
+
content: '';
|
| 200 |
+
position: absolute; top: -2px; left: -2px; right: -2px; bottom: -2px;
|
| 201 |
+
border-radius: 50%;
|
| 202 |
+
border: 2px solid rgba(34,197,94,0.3);
|
| 203 |
+
animation: pulse 2s ease-in-out infinite;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 204 |
}
|
| 205 |
|
| 206 |
+
/* ─── Progress Bar ────────────────────────────────────────────────────────── */
|
| 207 |
+
.progress-bar {
|
| 208 |
+
height: 4px; border-radius: 4px;
|
| 209 |
+
background: rgba(255,255,255,0.06);
|
| 210 |
+
overflow: hidden;
|
| 211 |
}
|
| 212 |
|
| 213 |
+
.progress-fill {
|
| 214 |
+
height: 100%; border-radius: 4px;
|
| 215 |
+
transition: width 0.8s ease-out;
|
| 216 |
+
}
|
|
|
|
| 217 |
|
| 218 |
+
/* ─── Nav Item ────────────────────────────────────────────────────────────── */
|
| 219 |
+
.nav-item {
|
| 220 |
+
display: flex; align-items: center; gap: 10px;
|
| 221 |
+
padding: 8px 12px; border-radius: 10px;
|
| 222 |
+
font-size: 0.8125rem; font-weight: 500;
|
| 223 |
+
color: var(--text-secondary);
|
| 224 |
+
cursor: pointer; transition: all 0.2s ease;
|
| 225 |
+
position: relative;
|
| 226 |
}
|
| 227 |
+
|
| 228 |
+
.nav-item:hover {
|
| 229 |
+
background: rgba(255,255,255,0.05);
|
| 230 |
color: var(--text-primary);
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
.nav-item.active {
|
| 234 |
+
background: rgba(124,58,237,0.12);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
color: #a78bfa;
|
| 236 |
+
border: 1px solid rgba(124,58,237,0.2);
|
| 237 |
}
|
| 238 |
+
|
| 239 |
+
.nav-item.active::before {
|
| 240 |
+
content: '';
|
| 241 |
+
position: absolute; left: 0; top: 50%;
|
| 242 |
+
transform: translateY(-50%);
|
| 243 |
+
width: 3px; height: 60%; min-height: 16px;
|
| 244 |
+
background: linear-gradient(180deg, #a78bfa, #7c3aed);
|
| 245 |
+
border-radius: 0 2px 2px 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 246 |
}
|
| 247 |
+
|
| 248 |
+
/* ─── Command Input ───────────────────────────────────────────────────────── */
|
| 249 |
+
.cmd-input {
|
| 250 |
+
background: rgba(255,255,255,0.04);
|
| 251 |
+
border: 1px solid rgba(255,255,255,0.08);
|
| 252 |
+
border-radius: 12px;
|
| 253 |
+
color: var(--text-primary);
|
| 254 |
+
font-size: 0.9rem;
|
| 255 |
+
transition: all 0.2s ease;
|
| 256 |
+
}
|
| 257 |
+
|
| 258 |
+
.cmd-input:focus {
|
| 259 |
+
outline: none;
|
| 260 |
+
background: rgba(255,255,255,0.06);
|
| 261 |
+
border-color: rgba(124,58,237,0.4);
|
| 262 |
+
box-shadow: 0 0 0 3px rgba(124,58,237,0.1), 0 0 20px rgba(124,58,237,0.1);
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
/* ─── Card ────────────────────────────────────────────────────────────────── */
|
| 266 |
+
.card {
|
| 267 |
+
background: rgba(255,255,255,0.03);
|
| 268 |
+
border: 1px solid rgba(255,255,255,0.07);
|
| 269 |
+
border-radius: 16px;
|
| 270 |
+
transition: all 0.25s ease;
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
.card:hover {
|
| 274 |
+
background: rgba(255,255,255,0.05);
|
| 275 |
+
border-color: rgba(255,255,255,0.12);
|
| 276 |
+
transform: translateY(-1px);
|
| 277 |
}
|
| 278 |
|
| 279 |
+
/* ─── Status Badge ────────────────────────────────────────────────────────── */
|
| 280 |
+
.badge {
|
| 281 |
+
display: inline-flex; align-items: center; gap: 5px;
|
| 282 |
+
padding: 2px 8px; border-radius: 20px;
|
| 283 |
+
font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
|
| 284 |
}
|
| 285 |
|
| 286 |
+
.badge-active { background: rgba(34,197,94,0.12); color: #4ade80; }
|
| 287 |
+
.badge-idle { background: rgba(148,163,184,0.1); color: #94a3b8; }
|
| 288 |
+
.badge-processing { background: rgba(245,158,11,0.12); color: #fbbf24; }
|
| 289 |
+
.badge-error { background: rgba(239,68,68,0.12); color: #f87171; }
|
| 290 |
|
| 291 |
+
/* ─── Chip / Tag ──────────────────────────────────────────────────────────── */
|
| 292 |
+
.chip {
|
| 293 |
+
display: inline-flex; align-items: center; gap: 6px;
|
| 294 |
+
padding: 5px 12px; border-radius: 20px;
|
| 295 |
+
font-size: 0.78rem; font-weight: 500;
|
| 296 |
+
background: rgba(255,255,255,0.05);
|
| 297 |
+
border: 1px solid rgba(255,255,255,0.08);
|
| 298 |
+
color: var(--text-secondary);
|
| 299 |
+
cursor: pointer; white-space: nowrap;
|
| 300 |
+
transition: all 0.2s ease;
|
| 301 |
+
}
|
| 302 |
|
| 303 |
+
.chip:hover {
|
| 304 |
+
background: rgba(124,58,237,0.12);
|
| 305 |
+
border-color: rgba(124,58,237,0.3);
|
| 306 |
+
color: #a78bfa;
|
| 307 |
+
}
|
| 308 |
+
|
| 309 |
+
/* ─── Terminal / Console ───────────────────────────────────────────��──────── */
|
| 310 |
+
.terminal {
|
| 311 |
+
background: rgba(0,0,0,0.3);
|
| 312 |
+
border: 1px solid rgba(255,255,255,0.06);
|
| 313 |
+
border-radius: 12px;
|
| 314 |
+
font-family: 'JetBrains Mono', monospace;
|
| 315 |
+
font-size: 0.78rem;
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
/* ─── Stagger Delays ──────────────────────────────────────────────────────── */
|
| 319 |
+
.stagger-1 { animation-delay: 0.05s; }
|
| 320 |
+
.stagger-2 { animation-delay: 0.10s; }
|
| 321 |
+
.stagger-3 { animation-delay: 0.15s; }
|
| 322 |
+
.stagger-4 { animation-delay: 0.20s; }
|
| 323 |
+
.stagger-5 { animation-delay: 0.25s; }
|
| 324 |
+
.stagger-6 { animation-delay: 0.30s; }
|
| 325 |
+
|
| 326 |
+
/* ─── Responsive ──────────────────────────────────────────────────────────── */
|
| 327 |
+
@media (max-width: 1280px) {
|
| 328 |
+
.hide-xl { display: none; }
|
| 329 |
+
}
|
| 330 |
+
@media (max-width: 1024px) {
|
| 331 |
+
.hide-lg { display: none; }
|
| 332 |
+
}
|
frontend/app/layout.tsx
CHANGED
|
@@ -2,23 +2,25 @@ import type { Metadata } from 'next'
|
|
| 2 |
import './globals.css'
|
| 3 |
|
| 4 |
export const metadata: Metadata = {
|
| 5 |
-
title: '
|
| 6 |
-
description: '
|
| 7 |
-
|
| 8 |
}
|
| 9 |
|
| 10 |
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
| 11 |
return (
|
| 12 |
-
<html lang="en"
|
| 13 |
<head>
|
| 14 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
| 15 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
|
| 16 |
<link
|
| 17 |
-
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
| 18 |
rel="stylesheet"
|
| 19 |
/>
|
| 20 |
</head>
|
| 21 |
-
<body className="antialiased">
|
|
|
|
|
|
|
| 22 |
</html>
|
| 23 |
)
|
| 24 |
}
|
|
|
|
| 2 |
import './globals.css'
|
| 3 |
|
| 4 |
export const metadata: Metadata = {
|
| 5 |
+
title: 'GOD AGENT OS — Autonomous AI Operating System',
|
| 6 |
+
description: 'Multi-agent AI OS powered by Gemini, Sambanova & GitHub Models',
|
| 7 |
+
icons: { icon: '/favicon.ico' },
|
| 8 |
}
|
| 9 |
|
| 10 |
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
| 11 |
return (
|
| 12 |
+
<html lang="en" className="dark">
|
| 13 |
<head>
|
| 14 |
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
| 15 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
| 16 |
<link
|
| 17 |
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap"
|
| 18 |
rel="stylesheet"
|
| 19 |
/>
|
| 20 |
</head>
|
| 21 |
+
<body className="bg-void text-slate-100 antialiased overflow-hidden h-screen font-sans">
|
| 22 |
+
{children}
|
| 23 |
+
</body>
|
| 24 |
</html>
|
| 25 |
)
|
| 26 |
}
|
frontend/app/page.tsx
CHANGED
|
@@ -1,79 +1,81 @@
|
|
| 1 |
'use client'
|
| 2 |
|
| 3 |
import { useEffect, useState } from 'react'
|
| 4 |
-
import {
|
| 5 |
-
import { useAgentWebSocket } from '@/hooks/useWebSocket'
|
| 6 |
-
import TopBar from '@/components/layout/TopBar'
|
| 7 |
-
import Sidebar from '@/components/layout/Sidebar'
|
| 8 |
-
import ChatPanel from '@/components/chat/ChatPanel'
|
| 9 |
-
import ExecutionTimeline from '@/components/timeline/ExecutionTimeline'
|
| 10 |
-
import TasksPanel from '@/components/layout/TasksPanel'
|
| 11 |
-
import MemoryPanel from '@/components/layout/MemoryPanel'
|
| 12 |
-
import ConnectorsPanel from '@/components/layout/ConnectorsPanel'
|
| 13 |
-
import SandboxPanel from '@/components/layout/SandboxPanel'
|
| 14 |
-
import FileExplorer from '@/components/layout/FileExplorer'
|
| 15 |
-
import BrowserPanel from '@/components/layout/BrowserPanel'
|
| 16 |
import { Zap } from 'lucide-react'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
| 26 |
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
|
| 31 |
-
|
| 32 |
-
useAgentWebSocket(activeTaskId || undefined)
|
| 33 |
|
| 34 |
if (!mounted) return (
|
| 35 |
-
<div className="flex items-center justify-center h-screen" style={{ background: '
|
| 36 |
-
<div
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
</div>
|
| 41 |
-
<
|
| 42 |
-
<
|
| 43 |
-
<
|
| 44 |
-
<div className="flex gap-
|
| 45 |
{[0, 1, 2].map(i => (
|
| 46 |
-
<div key={i} className="typing-dot" style={{ animationDelay: `${i * 0.
|
| 47 |
))}
|
| 48 |
</div>
|
| 49 |
-
</div>
|
| 50 |
</div>
|
| 51 |
)
|
| 52 |
|
| 53 |
-
const
|
| 54 |
-
switch (activePanel) {
|
| 55 |
-
case 'timeline': return <ExecutionTimeline />
|
| 56 |
-
case 'tasks': return <TasksPanel />
|
| 57 |
-
case 'memory': return <MemoryPanel />
|
| 58 |
-
case 'connectors': return <ConnectorsPanel />
|
| 59 |
-
case 'sandbox': return <SandboxPanel />
|
| 60 |
-
case 'files': return <FileExplorer />
|
| 61 |
-
case 'browser': return <BrowserPanel />
|
| 62 |
-
default: return <ExecutionTimeline />
|
| 63 |
-
}
|
| 64 |
-
}
|
| 65 |
|
| 66 |
return (
|
| 67 |
-
<div className="flex
|
| 68 |
-
<
|
| 69 |
-
<div className="flex flex-1 overflow-hidden">
|
| 70 |
-
<
|
| 71 |
-
<
|
| 72 |
-
<
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
</div>
|
| 78 |
</div>
|
| 79 |
)
|
|
|
|
| 1 |
'use client'
|
| 2 |
|
| 3 |
import { useEffect, useState } from 'react'
|
| 4 |
+
import { motion, AnimatePresence } from 'framer-motion'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
import { Zap } from 'lucide-react'
|
| 6 |
+
import Sidebar from '@/components/shared/Sidebar'
|
| 7 |
+
import TopBar from '@/components/shared/TopBar'
|
| 8 |
+
import DashboardPage from '@/components/pages/DashboardPage'
|
| 9 |
+
import AgentsPage from '@/components/pages/AgentsPage'
|
| 10 |
+
import TasksPage from '@/components/pages/TasksPage'
|
| 11 |
+
import MemoryPage from '@/components/pages/MemoryPage'
|
| 12 |
+
import KnowledgePage from '@/components/pages/KnowledgePage'
|
| 13 |
+
import WorkflowsPage from '@/components/pages/WorkflowsPage'
|
| 14 |
+
import AnalyticsPage from '@/components/pages/AnalyticsPage'
|
| 15 |
+
import SettingsPage from '@/components/pages/SettingsPage'
|
| 16 |
+
import { useAppStore } from '@/store/useAppStore'
|
| 17 |
|
| 18 |
+
const PAGE_MAP = {
|
| 19 |
+
dashboard: DashboardPage,
|
| 20 |
+
agents: AgentsPage,
|
| 21 |
+
tasks: TasksPage,
|
| 22 |
+
memory: MemoryPage,
|
| 23 |
+
knowledge: KnowledgePage,
|
| 24 |
+
workflows: WorkflowsPage,
|
| 25 |
+
analytics: AnalyticsPage,
|
| 26 |
+
settings: SettingsPage,
|
| 27 |
+
}
|
| 28 |
|
| 29 |
+
export default function GodAgentOS() {
|
| 30 |
+
const { currentPage } = useAppStore()
|
| 31 |
+
const [mounted, setMounted] = useState(false)
|
| 32 |
|
| 33 |
+
useEffect(() => { setMounted(true) }, [])
|
|
|
|
| 34 |
|
| 35 |
if (!mounted) return (
|
| 36 |
+
<div className="flex items-center justify-center h-screen" style={{ background: '#05060d' }}>
|
| 37 |
+
<motion.div
|
| 38 |
+
initial={{ opacity: 0, scale: 0.9 }}
|
| 39 |
+
animate={{ opacity: 1, scale: 1 }}
|
| 40 |
+
className="text-center"
|
| 41 |
+
>
|
| 42 |
+
<div className="w-16 h-16 rounded-2xl mx-auto mb-5 flex items-center justify-center glow-purple"
|
| 43 |
+
style={{ background: 'linear-gradient(135deg, #7c3aed, #4f46e5)' }}>
|
| 44 |
+
<Zap size={28} className="text-white" />
|
| 45 |
</div>
|
| 46 |
+
<div className="shimmer-text text-xl font-black mb-2">GOD AGENT OS</div>
|
| 47 |
+
<div className="text-sm text-slate-600 mb-1">Autonomous AI Operating System</div>
|
| 48 |
+
<div className="text-xs text-slate-700">Gemini · Sambanova · GitHub Models</div>
|
| 49 |
+
<div className="flex gap-2 justify-center mt-6">
|
| 50 |
{[0, 1, 2].map(i => (
|
| 51 |
+
<div key={i} className="typing-dot" style={{ animationDelay: `${i * 0.2}s` }} />
|
| 52 |
))}
|
| 53 |
</div>
|
| 54 |
+
</motion.div>
|
| 55 |
</div>
|
| 56 |
)
|
| 57 |
|
| 58 |
+
const PageComponent = PAGE_MAP[currentPage]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
|
| 60 |
return (
|
| 61 |
+
<div className="flex h-screen overflow-hidden" style={{ background: '#05060d' }}>
|
| 62 |
+
<Sidebar />
|
| 63 |
+
<div className="flex flex-col flex-1 min-w-0 overflow-hidden">
|
| 64 |
+
<TopBar />
|
| 65 |
+
<main className="flex-1 overflow-hidden">
|
| 66 |
+
<AnimatePresence mode="wait">
|
| 67 |
+
<motion.div
|
| 68 |
+
key={currentPage}
|
| 69 |
+
initial={{ opacity: 0, y: 8 }}
|
| 70 |
+
animate={{ opacity: 1, y: 0 }}
|
| 71 |
+
exit={{ opacity: 0, y: -8 }}
|
| 72 |
+
transition={{ duration: 0.25, ease: [0.4, 0, 0.2, 1] }}
|
| 73 |
+
className="h-full"
|
| 74 |
+
>
|
| 75 |
+
<PageComponent />
|
| 76 |
+
</motion.div>
|
| 77 |
+
</AnimatePresence>
|
| 78 |
+
</main>
|
| 79 |
</div>
|
| 80 |
</div>
|
| 81 |
)
|
frontend/components/dashboard/ActivityFeed.tsx
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { ACTIVITY } from '@/store/useAppStore'
|
| 5 |
+
import { CheckCircle2, Loader2, Info, AlertTriangle } from 'lucide-react'
|
| 6 |
+
|
| 7 |
+
const TypeIcon = ({ type }: { type: string }) => {
|
| 8 |
+
const cls = 'w-3.5 h-3.5 flex-shrink-0'
|
| 9 |
+
switch (type) {
|
| 10 |
+
case 'success': return <CheckCircle2 className={cls} style={{ color: '#22c55e' }} />
|
| 11 |
+
case 'processing': return <Loader2 className={`${cls} animate-spin`} style={{ color: '#f59e0b' }} />
|
| 12 |
+
case 'warning': return <AlertTriangle className={cls} style={{ color: '#f59e0b' }} />
|
| 13 |
+
default: return <Info className={cls} style={{ color: '#60a5fa' }} />
|
| 14 |
+
}
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
export default function ActivityFeed({ max = 6 }: { max?: number }) {
|
| 18 |
+
const items = ACTIVITY.slice(0, max)
|
| 19 |
+
return (
|
| 20 |
+
<div className="space-y-1">
|
| 21 |
+
{items.map((item, i) => (
|
| 22 |
+
<motion.div
|
| 23 |
+
key={item.id}
|
| 24 |
+
initial={{ opacity: 0, x: 8 }}
|
| 25 |
+
animate={{ opacity: 1, x: 0 }}
|
| 26 |
+
transition={{ duration: 0.3, delay: i * 0.06 }}
|
| 27 |
+
className="flex items-start gap-3 px-3 py-2.5 rounded-xl hover:bg-white/[0.03] transition-colors group cursor-default"
|
| 28 |
+
>
|
| 29 |
+
<div className="w-6 h-6 rounded-lg flex items-center justify-center flex-shrink-0 mt-0.5"
|
| 30 |
+
style={{ background: `${item.color}15` }}>
|
| 31 |
+
<div className="w-2 h-2 rounded-full" style={{ background: item.color }} />
|
| 32 |
+
</div>
|
| 33 |
+
<div className="flex-1 min-w-0">
|
| 34 |
+
<div className="flex items-center justify-between gap-2">
|
| 35 |
+
<span className="text-xs font-semibold text-white truncate">{item.agent}</span>
|
| 36 |
+
<span className="text-xs flex-shrink-0" style={{ color: 'var(--text-muted)' }}>{item.time}</span>
|
| 37 |
+
</div>
|
| 38 |
+
<div className="text-xs mt-0.5 truncate" style={{ color: 'var(--text-secondary)' }}>{item.action}</div>
|
| 39 |
+
</div>
|
| 40 |
+
<TypeIcon type={item.type} />
|
| 41 |
+
</motion.div>
|
| 42 |
+
))}
|
| 43 |
+
</div>
|
| 44 |
+
)
|
| 45 |
+
}
|
frontend/components/dashboard/AgentFleetCard.tsx
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { Agent } from '@/store/useAppStore'
|
| 5 |
+
import { cn, getStatusColor } from '@/lib/utils'
|
| 6 |
+
import { ChevronRight } from 'lucide-react'
|
| 7 |
+
|
| 8 |
+
interface AgentFleetCardProps {
|
| 9 |
+
agent: Agent
|
| 10 |
+
delay?: number
|
| 11 |
+
onClick?: () => void
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
export default function AgentFleetCard({ agent, delay = 0, onClick }: AgentFleetCardProps) {
|
| 15 |
+
const statusColor = getStatusColor(agent.status)
|
| 16 |
+
|
| 17 |
+
return (
|
| 18 |
+
<motion.div
|
| 19 |
+
initial={{ opacity: 0, y: 12 }}
|
| 20 |
+
animate={{ opacity: 1, y: 0 }}
|
| 21 |
+
transition={{ duration: 0.35, delay, ease: [0.4, 0, 0.2, 1] }}
|
| 22 |
+
onClick={onClick}
|
| 23 |
+
className="card p-4 cursor-pointer group relative overflow-hidden"
|
| 24 |
+
>
|
| 25 |
+
{/* Accent line */}
|
| 26 |
+
<div className="absolute top-0 left-0 right-0 h-[2px] opacity-60 rounded-t-2xl"
|
| 27 |
+
style={{ background: `linear-gradient(90deg, ${agent.color}, transparent)` }} />
|
| 28 |
+
|
| 29 |
+
{/* Header */}
|
| 30 |
+
<div className="flex items-start justify-between mb-3">
|
| 31 |
+
<div className="w-10 h-10 rounded-xl flex items-center justify-center text-xl flex-shrink-0"
|
| 32 |
+
style={{ background: `${agent.color}15`, border: `1px solid ${agent.color}20` }}>
|
| 33 |
+
{agent.icon}
|
| 34 |
+
</div>
|
| 35 |
+
<div className={cn('badge', `badge-${agent.status}`)}>
|
| 36 |
+
<div className="w-1.5 h-1.5 rounded-full" style={{ background: statusColor }} />
|
| 37 |
+
{agent.status}
|
| 38 |
+
</div>
|
| 39 |
+
</div>
|
| 40 |
+
|
| 41 |
+
{/* Info */}
|
| 42 |
+
<div className="mb-3">
|
| 43 |
+
<div className="text-sm font-semibold text-white leading-snug">{agent.name}</div>
|
| 44 |
+
<div className="text-xs mt-0.5" style={{ color: 'var(--text-secondary)' }}>{agent.role}</div>
|
| 45 |
+
</div>
|
| 46 |
+
|
| 47 |
+
{/* Stats Row */}
|
| 48 |
+
<div className="grid grid-cols-2 gap-2 mb-3">
|
| 49 |
+
<div>
|
| 50 |
+
<div className="text-xs text-slate-500 mb-1">Efficiency</div>
|
| 51 |
+
<div className="progress-bar">
|
| 52 |
+
<div className="progress-fill"
|
| 53 |
+
style={{ width: `${agent.efficiency}%`, background: `linear-gradient(90deg, ${agent.color}80, ${agent.color})` }} />
|
| 54 |
+
</div>
|
| 55 |
+
<div className="text-xs font-semibold mt-1" style={{ color: agent.color }}>{agent.efficiency}%</div>
|
| 56 |
+
</div>
|
| 57 |
+
<div>
|
| 58 |
+
<div className="text-xs text-slate-500 mb-1">Uptime</div>
|
| 59 |
+
<div className="progress-bar">
|
| 60 |
+
<div className="progress-fill"
|
| 61 |
+
style={{ width: `${agent.uptime}%`, background: `linear-gradient(90deg, #22d3ee60, #22d3ee)` }} />
|
| 62 |
+
</div>
|
| 63 |
+
<div className="text-xs font-semibold mt-1 text-cyan-400">{agent.uptime}%</div>
|
| 64 |
+
</div>
|
| 65 |
+
</div>
|
| 66 |
+
|
| 67 |
+
{/* Last Action */}
|
| 68 |
+
<div className="flex items-center gap-1.5 text-xs text-slate-500 group-hover:text-slate-400 transition-colors">
|
| 69 |
+
<span className="truncate">{agent.lastAction}</span>
|
| 70 |
+
<span className="flex-shrink-0">· {agent.lastActionTime}</span>
|
| 71 |
+
</div>
|
| 72 |
+
|
| 73 |
+
<ChevronRight size={14} className="absolute right-3 bottom-3 text-slate-700 group-hover:text-purple-400 transition-colors" />
|
| 74 |
+
</motion.div>
|
| 75 |
+
)
|
| 76 |
+
}
|
frontend/components/dashboard/CommandCenter.tsx
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useState, useRef, useEffect } from 'react'
|
| 4 |
+
import { motion } from 'framer-motion'
|
| 5 |
+
import { Terminal, Mic, Send } from 'lucide-react'
|
| 6 |
+
|
| 7 |
+
const COMMANDS = ['/new-project', '/analyze-competitors', '/generate-report', '/deploy-app', '/automate-workflow', '/research']
|
| 8 |
+
const LINES = [
|
| 9 |
+
{ text: '> God Agent OS is listening...', color: '#6366f1' },
|
| 10 |
+
{ text: '> Multi-agent system ready. Gemini · Sambanova · GitHub Models active.', color: '#22d3ee' },
|
| 11 |
+
{ text: '> How may I assist in your divine mission?', color: 'var(--text-secondary)' },
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
export default function CommandCenter() {
|
| 15 |
+
const [input, setInput] = useState('')
|
| 16 |
+
const [history, setHistory] = useState<string[]>([])
|
| 17 |
+
const inputRef = useRef<HTMLInputElement>(null)
|
| 18 |
+
|
| 19 |
+
const handleSubmit = (cmd?: string) => {
|
| 20 |
+
const command = cmd || input.trim()
|
| 21 |
+
if (!command) return
|
| 22 |
+
setHistory(prev => [...prev, `> ${command}`, ' Executing…'])
|
| 23 |
+
setInput('')
|
| 24 |
+
setTimeout(() => {
|
| 25 |
+
setHistory(prev => [...prev, ' ✓ Task dispatched to agent fleet.'])
|
| 26 |
+
}, 800)
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
return (
|
| 30 |
+
<div className="card overflow-hidden">
|
| 31 |
+
{/* Header */}
|
| 32 |
+
<div className="flex items-center justify-between px-4 py-3 border-b" style={{ borderColor: 'var(--border)' }}>
|
| 33 |
+
<div className="flex items-center gap-2">
|
| 34 |
+
<Terminal size={14} className="text-purple-400" />
|
| 35 |
+
<span className="text-xs font-bold text-white">Command Center</span>
|
| 36 |
+
<div className="w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse-glow" />
|
| 37 |
+
</div>
|
| 38 |
+
<button className="flex items-center gap-1.5 text-xs px-3 py-1.5 rounded-lg font-medium transition-all hover:bg-purple-500/10"
|
| 39 |
+
style={{ background: 'rgba(124,58,237,0.08)', border: '1px solid rgba(124,58,237,0.2)', color: '#a78bfa' }}>
|
| 40 |
+
<Mic size={11} />
|
| 41 |
+
Voice Command
|
| 42 |
+
</button>
|
| 43 |
+
</div>
|
| 44 |
+
|
| 45 |
+
{/* Terminal */}
|
| 46 |
+
<div className="terminal mx-3 mt-3 mb-2 p-3 min-h-[80px]">
|
| 47 |
+
{LINES.map((line, i) => (
|
| 48 |
+
<div key={i} className="text-xs leading-relaxed" style={{ color: line.color }}>{line.text}</div>
|
| 49 |
+
))}
|
| 50 |
+
{history.map((line, i) => (
|
| 51 |
+
<div key={`h${i}`} className="text-xs leading-relaxed text-slate-400">{line}</div>
|
| 52 |
+
))}
|
| 53 |
+
</div>
|
| 54 |
+
|
| 55 |
+
{/* Command Chips */}
|
| 56 |
+
<div className="flex flex-wrap gap-2 px-3 pb-3">
|
| 57 |
+
{COMMANDS.map(cmd => (
|
| 58 |
+
<button key={cmd} onClick={() => handleSubmit(cmd)}
|
| 59 |
+
className="chip text-xs">
|
| 60 |
+
{cmd}
|
| 61 |
+
</button>
|
| 62 |
+
))}
|
| 63 |
+
<div className="flex gap-2 ml-auto">
|
| 64 |
+
<input
|
| 65 |
+
ref={inputRef}
|
| 66 |
+
value={input}
|
| 67 |
+
onChange={e => setInput(e.target.value)}
|
| 68 |
+
onKeyDown={e => e.key === 'Enter' && handleSubmit()}
|
| 69 |
+
placeholder="Custom command…"
|
| 70 |
+
className="cmd-input px-3 py-1.5 text-xs w-36"
|
| 71 |
+
/>
|
| 72 |
+
<button onClick={() => handleSubmit()}
|
| 73 |
+
className="p-1.5 rounded-lg transition-colors hover:bg-purple-500/20"
|
| 74 |
+
style={{ background: 'rgba(124,58,237,0.1)', border: '1px solid rgba(124,58,237,0.2)' }}>
|
| 75 |
+
<Send size={12} className="text-purple-400" />
|
| 76 |
+
</button>
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
</div>
|
| 80 |
+
)
|
| 81 |
+
}
|
frontend/components/dashboard/GodModeCard.tsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { useAppStore } from '@/store/useAppStore'
|
| 5 |
+
|
| 6 |
+
export default function GodModeCard() {
|
| 7 |
+
const { godModeActive } = useAppStore()
|
| 8 |
+
|
| 9 |
+
return (
|
| 10 |
+
<div className="relative overflow-hidden rounded-2xl p-5"
|
| 11 |
+
style={{ background: 'linear-gradient(135deg, rgba(124,58,237,0.15) 0%, rgba(59,130,246,0.1) 50%, rgba(20,24,40,0.8) 100%)', border: '1px solid rgba(124,58,237,0.25)' }}>
|
| 12 |
+
|
| 13 |
+
{/* Cosmic Orb */}
|
| 14 |
+
<div className="flex justify-center mb-4">
|
| 15 |
+
<div className="cosmic-orb" style={{ width: 80, height: 80 }} />
|
| 16 |
+
</div>
|
| 17 |
+
|
| 18 |
+
{/* Status */}
|
| 19 |
+
<div className="text-center">
|
| 20 |
+
<div className="text-xs font-semibold uppercase tracking-widest mb-1" style={{ color: 'var(--text-secondary)' }}>GOD MODE</div>
|
| 21 |
+
<div className={`text-xl font-black tracking-wide mb-2 ${godModeActive ? 'gradient-text' : 'text-slate-500'}`}>
|
| 22 |
+
{godModeActive ? 'ACTIVE' : 'STANDBY'}
|
| 23 |
+
</div>
|
| 24 |
+
<p className="text-xs" style={{ color: 'var(--text-secondary)' }}>
|
| 25 |
+
{godModeActive ? 'All systems operational. You are the Architect.' : 'Enable God Mode for full autonomy.'}
|
| 26 |
+
</p>
|
| 27 |
+
</div>
|
| 28 |
+
|
| 29 |
+
{/* Glow overlay */}
|
| 30 |
+
{godModeActive && (
|
| 31 |
+
<motion.div
|
| 32 |
+
className="absolute inset-0 pointer-events-none rounded-2xl"
|
| 33 |
+
animate={{ opacity: [0.3, 0.6, 0.3] }}
|
| 34 |
+
transition={{ duration: 3, repeat: Infinity, ease: 'easeInOut' }}
|
| 35 |
+
style={{ background: 'radial-gradient(ellipse at 50% 0%, rgba(124,58,237,0.15) 0%, transparent 70%)' }}
|
| 36 |
+
/>
|
| 37 |
+
)}
|
| 38 |
+
|
| 39 |
+
{/* Status dot */}
|
| 40 |
+
<div className="absolute top-3 right-3 flex items-center gap-1.5">
|
| 41 |
+
<div className={`w-2 h-2 rounded-full ${godModeActive ? 'bg-green-400 animate-pulse-glow' : 'bg-slate-600'}`} />
|
| 42 |
+
<span className="text-xs font-medium" style={{ color: godModeActive ? '#4ade80' : 'var(--text-muted)' }}>
|
| 43 |
+
{godModeActive ? 'Live' : 'Off'}
|
| 44 |
+
</span>
|
| 45 |
+
</div>
|
| 46 |
+
</div>
|
| 47 |
+
)
|
| 48 |
+
}
|
frontend/components/dashboard/MetricCard.tsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { TrendingUp, TrendingDown } from 'lucide-react'
|
| 5 |
+
import { cn } from '@/lib/utils'
|
| 6 |
+
|
| 7 |
+
interface MetricCardProps {
|
| 8 |
+
label: string
|
| 9 |
+
value: string | number
|
| 10 |
+
unit?: string
|
| 11 |
+
trend?: string
|
| 12 |
+
trendUp?: boolean
|
| 13 |
+
icon: React.ReactNode
|
| 14 |
+
iconColor: string
|
| 15 |
+
delay?: number
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
export default function MetricCard({ label, value, unit, trend, trendUp = true, icon, iconColor, delay = 0 }: MetricCardProps) {
|
| 19 |
+
return (
|
| 20 |
+
<motion.div
|
| 21 |
+
initial={{ opacity: 0, y: 16 }}
|
| 22 |
+
animate={{ opacity: 1, y: 0 }}
|
| 23 |
+
transition={{ duration: 0.4, delay, ease: [0.4, 0, 0.2, 1] }}
|
| 24 |
+
className="card p-5 group cursor-default"
|
| 25 |
+
>
|
| 26 |
+
<div className="flex items-start justify-between mb-4">
|
| 27 |
+
<div className="w-10 h-10 rounded-xl flex items-center justify-center transition-transform group-hover:scale-110"
|
| 28 |
+
style={{ background: `${iconColor}15`, border: `1px solid ${iconColor}25` }}>
|
| 29 |
+
<div style={{ color: iconColor }}>{icon}</div>
|
| 30 |
+
</div>
|
| 31 |
+
{trend && (
|
| 32 |
+
<div className={cn('flex items-center gap-1 text-xs font-semibold px-2 py-1 rounded-full',
|
| 33 |
+
trendUp ? 'text-green-400 bg-green-400/10' : 'text-red-400 bg-red-400/10'
|
| 34 |
+
)}>
|
| 35 |
+
{trendUp ? <TrendingUp size={11} /> : <TrendingDown size={11} />}
|
| 36 |
+
{trend}
|
| 37 |
+
</div>
|
| 38 |
+
)}
|
| 39 |
+
</div>
|
| 40 |
+
|
| 41 |
+
<div className="flex items-end gap-1.5">
|
| 42 |
+
<span className="text-3xl font-bold text-white leading-none">{value}</span>
|
| 43 |
+
{unit && <span className="text-sm font-medium text-slate-400 mb-0.5">{unit}</span>}
|
| 44 |
+
</div>
|
| 45 |
+
<div className="text-xs font-medium mt-1.5" style={{ color: 'var(--text-secondary)' }}>{label}</div>
|
| 46 |
+
</motion.div>
|
| 47 |
+
)
|
| 48 |
+
}
|
frontend/components/dashboard/MissionInput.tsx
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useState } from 'react'
|
| 4 |
+
import { motion, AnimatePresence } from 'framer-motion'
|
| 5 |
+
import { Send, Telescope, Code2, Zap, BarChart2, PenLine, MoreHorizontal, Loader2, Mic } from 'lucide-react'
|
| 6 |
+
|
| 7 |
+
const QUICK_ACTIONS = [
|
| 8 |
+
{ icon: Telescope, label: 'Research', color: '#6366f1', prompt: 'Research the latest trends in ' },
|
| 9 |
+
{ icon: Code2, label: 'Build', color: '#34d399', prompt: 'Build and deploy a ' },
|
| 10 |
+
{ icon: Zap, label: 'Automate', color: '#f59e0b', prompt: 'Create an automation workflow for ' },
|
| 11 |
+
{ icon: BarChart2, label: 'Analyze', color: '#22d3ee', prompt: 'Analyze data and generate insights for ' },
|
| 12 |
+
{ icon: PenLine, label: 'Generate', color: '#a78bfa', prompt: 'Generate high-quality content for ' },
|
| 13 |
+
]
|
| 14 |
+
|
| 15 |
+
const EXAMPLE_PROMPTS = [
|
| 16 |
+
'Build a complete marketing analysis dashboard with AI insights',
|
| 17 |
+
'Research competitors in the SaaS market and synthesize findings',
|
| 18 |
+
'Automate my GitHub PR review workflow with AI agents',
|
| 19 |
+
'Analyze Q4 performance data and generate executive summary',
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
export default function MissionInput() {
|
| 23 |
+
const [prompt, setPrompt] = useState('')
|
| 24 |
+
const [loading, setLoading] = useState(false)
|
| 25 |
+
const [selectedAction, setSelectedAction] = useState<string | null>(null)
|
| 26 |
+
|
| 27 |
+
const handleAction = (actionPrompt: string, label: string) => {
|
| 28 |
+
setPrompt(actionPrompt)
|
| 29 |
+
setSelectedAction(label)
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
const handleSubmit = async () => {
|
| 33 |
+
if (!prompt.trim() || loading) return
|
| 34 |
+
setLoading(true)
|
| 35 |
+
await new Promise(r => setTimeout(r, 2000))
|
| 36 |
+
setLoading(false)
|
| 37 |
+
setPrompt('')
|
| 38 |
+
setSelectedAction(null)
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
const handleKeyDown = (e: React.KeyboardEvent) => {
|
| 42 |
+
if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit() }
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
return (
|
| 46 |
+
<div className="card p-5">
|
| 47 |
+
{/* Header */}
|
| 48 |
+
<div className="flex items-start gap-3 mb-4">
|
| 49 |
+
<div className="w-8 h-8 rounded-xl flex items-center justify-center flex-shrink-0"
|
| 50 |
+
style={{ background: 'rgba(124,58,237,0.15)', border: '1px solid rgba(124,58,237,0.25)' }}>
|
| 51 |
+
<Zap size={15} className="text-purple-400" />
|
| 52 |
+
</div>
|
| 53 |
+
<div>
|
| 54 |
+
<h2 className="text-base font-semibold text-white">What shall we build today?</h2>
|
| 55 |
+
<p className="text-xs mt-0.5" style={{ color: 'var(--text-secondary)' }}>
|
| 56 |
+
Describe your mission. God Agent OS will orchestrate the rest.
|
| 57 |
+
</p>
|
| 58 |
+
</div>
|
| 59 |
+
</div>
|
| 60 |
+
|
| 61 |
+
{/* Input */}
|
| 62 |
+
<div className="relative mb-3">
|
| 63 |
+
<textarea
|
| 64 |
+
value={prompt}
|
| 65 |
+
onChange={e => setPrompt(e.target.value)}
|
| 66 |
+
onKeyDown={handleKeyDown}
|
| 67 |
+
placeholder="e.g., Build a complete marketing analysis dashboard with AI insights…"
|
| 68 |
+
rows={3}
|
| 69 |
+
className="cmd-input w-full px-4 py-3 pr-12 text-sm resize-none"
|
| 70 |
+
style={{ minHeight: 88, lineHeight: 1.6 }}
|
| 71 |
+
/>
|
| 72 |
+
<div className="absolute right-3 bottom-3 flex items-center gap-2">
|
| 73 |
+
<button className="p-1.5 rounded-lg text-slate-600 hover:text-purple-400 transition-colors">
|
| 74 |
+
<Mic size={15} />
|
| 75 |
+
</button>
|
| 76 |
+
<motion.button
|
| 77 |
+
onClick={handleSubmit}
|
| 78 |
+
disabled={!prompt.trim() || loading}
|
| 79 |
+
whileHover={{ scale: 1.05 }}
|
| 80 |
+
whileTap={{ scale: 0.95 }}
|
| 81 |
+
className="w-8 h-8 rounded-lg flex items-center justify-center transition-all disabled:opacity-40"
|
| 82 |
+
style={{ background: prompt.trim() && !loading ? 'linear-gradient(135deg, #7c3aed, #4f46e5)' : 'rgba(255,255,255,0.08)' }}
|
| 83 |
+
>
|
| 84 |
+
{loading ? <Loader2 size={14} className="text-white animate-spin" /> : <Send size={14} className="text-white" />}
|
| 85 |
+
</motion.button>
|
| 86 |
+
</div>
|
| 87 |
+
</div>
|
| 88 |
+
|
| 89 |
+
{/* Quick Actions */}
|
| 90 |
+
<div className="flex flex-wrap gap-2">
|
| 91 |
+
{QUICK_ACTIONS.map(({ icon: Icon, label, color, prompt: p }) => (
|
| 92 |
+
<button
|
| 93 |
+
key={label}
|
| 94 |
+
onClick={() => handleAction(p, label)}
|
| 95 |
+
className={`chip transition-all ${selectedAction === label ? 'border-purple-500/40 bg-purple-500/10 text-purple-300' : ''}`}
|
| 96 |
+
>
|
| 97 |
+
<Icon size={12} style={{ color }} />
|
| 98 |
+
{label}
|
| 99 |
+
</button>
|
| 100 |
+
))}
|
| 101 |
+
<button className="chip">
|
| 102 |
+
<MoreHorizontal size={12} />
|
| 103 |
+
More
|
| 104 |
+
</button>
|
| 105 |
+
</div>
|
| 106 |
+
|
| 107 |
+
{/* Example prompts */}
|
| 108 |
+
<AnimatePresence>
|
| 109 |
+
{!prompt && (
|
| 110 |
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="mt-3 pt-3 border-t" style={{ borderColor: 'var(--border)' }}>
|
| 111 |
+
<div className="text-xs mb-2 font-medium" style={{ color: 'var(--text-muted)' }}>Quick start:</div>
|
| 112 |
+
<div className="space-y-1">
|
| 113 |
+
{EXAMPLE_PROMPTS.slice(0, 2).map(ep => (
|
| 114 |
+
<button key={ep} onClick={() => setPrompt(ep)}
|
| 115 |
+
className="w-full text-left text-xs px-3 py-1.5 rounded-lg hover:bg-white/[0.04] text-slate-500 hover:text-slate-300 transition-colors truncate">
|
| 116 |
+
→ {ep}
|
| 117 |
+
</button>
|
| 118 |
+
))}
|
| 119 |
+
</div>
|
| 120 |
+
</motion.div>
|
| 121 |
+
)}
|
| 122 |
+
</AnimatePresence>
|
| 123 |
+
</div>
|
| 124 |
+
)
|
| 125 |
+
}
|
frontend/components/dashboard/SystemResources.tsx
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useEffect, useState } from 'react'
|
| 4 |
+
import { motion } from 'framer-motion'
|
| 5 |
+
import { Cpu, MemoryStick, HardDrive, Wifi } from 'lucide-react'
|
| 6 |
+
import { useAppStore } from '@/store/useAppStore'
|
| 7 |
+
|
| 8 |
+
const RESOURCE_CONFIGS = [
|
| 9 |
+
{ key: 'cpu', label: 'CPU', icon: Cpu, color: '#6366f1' },
|
| 10 |
+
{ key: 'memory', label: 'Memory', icon: MemoryStick, color: '#22d3ee' },
|
| 11 |
+
{ key: 'storage', label: 'Storage', icon: HardDrive, color: '#a78bfa' },
|
| 12 |
+
{ key: 'network', label: 'Network', icon: Wifi, color: '#34d399' },
|
| 13 |
+
] as const
|
| 14 |
+
|
| 15 |
+
export default function SystemResources() {
|
| 16 |
+
const { systemResources, updateSystemResources } = useAppStore()
|
| 17 |
+
|
| 18 |
+
// Simulate live fluctuation
|
| 19 |
+
useEffect(() => {
|
| 20 |
+
const interval = setInterval(() => {
|
| 21 |
+
updateSystemResources({
|
| 22 |
+
cpu: Math.min(95, Math.max(15, systemResources.cpu + (Math.random() - 0.5) * 6)),
|
| 23 |
+
memory: Math.min(90, Math.max(40, systemResources.memory + (Math.random() - 0.5) * 3)),
|
| 24 |
+
network: Math.min(80, Math.max(10, systemResources.network + (Math.random() - 0.5) * 8)),
|
| 25 |
+
})
|
| 26 |
+
}, 3000)
|
| 27 |
+
return () => clearInterval(interval)
|
| 28 |
+
}, [systemResources, updateSystemResources])
|
| 29 |
+
|
| 30 |
+
return (
|
| 31 |
+
<div className="space-y-3">
|
| 32 |
+
{RESOURCE_CONFIGS.map(({ key, label, icon: Icon, color }) => {
|
| 33 |
+
const value = Math.round(systemResources[key])
|
| 34 |
+
return (
|
| 35 |
+
<div key={key} className="flex items-center gap-3">
|
| 36 |
+
<div className="w-6 h-6 rounded-lg flex items-center justify-center flex-shrink-0"
|
| 37 |
+
style={{ background: `${color}15` }}>
|
| 38 |
+
<Icon size={12} style={{ color }} />
|
| 39 |
+
</div>
|
| 40 |
+
<div className="flex-1 min-w-0">
|
| 41 |
+
<div className="flex items-center justify-between mb-1.5">
|
| 42 |
+
<span className="text-xs font-medium" style={{ color: 'var(--text-secondary)' }}>{label}</span>
|
| 43 |
+
<span className="text-xs font-bold" style={{ color }}>{value}%</span>
|
| 44 |
+
</div>
|
| 45 |
+
<div className="progress-bar h-1.5">
|
| 46 |
+
<motion.div
|
| 47 |
+
className="progress-fill h-full rounded-full"
|
| 48 |
+
animate={{ width: `${value}%` }}
|
| 49 |
+
transition={{ duration: 0.8, ease: 'easeOut' }}
|
| 50 |
+
style={{ background: `linear-gradient(90deg, ${color}60, ${color})` }}
|
| 51 |
+
/>
|
| 52 |
+
</div>
|
| 53 |
+
</div>
|
| 54 |
+
</div>
|
| 55 |
+
)
|
| 56 |
+
})}
|
| 57 |
+
</div>
|
| 58 |
+
)
|
| 59 |
+
}
|
frontend/components/layout/AIRouterPanel.tsx
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useEffect, useState } from 'react'
|
| 4 |
+
import { useAgentStore } from '@/hooks/useAgentStore'
|
| 5 |
+
import { Cpu, Key, RefreshCw, CheckCircle2, XCircle, AlertCircle, Zap, Activity } from 'lucide-react'
|
| 6 |
+
|
| 7 |
+
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:7860'
|
| 8 |
+
|
| 9 |
+
interface ProviderStat {
|
| 10 |
+
calls: number
|
| 11 |
+
errors: number
|
| 12 |
+
avg_latency_ms: number
|
| 13 |
+
available: boolean
|
| 14 |
+
key_count: number
|
| 15 |
+
available_keys: number
|
| 16 |
+
priority: number
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
interface KeyInfo {
|
| 20 |
+
key_preview: string
|
| 21 |
+
available: boolean
|
| 22 |
+
failures: number
|
| 23 |
+
calls: number
|
| 24 |
+
cooldown_remaining_s: number
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
interface PoolStatus {
|
| 28 |
+
provider: string
|
| 29 |
+
total_keys: number
|
| 30 |
+
available_keys: number
|
| 31 |
+
keys: KeyInfo[]
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
const PROVIDER_ICONS: Record<string, string> = {
|
| 35 |
+
sambanova: '⚡',
|
| 36 |
+
gemini: '✨',
|
| 37 |
+
openai: '🤖',
|
| 38 |
+
groq: '🦙',
|
| 39 |
+
cerebras: '🧠',
|
| 40 |
+
openrouter: '🔀',
|
| 41 |
+
anthropic: '🪄',
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
const PROVIDER_COLORS: Record<string, string> = {
|
| 45 |
+
sambanova: '#f97316',
|
| 46 |
+
gemini: '#4285f4',
|
| 47 |
+
openai: '#10a37f',
|
| 48 |
+
groq: '#f59e0b',
|
| 49 |
+
cerebras: '#8b5cf6',
|
| 50 |
+
openrouter: '#6366f1',
|
| 51 |
+
anthropic: '#d97706',
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
export default function AIRouterPanel() {
|
| 55 |
+
const { locale } = useAgentStore()
|
| 56 |
+
const [stats, setStats] = useState<Record<string, ProviderStat>>({})
|
| 57 |
+
const [pools, setPools] = useState<Record<string, PoolStatus>>({})
|
| 58 |
+
const [loading, setLoading] = useState(true)
|
| 59 |
+
const [expandedProvider, setExpandedProvider] = useState<string | null>(null)
|
| 60 |
+
const [lastRefresh, setLastRefresh] = useState<Date | null>(null)
|
| 61 |
+
|
| 62 |
+
const load = async () => {
|
| 63 |
+
setLoading(true)
|
| 64 |
+
try {
|
| 65 |
+
const [statsRes, poolRes] = await Promise.all([
|
| 66 |
+
fetch(`${API_URL}/api/v1/ai/stats`).then(r => r.json()).catch(() => ({})),
|
| 67 |
+
fetch(`${API_URL}/api/v1/ai/pool-status`).then(r => r.json()).catch(() => ({})),
|
| 68 |
+
])
|
| 69 |
+
setStats(statsRes.stats || {})
|
| 70 |
+
setPools(poolRes.pools || {})
|
| 71 |
+
setLastRefresh(new Date())
|
| 72 |
+
} catch {}
|
| 73 |
+
setLoading(false)
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
useEffect(() => {
|
| 77 |
+
load()
|
| 78 |
+
const interval = setInterval(load, 30000)
|
| 79 |
+
return () => clearInterval(interval)
|
| 80 |
+
}, [])
|
| 81 |
+
|
| 82 |
+
const sortedProviders = Object.entries(stats).sort(
|
| 83 |
+
([, a], [, b]) => (a.priority || 99) - (b.priority || 99)
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
const activeCount = sortedProviders.filter(([, s]) => s.available).length
|
| 87 |
+
const totalCalls = sortedProviders.reduce((sum, [, s]) => sum + s.calls, 0)
|
| 88 |
+
|
| 89 |
+
return (
|
| 90 |
+
<div className="flex flex-col h-full" style={{ background: 'var(--bg-2)' }}>
|
| 91 |
+
{/* Header */}
|
| 92 |
+
<div className="flex items-center justify-between px-4 py-2.5 border-b shrink-0"
|
| 93 |
+
style={{ borderColor: 'var(--border)', background: 'var(--bg-3)' }}>
|
| 94 |
+
<div className="flex items-center gap-2">
|
| 95 |
+
<Cpu size={14} className="text-indigo-400" />
|
| 96 |
+
<span className="text-sm font-semibold" style={{ color: 'var(--text-primary)' }}>
|
| 97 |
+
{locale === 'my' ? 'AI Router v8' : 'AI Router v8'}
|
| 98 |
+
</span>
|
| 99 |
+
<span className="text-[10px] px-1.5 py-0.5 rounded-full"
|
| 100 |
+
style={{
|
| 101 |
+
background: activeCount > 0 ? 'rgba(34,197,94,0.15)' : 'rgba(239,68,68,0.15)',
|
| 102 |
+
color: activeCount > 0 ? '#4ade80' : '#f87171',
|
| 103 |
+
border: `1px solid ${activeCount > 0 ? 'rgba(34,197,94,0.3)' : 'rgba(239,68,68,0.3)'}`,
|
| 104 |
+
}}>
|
| 105 |
+
{activeCount} active
|
| 106 |
+
</span>
|
| 107 |
+
</div>
|
| 108 |
+
<button onClick={load} disabled={loading}
|
| 109 |
+
className="p-1.5 rounded-lg hover:bg-white/5 transition-colors" title="Refresh">
|
| 110 |
+
<RefreshCw size={12} style={{ color: 'var(--text-muted)' }}
|
| 111 |
+
className={loading ? 'animate-spin' : ''} />
|
| 112 |
+
</button>
|
| 113 |
+
</div>
|
| 114 |
+
|
| 115 |
+
{/* Summary */}
|
| 116 |
+
<div className="px-3 py-2 border-b flex gap-3 text-xs"
|
| 117 |
+
style={{ borderColor: 'var(--border)', background: 'rgba(99,102,241,0.05)' }}>
|
| 118 |
+
<div className="flex items-center gap-1">
|
| 119 |
+
<Activity size={10} className="text-indigo-400" />
|
| 120 |
+
<span style={{ color: 'var(--text-muted)' }}>Total calls:</span>
|
| 121 |
+
<span className="font-mono font-semibold" style={{ color: 'var(--text-primary)' }}>{totalCalls}</span>
|
| 122 |
+
</div>
|
| 123 |
+
<div className="flex items-center gap-1">
|
| 124 |
+
<Key size={10} className="text-indigo-400" />
|
| 125 |
+
<span style={{ color: 'var(--text-muted)' }}>Providers:</span>
|
| 126 |
+
<span className="font-mono font-semibold" style={{ color: 'var(--text-primary)' }}>
|
| 127 |
+
{activeCount}/{sortedProviders.length}
|
| 128 |
+
</span>
|
| 129 |
+
</div>
|
| 130 |
+
{lastRefresh && (
|
| 131 |
+
<div className="ml-auto text-[10px]" style={{ color: 'var(--text-muted)' }}>
|
| 132 |
+
{lastRefresh.toLocaleTimeString()}
|
| 133 |
+
</div>
|
| 134 |
+
)}
|
| 135 |
+
</div>
|
| 136 |
+
|
| 137 |
+
{/* Provider List */}
|
| 138 |
+
<div className="flex-1 overflow-y-auto">
|
| 139 |
+
{loading && sortedProviders.length === 0 ? (
|
| 140 |
+
<div className="flex items-center justify-center h-24">
|
| 141 |
+
<div className="flex gap-1">
|
| 142 |
+
{[0, 1, 2].map(i => (
|
| 143 |
+
<div key={i} className="w-1.5 h-1.5 rounded-full animate-bounce"
|
| 144 |
+
style={{ background: 'var(--brand)', animationDelay: `${i * 0.15}s` }} />
|
| 145 |
+
))}
|
| 146 |
+
</div>
|
| 147 |
+
</div>
|
| 148 |
+
) : sortedProviders.length === 0 ? (
|
| 149 |
+
<div className="p-4 text-center text-xs" style={{ color: 'var(--text-muted)' }}>
|
| 150 |
+
No providers configured
|
| 151 |
+
</div>
|
| 152 |
+
) : (
|
| 153 |
+
<div className="p-2 flex flex-col gap-1.5">
|
| 154 |
+
{sortedProviders.map(([name, stat]) => {
|
| 155 |
+
const pool = pools[name]
|
| 156 |
+
const icon = PROVIDER_ICONS[name] || '🔌'
|
| 157 |
+
const color = PROVIDER_COLORS[name] || '#6366f1'
|
| 158 |
+
const isExpanded = expandedProvider === name
|
| 159 |
+
const successRate = stat.calls > 0
|
| 160 |
+
? Math.round(((stat.calls - stat.errors) / stat.calls) * 100)
|
| 161 |
+
: 100
|
| 162 |
+
|
| 163 |
+
return (
|
| 164 |
+
<div key={name}
|
| 165 |
+
className="rounded-xl border overflow-hidden cursor-pointer hover:border-opacity-60 transition-all"
|
| 166 |
+
style={{
|
| 167 |
+
borderColor: stat.available ? `${color}40` : 'var(--border)',
|
| 168 |
+
background: stat.available ? `${color}08` : 'var(--bg-3)',
|
| 169 |
+
}}
|
| 170 |
+
onClick={() => setExpandedProvider(isExpanded ? null : name)}>
|
| 171 |
+
|
| 172 |
+
{/* Provider Header */}
|
| 173 |
+
<div className="flex items-center gap-2 px-3 py-2">
|
| 174 |
+
<span className="text-sm">{icon}</span>
|
| 175 |
+
<div className="flex-1 min-w-0">
|
| 176 |
+
<div className="flex items-center gap-2">
|
| 177 |
+
<span className="text-xs font-semibold capitalize" style={{ color: 'var(--text-primary)' }}>
|
| 178 |
+
{name}
|
| 179 |
+
</span>
|
| 180 |
+
{stat.priority <= 2 && (
|
| 181 |
+
<span className="text-[9px] px-1 py-0.5 rounded font-bold"
|
| 182 |
+
style={{ background: `${color}25`, color }}>
|
| 183 |
+
PRIMARY
|
| 184 |
+
</span>
|
| 185 |
+
)}
|
| 186 |
+
</div>
|
| 187 |
+
<div className="flex items-center gap-2 mt-0.5">
|
| 188 |
+
<span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
|
| 189 |
+
{stat.calls} calls · {stat.avg_latency_ms}ms avg
|
| 190 |
+
</span>
|
| 191 |
+
{pool && (
|
| 192 |
+
<span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
|
| 193 |
+
· {pool.available_keys}/{pool.total_keys} keys
|
| 194 |
+
</span>
|
| 195 |
+
)}
|
| 196 |
+
</div>
|
| 197 |
+
</div>
|
| 198 |
+
<div className="flex items-center gap-1.5">
|
| 199 |
+
{/* Success Rate Bar */}
|
| 200 |
+
{stat.calls > 0 && (
|
| 201 |
+
<div className="w-12 h-1.5 rounded-full overflow-hidden"
|
| 202 |
+
style={{ background: 'var(--bg-0)' }}>
|
| 203 |
+
<div className="h-full rounded-full transition-all"
|
| 204 |
+
style={{
|
| 205 |
+
width: `${successRate}%`,
|
| 206 |
+
background: successRate > 80 ? '#4ade80' : successRate > 50 ? '#fbbf24' : '#f87171',
|
| 207 |
+
}} />
|
| 208 |
+
</div>
|
| 209 |
+
)}
|
| 210 |
+
{stat.available ? (
|
| 211 |
+
<CheckCircle2 size={12} style={{ color: '#4ade80' }} />
|
| 212 |
+
) : (
|
| 213 |
+
<XCircle size={12} style={{ color: '#f87171' }} />
|
| 214 |
+
)}
|
| 215 |
+
</div>
|
| 216 |
+
</div>
|
| 217 |
+
|
| 218 |
+
{/* Expanded Key Pool */}
|
| 219 |
+
{isExpanded && pool && pool.keys.length > 0 && (
|
| 220 |
+
<div className="px-3 pb-3 border-t" style={{ borderColor: 'var(--border)' }}>
|
| 221 |
+
<div className="pt-2 text-[10px] font-semibold mb-2" style={{ color: 'var(--text-muted)' }}>
|
| 222 |
+
KEY POOL ({pool.available_keys}/{pool.total_keys} available)
|
| 223 |
+
</div>
|
| 224 |
+
<div className="flex flex-col gap-1">
|
| 225 |
+
{pool.keys.map((k, i) => (
|
| 226 |
+
<div key={i} className="flex items-center gap-2 px-2 py-1 rounded-lg"
|
| 227 |
+
style={{ background: k.available ? 'rgba(34,197,94,0.05)' : 'rgba(239,68,68,0.05)' }}>
|
| 228 |
+
<Key size={9} style={{ color: k.available ? '#4ade80' : '#f87171' }} />
|
| 229 |
+
<span className="font-mono text-[10px] flex-1" style={{ color: 'var(--text-secondary)' }}>
|
| 230 |
+
{k.key_preview}
|
| 231 |
+
</span>
|
| 232 |
+
<span className="text-[9px]" style={{ color: 'var(--text-muted)' }}>
|
| 233 |
+
{k.calls} calls
|
| 234 |
+
</span>
|
| 235 |
+
{k.failures > 0 && (
|
| 236 |
+
<span className="text-[9px]" style={{ color: '#fbbf24' }}>
|
| 237 |
+
{k.failures} fails
|
| 238 |
+
</span>
|
| 239 |
+
)}
|
| 240 |
+
{!k.available && k.cooldown_remaining_s > 0 && (
|
| 241 |
+
<span className="text-[9px] px-1 rounded"
|
| 242 |
+
style={{ background: 'rgba(239,68,68,0.15)', color: '#f87171' }}>
|
| 243 |
+
{Math.round(k.cooldown_remaining_s)}s
|
| 244 |
+
</span>
|
| 245 |
+
)}
|
| 246 |
+
</div>
|
| 247 |
+
))}
|
| 248 |
+
</div>
|
| 249 |
+
</div>
|
| 250 |
+
)}
|
| 251 |
+
</div>
|
| 252 |
+
)
|
| 253 |
+
})}
|
| 254 |
+
</div>
|
| 255 |
+
)}
|
| 256 |
+
</div>
|
| 257 |
+
|
| 258 |
+
{/* Footer Info */}
|
| 259 |
+
<div className="px-3 py-2 border-t text-[10px]"
|
| 260 |
+
style={{ borderColor: 'var(--border)', color: 'var(--text-muted)', background: 'var(--bg-3)' }}>
|
| 261 |
+
<div className="flex items-center gap-1">
|
| 262 |
+
<Zap size={9} className="text-indigo-400" />
|
| 263 |
+
<span>Priority: SambaNova → Gemini → OpenAI → Groq → Cerebras → Anthropic</span>
|
| 264 |
+
</div>
|
| 265 |
+
</div>
|
| 266 |
+
</div>
|
| 267 |
+
)
|
| 268 |
+
}
|
frontend/components/layout/Sidebar.tsx
CHANGED
|
@@ -17,6 +17,7 @@ const PANELS: { id: ActivePanel; icon: React.ElementType; labelEn: string; label
|
|
| 17 |
{ id: 'browser', icon: Globe, labelEn: 'Browser', labelMy: 'ဘရောင်ဇာ', badge: 'v7' },
|
| 18 |
{ id: 'memory', icon: Brain, labelEn: 'Memory', labelMy: 'မှတ်ဉာဏ်' },
|
| 19 |
{ id: 'connectors', icon: Plug, labelEn: 'Connectors', labelMy: 'ချိတ်ဆက်မှု' },
|
|
|
|
| 20 |
]
|
| 21 |
|
| 22 |
const AGENT_META: Record<string, { icon: React.ElementType; color: string; label: string; isNew?: boolean }> = {
|
|
@@ -128,7 +129,7 @@ export default function Sidebar() {
|
|
| 128 |
<div className="flex items-center gap-2 px-2 py-1.5 rounded-lg text-[10px]"
|
| 129 |
style={{ background: 'rgba(99,102,241,0.08)', border: '1px solid rgba(99,102,241,0.2)' }}>
|
| 130 |
<Bot size={10} className="text-indigo-400" />
|
| 131 |
-
<span style={{ color: 'var(--text-muted)' }}>God Agent OS
|
| 132 |
<div className="ml-auto w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse" />
|
| 133 |
</div>
|
| 134 |
</div>
|
|
|
|
| 17 |
{ id: 'browser', icon: Globe, labelEn: 'Browser', labelMy: 'ဘရောင်ဇာ', badge: 'v7' },
|
| 18 |
{ id: 'memory', icon: Brain, labelEn: 'Memory', labelMy: 'မှတ်ဉာဏ်' },
|
| 19 |
{ id: 'connectors', icon: Plug, labelEn: 'Connectors', labelMy: 'ချိတ်ဆက်မှု' },
|
| 20 |
+
{ id: 'ai_router', icon: Cpu, labelEn: 'AI Router', labelMy: 'AI Router', badge: 'v8' },
|
| 21 |
]
|
| 22 |
|
| 23 |
const AGENT_META: Record<string, { icon: React.ElementType; color: string; label: string; isNew?: boolean }> = {
|
|
|
|
| 129 |
<div className="flex items-center gap-2 px-2 py-1.5 rounded-lg text-[10px]"
|
| 130 |
style={{ background: 'rgba(99,102,241,0.08)', border: '1px solid rgba(99,102,241,0.2)' }}>
|
| 131 |
<Bot size={10} className="text-indigo-400" />
|
| 132 |
+
<span style={{ color: 'var(--text-muted)' }}>God Agent OS v8.0</span>
|
| 133 |
<div className="ml-auto w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse" />
|
| 134 |
</div>
|
| 135 |
</div>
|
frontend/components/pages/AgentsPage.tsx
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useState } from 'react'
|
| 4 |
+
import { motion } from 'framer-motion'
|
| 5 |
+
import { Search, Filter, Plus, Bot, Activity, Zap } from 'lucide-react'
|
| 6 |
+
import { AGENTS, Agent } from '@/store/useAppStore'
|
| 7 |
+
import { getStatusColor, cn } from '@/lib/utils'
|
| 8 |
+
|
| 9 |
+
const STATUS_FILTERS = ['All', 'Active', 'Processing', 'Idle', 'Error']
|
| 10 |
+
|
| 11 |
+
function AgentDetailCard({ agent }: { agent: Agent }) {
|
| 12 |
+
const sc = getStatusColor(agent.status)
|
| 13 |
+
return (
|
| 14 |
+
<motion.div layout className="card p-5 relative overflow-hidden group">
|
| 15 |
+
<div className="absolute top-0 left-0 right-0 h-[2px]"
|
| 16 |
+
style={{ background: `linear-gradient(90deg, ${agent.color}, transparent)` }} />
|
| 17 |
+
|
| 18 |
+
<div className="flex items-start gap-4 mb-4">
|
| 19 |
+
<div className="w-12 h-12 rounded-2xl flex items-center justify-center text-2xl flex-shrink-0"
|
| 20 |
+
style={{ background: `${agent.color}15`, border: `1px solid ${agent.color}25` }}>
|
| 21 |
+
{agent.icon}
|
| 22 |
+
</div>
|
| 23 |
+
<div className="flex-1 min-w-0">
|
| 24 |
+
<div className="flex items-center gap-2">
|
| 25 |
+
<h3 className="font-bold text-white">{agent.name}</h3>
|
| 26 |
+
<div className="flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-semibold"
|
| 27 |
+
style={{ background: `${sc}15`, color: sc }}>
|
| 28 |
+
<div className="w-1.5 h-1.5 rounded-full" style={{ background: sc }} />
|
| 29 |
+
{agent.status}
|
| 30 |
+
</div>
|
| 31 |
+
</div>
|
| 32 |
+
<p className="text-sm mt-0.5" style={{ color: 'var(--text-secondary)' }}>{agent.role}</p>
|
| 33 |
+
<p className="text-xs mt-2 text-slate-500">{agent.lastAction} · {agent.lastActionTime}</p>
|
| 34 |
+
</div>
|
| 35 |
+
<div className="text-right">
|
| 36 |
+
<div className="text-xs text-slate-500 mb-0.5">Tasks</div>
|
| 37 |
+
<div className="text-xl font-bold text-white">{agent.tasks}</div>
|
| 38 |
+
</div>
|
| 39 |
+
</div>
|
| 40 |
+
|
| 41 |
+
<div className="grid grid-cols-2 gap-4">
|
| 42 |
+
<div>
|
| 43 |
+
<div className="flex items-center justify-between mb-1.5">
|
| 44 |
+
<span className="text-xs text-slate-500">Efficiency</span>
|
| 45 |
+
<span className="text-xs font-bold" style={{ color: agent.color }}>{agent.efficiency}%</span>
|
| 46 |
+
</div>
|
| 47 |
+
<div className="progress-bar">
|
| 48 |
+
<div className="progress-fill" style={{ width: `${agent.efficiency}%`, background: `linear-gradient(90deg, ${agent.color}60, ${agent.color})` }} />
|
| 49 |
+
</div>
|
| 50 |
+
</div>
|
| 51 |
+
<div>
|
| 52 |
+
<div className="flex items-center justify-between mb-1.5">
|
| 53 |
+
<span className="text-xs text-slate-500">Uptime</span>
|
| 54 |
+
<span className="text-xs font-bold text-cyan-400">{agent.uptime}%</span>
|
| 55 |
+
</div>
|
| 56 |
+
<div className="progress-bar">
|
| 57 |
+
<div className="progress-fill" style={{ width: `${agent.uptime}%`, background: 'linear-gradient(90deg, #22d3ee60, #22d3ee)' }} />
|
| 58 |
+
</div>
|
| 59 |
+
</div>
|
| 60 |
+
</div>
|
| 61 |
+
|
| 62 |
+
<div className="flex gap-2 mt-4">
|
| 63 |
+
<button className="flex-1 py-2 rounded-xl text-xs font-semibold transition-all hover:opacity-90"
|
| 64 |
+
style={{ background: `${agent.color}18`, border: `1px solid ${agent.color}30`, color: agent.color }}>
|
| 65 |
+
View Details
|
| 66 |
+
</button>
|
| 67 |
+
<button className="flex-1 py-2 rounded-xl text-xs font-semibold transition-all hover:opacity-90"
|
| 68 |
+
style={{ background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.08)', color: 'var(--text-secondary)' }}>
|
| 69 |
+
Assign Task
|
| 70 |
+
</button>
|
| 71 |
+
</div>
|
| 72 |
+
</motion.div>
|
| 73 |
+
)
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
export default function AgentsPage() {
|
| 77 |
+
const [search, setSearch] = useState('')
|
| 78 |
+
const [statusFilter, setStatusFilter] = useState('All')
|
| 79 |
+
|
| 80 |
+
const filtered = AGENTS.filter(a =>
|
| 81 |
+
(statusFilter === 'All' || a.status === statusFilter.toLowerCase()) &&
|
| 82 |
+
(search === '' || a.name.toLowerCase().includes(search.toLowerCase()))
|
| 83 |
+
)
|
| 84 |
+
|
| 85 |
+
const activeCount = AGENTS.filter(a => a.status === 'active').length
|
| 86 |
+
const processingCount = AGENTS.filter(a => a.status === 'processing').length
|
| 87 |
+
|
| 88 |
+
return (
|
| 89 |
+
<div className="h-full overflow-y-auto p-6">
|
| 90 |
+
{/* Header */}
|
| 91 |
+
<div className="flex items-start justify-between mb-6">
|
| 92 |
+
<div>
|
| 93 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 94 |
+
<Bot size={22} className="text-purple-400" /> Agent Fleet
|
| 95 |
+
</h1>
|
| 96 |
+
<p className="text-sm mt-1 text-slate-500">
|
| 97 |
+
{activeCount} active · {processingCount} processing · {AGENTS.length} total agents deployed
|
| 98 |
+
</p>
|
| 99 |
+
</div>
|
| 100 |
+
<button className="flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-semibold text-white transition-all hover:opacity-90"
|
| 101 |
+
style={{ background: 'linear-gradient(135deg, #7c3aed, #4f46e5)', boxShadow: '0 0 20px rgba(124,58,237,0.3)' }}>
|
| 102 |
+
<Plus size={15} /> Deploy Agent
|
| 103 |
+
</button>
|
| 104 |
+
</div>
|
| 105 |
+
|
| 106 |
+
{/* Stats */}
|
| 107 |
+
<div className="grid grid-cols-4 gap-4 mb-6">
|
| 108 |
+
{[
|
| 109 |
+
{ label: 'Active', value: activeCount, color: '#22c55e' },
|
| 110 |
+
{ label: 'Processing', value: processingCount, color: '#f59e0b' },
|
| 111 |
+
{ label: 'Idle', value: AGENTS.filter(a => a.status === 'idle').length, color: '#94a3b8' },
|
| 112 |
+
{ label: 'Total Tasks', value: AGENTS.reduce((acc, a) => acc + a.tasks, 0), color: '#6366f1' },
|
| 113 |
+
].map(stat => (
|
| 114 |
+
<div key={stat.label} className="card p-4 text-center">
|
| 115 |
+
<div className="text-2xl font-bold text-white">{stat.value}</div>
|
| 116 |
+
<div className="text-xs mt-1 font-medium" style={{ color: stat.color }}>{stat.label}</div>
|
| 117 |
+
</div>
|
| 118 |
+
))}
|
| 119 |
+
</div>
|
| 120 |
+
|
| 121 |
+
{/* Search & Filter */}
|
| 122 |
+
<div className="flex gap-3 mb-6">
|
| 123 |
+
<div className="relative flex-1 max-w-sm">
|
| 124 |
+
<Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500" />
|
| 125 |
+
<input value={search} onChange={e => setSearch(e.target.value)}
|
| 126 |
+
placeholder="Search agents…"
|
| 127 |
+
className="cmd-input w-full pl-9 pr-4 py-2.5 text-sm" />
|
| 128 |
+
</div>
|
| 129 |
+
<div className="flex gap-2">
|
| 130 |
+
{STATUS_FILTERS.map(f => (
|
| 131 |
+
<button key={f} onClick={() => setStatusFilter(f)}
|
| 132 |
+
className={cn('px-3 py-2 rounded-xl text-xs font-semibold transition-all',
|
| 133 |
+
statusFilter === f
|
| 134 |
+
? 'bg-purple-600/20 text-purple-300 border border-purple-500/30'
|
| 135 |
+
: 'text-slate-500 hover:text-slate-300 border border-transparent hover:border-white/10'
|
| 136 |
+
)}>
|
| 137 |
+
{f}
|
| 138 |
+
</button>
|
| 139 |
+
))}
|
| 140 |
+
</div>
|
| 141 |
+
</div>
|
| 142 |
+
|
| 143 |
+
{/* Grid */}
|
| 144 |
+
<motion.div layout className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
|
| 145 |
+
{filtered.map((agent, i) => (
|
| 146 |
+
<motion.div key={agent.id} initial={{ opacity: 0, y: 16 }} animate={{ opacity: 1, y: 0 }}
|
| 147 |
+
transition={{ delay: i * 0.05 }}>
|
| 148 |
+
<AgentDetailCard agent={agent} />
|
| 149 |
+
</motion.div>
|
| 150 |
+
))}
|
| 151 |
+
{filtered.length === 0 && (
|
| 152 |
+
<div className="col-span-3 text-center py-16 text-slate-600">No agents match the filter</div>
|
| 153 |
+
)}
|
| 154 |
+
</motion.div>
|
| 155 |
+
</div>
|
| 156 |
+
)
|
| 157 |
+
}
|
frontend/components/pages/AnalyticsPage.tsx
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { BarChart3, TrendingUp, Clock, CheckSquare, Zap } from 'lucide-react'
|
| 5 |
+
import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, LineChart, Line, AreaChart, Area } from 'recharts'
|
| 6 |
+
|
| 7 |
+
const WEEKLY_DATA = [
|
| 8 |
+
{ day: 'Mon', tasks: 28, efficiency: 91 },
|
| 9 |
+
{ day: 'Tue', tasks: 35, efficiency: 94 },
|
| 10 |
+
{ day: 'Wed', tasks: 42, efficiency: 96 },
|
| 11 |
+
{ day: 'Thu', tasks: 31, efficiency: 89 },
|
| 12 |
+
{ day: 'Fri', tasks: 55, efficiency: 98 },
|
| 13 |
+
{ day: 'Sat', tasks: 22, efficiency: 92 },
|
| 14 |
+
{ day: 'Sun', tasks: 34, efficiency: 97 },
|
| 15 |
+
]
|
| 16 |
+
|
| 17 |
+
const AGENT_PERF = [
|
| 18 |
+
{ name: 'Code', tasks: 62, success: 99 },
|
| 19 |
+
{ name: 'Data', tasks: 83, success: 98 },
|
| 20 |
+
{ name: 'Research', tasks: 47, success: 92 },
|
| 21 |
+
{ name: 'Content', tasks: 31, success: 95 },
|
| 22 |
+
{ name: 'Design', tasks: 24, success: 90 },
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
const customTooltipStyle = {
|
| 26 |
+
background: 'rgba(14,17,33,0.95)',
|
| 27 |
+
border: '1px solid rgba(255,255,255,0.08)',
|
| 28 |
+
borderRadius: 10,
|
| 29 |
+
padding: '8px 12px',
|
| 30 |
+
fontSize: 12,
|
| 31 |
+
color: '#e2e8f0',
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
export default function AnalyticsPage() {
|
| 35 |
+
return (
|
| 36 |
+
<div className="h-full overflow-y-auto p-6">
|
| 37 |
+
<div className="mb-6">
|
| 38 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 39 |
+
<BarChart3 size={22} className="text-purple-400" /> Analytics
|
| 40 |
+
</h1>
|
| 41 |
+
<p className="text-sm mt-1 text-slate-500">Performance insights across all agents and tasks</p>
|
| 42 |
+
</div>
|
| 43 |
+
|
| 44 |
+
{/* KPI Row */}
|
| 45 |
+
<div className="grid grid-cols-4 gap-4 mb-6">
|
| 46 |
+
{[
|
| 47 |
+
{ label: 'Tasks This Week', value: '247', delta: '+37%', color: '#6366f1', icon: CheckSquare },
|
| 48 |
+
{ label: 'Avg Efficiency', value: '95.2%', delta: '+3.1%', color: '#22c55e', icon: TrendingUp },
|
| 49 |
+
{ label: 'Time Saved', value: '128h', delta: '+55%', color: '#22d3ee', icon: Clock },
|
| 50 |
+
{ label: 'Success Rate', value: '98.6%', delta: '+1.2%', color: '#a78bfa', icon: Zap },
|
| 51 |
+
].map(kpi => (
|
| 52 |
+
<div key={kpi.label} className="card p-4">
|
| 53 |
+
<div className="flex items-center gap-2 mb-3">
|
| 54 |
+
<div className="w-7 h-7 rounded-lg flex items-center justify-center"
|
| 55 |
+
style={{ background: `${kpi.color}15` }}>
|
| 56 |
+
<kpi.icon size={13} style={{ color: kpi.color }} />
|
| 57 |
+
</div>
|
| 58 |
+
<span className="text-xs text-slate-500">{kpi.label}</span>
|
| 59 |
+
</div>
|
| 60 |
+
<div className="text-2xl font-bold text-white">{kpi.value}</div>
|
| 61 |
+
<div className="text-xs mt-1 font-semibold text-green-400">{kpi.delta} vs last week</div>
|
| 62 |
+
</div>
|
| 63 |
+
))}
|
| 64 |
+
</div>
|
| 65 |
+
|
| 66 |
+
<div className="grid grid-cols-2 gap-4 mb-4">
|
| 67 |
+
{/* Tasks Chart */}
|
| 68 |
+
<div className="card p-5">
|
| 69 |
+
<h3 className="text-sm font-bold text-white mb-4">Weekly Task Completion</h3>
|
| 70 |
+
<ResponsiveContainer width="100%" height={180}>
|
| 71 |
+
<AreaChart data={WEEKLY_DATA}>
|
| 72 |
+
<defs>
|
| 73 |
+
<linearGradient id="taskGrad" x1="0" y1="0" x2="0" y2="1">
|
| 74 |
+
<stop offset="5%" stopColor="#7c3aed" stopOpacity={0.3} />
|
| 75 |
+
<stop offset="95%" stopColor="#7c3aed" stopOpacity={0} />
|
| 76 |
+
</linearGradient>
|
| 77 |
+
</defs>
|
| 78 |
+
<XAxis dataKey="day" tick={{ fill: '#475569', fontSize: 11 }} axisLine={false} tickLine={false} />
|
| 79 |
+
<YAxis tick={{ fill: '#475569', fontSize: 11 }} axisLine={false} tickLine={false} />
|
| 80 |
+
<Tooltip contentStyle={customTooltipStyle} />
|
| 81 |
+
<Area type="monotone" dataKey="tasks" stroke="#8b5cf6" strokeWidth={2} fill="url(#taskGrad)" />
|
| 82 |
+
</AreaChart>
|
| 83 |
+
</ResponsiveContainer>
|
| 84 |
+
</div>
|
| 85 |
+
|
| 86 |
+
{/* Efficiency Chart */}
|
| 87 |
+
<div className="card p-5">
|
| 88 |
+
<h3 className="text-sm font-bold text-white mb-4">Agent Efficiency Scores</h3>
|
| 89 |
+
<ResponsiveContainer width="100%" height={180}>
|
| 90 |
+
<BarChart data={AGENT_PERF} barSize={28}>
|
| 91 |
+
<XAxis dataKey="name" tick={{ fill: '#475569', fontSize: 11 }} axisLine={false} tickLine={false} />
|
| 92 |
+
<YAxis domain={[80, 100]} tick={{ fill: '#475569', fontSize: 11 }} axisLine={false} tickLine={false} />
|
| 93 |
+
<Tooltip contentStyle={customTooltipStyle} />
|
| 94 |
+
<Bar dataKey="success" fill="#22d3ee" radius={[4, 4, 0, 0]} />
|
| 95 |
+
</BarChart>
|
| 96 |
+
</ResponsiveContainer>
|
| 97 |
+
</div>
|
| 98 |
+
</div>
|
| 99 |
+
|
| 100 |
+
{/* Agent Performance Table */}
|
| 101 |
+
<div className="card p-5">
|
| 102 |
+
<h3 className="text-sm font-bold text-white mb-4">Agent Performance Breakdown</h3>
|
| 103 |
+
<div className="space-y-3">
|
| 104 |
+
{AGENT_PERF.map(agent => (
|
| 105 |
+
<div key={agent.name} className="flex items-center gap-4">
|
| 106 |
+
<span className="text-sm text-slate-400 w-24">{agent.name}</span>
|
| 107 |
+
<div className="flex-1 progress-bar">
|
| 108 |
+
<motion.div className="progress-fill"
|
| 109 |
+
initial={{ width: 0 }} animate={{ width: `${agent.success}%` }}
|
| 110 |
+
transition={{ duration: 1 }}
|
| 111 |
+
style={{ background: 'linear-gradient(90deg, #7c3aed60, #22d3ee)' }} />
|
| 112 |
+
</div>
|
| 113 |
+
<span className="text-xs font-bold text-white w-12 text-right">{agent.success}%</span>
|
| 114 |
+
<span className="text-xs text-slate-600 w-16 text-right">{agent.tasks} tasks</span>
|
| 115 |
+
</div>
|
| 116 |
+
))}
|
| 117 |
+
</div>
|
| 118 |
+
</div>
|
| 119 |
+
</div>
|
| 120 |
+
)
|
| 121 |
+
}
|
frontend/components/pages/DashboardPage.tsx
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { Bot, CheckSquare, Clock, TrendingUp, ChevronRight } from 'lucide-react'
|
| 5 |
+
import MetricCard from '@/components/dashboard/MetricCard'
|
| 6 |
+
import AgentFleetCard from '@/components/dashboard/AgentFleetCard'
|
| 7 |
+
import ActivityFeed from '@/components/dashboard/ActivityFeed'
|
| 8 |
+
import SystemResources from '@/components/dashboard/SystemResources'
|
| 9 |
+
import MissionInput from '@/components/dashboard/MissionInput'
|
| 10 |
+
import GodModeCard from '@/components/dashboard/GodModeCard'
|
| 11 |
+
import { useAppStore, AGENTS } from '@/store/useAppStore'
|
| 12 |
+
import CommandCenter from '@/components/dashboard/CommandCenter'
|
| 13 |
+
|
| 14 |
+
const METRICS = [
|
| 15 |
+
{ label: 'Total Agents', value: 12, trend: '+2 this week', trendUp: true, icon: <Bot size={18} />, iconColor: '#6366f1' },
|
| 16 |
+
{ label: 'Tasks Completed', value: 247, trend: '+37% this week', trendUp: true, icon: <CheckSquare size={18} />, iconColor: '#22c55e' },
|
| 17 |
+
{ label: 'Time Saved', value: 128, unit: 'h', trend: '+55% this week', trendUp: true, icon: <Clock size={18} />, iconColor: '#22d3ee' },
|
| 18 |
+
{ label: 'Success Rate', value: '98.6', unit: '%', trend: '1.2% this week', trendUp: true, icon: <TrendingUp size={18} />, iconColor: '#a78bfa' },
|
| 19 |
+
]
|
| 20 |
+
|
| 21 |
+
export default function DashboardPage() {
|
| 22 |
+
const { setCurrentPage } = useAppStore()
|
| 23 |
+
const featuredAgents = AGENTS.slice(0, 6)
|
| 24 |
+
|
| 25 |
+
return (
|
| 26 |
+
<div className="h-full overflow-y-auto">
|
| 27 |
+
<div className="flex h-full">
|
| 28 |
+
{/* Main content */}
|
| 29 |
+
<div className="flex-1 min-w-0 p-6 overflow-y-auto">
|
| 30 |
+
|
| 31 |
+
{/* Welcome Header */}
|
| 32 |
+
<motion.div initial={{ opacity: 0, y: -8 }} animate={{ opacity: 1, y: 0 }} className="mb-6">
|
| 33 |
+
<h1 className="text-2xl font-bold text-white">
|
| 34 |
+
Welcome back, <span className="gradient-text-purple">Creator.</span>
|
| 35 |
+
</h1>
|
| 36 |
+
<p className="text-sm mt-1" style={{ color: 'var(--text-secondary)' }}>
|
| 37 |
+
Where Intelligence, Autonomy and Execution become{' '}
|
| 38 |
+
<span className="gradient-text font-semibold">Divine.</span>
|
| 39 |
+
</p>
|
| 40 |
+
</motion.div>
|
| 41 |
+
|
| 42 |
+
{/* Metrics Row */}
|
| 43 |
+
<div className="grid grid-cols-2 xl:grid-cols-4 gap-4 mb-6">
|
| 44 |
+
{METRICS.map((m, i) => (
|
| 45 |
+
<MetricCard key={m.label} {...m} delay={i * 0.06} />
|
| 46 |
+
))}
|
| 47 |
+
</div>
|
| 48 |
+
|
| 49 |
+
{/* Mission Input */}
|
| 50 |
+
<div className="mb-6">
|
| 51 |
+
<MissionInput />
|
| 52 |
+
</div>
|
| 53 |
+
|
| 54 |
+
{/* Agent Fleet */}
|
| 55 |
+
<div className="mb-6">
|
| 56 |
+
<div className="flex items-center justify-between mb-4">
|
| 57 |
+
<div>
|
| 58 |
+
<h2 className="text-sm font-bold text-white">Agent Fleet</h2>
|
| 59 |
+
<p className="text-xs mt-0.5" style={{ color: 'var(--text-secondary)' }}>Manage your autonomous workforce</p>
|
| 60 |
+
</div>
|
| 61 |
+
<button onClick={() => setCurrentPage('agents')}
|
| 62 |
+
className="flex items-center gap-1 text-xs font-medium text-purple-400 hover:text-purple-300 transition-colors">
|
| 63 |
+
View all agents <ChevronRight size={13} />
|
| 64 |
+
</button>
|
| 65 |
+
</div>
|
| 66 |
+
<div className="grid grid-cols-2 xl:grid-cols-3 gap-3">
|
| 67 |
+
{featuredAgents.map((agent, i) => (
|
| 68 |
+
<AgentFleetCard key={agent.id} agent={agent} delay={0.1 + i * 0.05}
|
| 69 |
+
onClick={() => setCurrentPage('agents')} />
|
| 70 |
+
))}
|
| 71 |
+
</div>
|
| 72 |
+
</div>
|
| 73 |
+
|
| 74 |
+
{/* Command Center */}
|
| 75 |
+
<CommandCenter />
|
| 76 |
+
</div>
|
| 77 |
+
|
| 78 |
+
{/* Right Panel */}
|
| 79 |
+
<div className="w-72 xl:w-80 flex-shrink-0 border-l p-4 space-y-4 overflow-y-auto hide-lg"
|
| 80 |
+
style={{ borderColor: 'var(--border)' }}>
|
| 81 |
+
|
| 82 |
+
<GodModeCard />
|
| 83 |
+
|
| 84 |
+
{/* Recent Activity */}
|
| 85 |
+
<div className="card p-4">
|
| 86 |
+
<div className="flex items-center justify-between mb-3">
|
| 87 |
+
<h3 className="text-sm font-bold text-white">Recent Activity</h3>
|
| 88 |
+
<button className="text-xs text-purple-400 hover:text-purple-300 transition-colors">View all</button>
|
| 89 |
+
</div>
|
| 90 |
+
<ActivityFeed max={5} />
|
| 91 |
+
</div>
|
| 92 |
+
|
| 93 |
+
{/* System Resources */}
|
| 94 |
+
<div className="card p-4">
|
| 95 |
+
<div className="flex items-center justify-between mb-4">
|
| 96 |
+
<h3 className="text-sm font-bold text-white">System Resources</h3>
|
| 97 |
+
<button className="text-xs text-purple-400 hover:text-purple-300 transition-colors">Details</button>
|
| 98 |
+
</div>
|
| 99 |
+
<SystemResources />
|
| 100 |
+
</div>
|
| 101 |
+
|
| 102 |
+
{/* Branding Footer */}
|
| 103 |
+
<div className="px-1 py-2 text-center">
|
| 104 |
+
<div className="text-xs font-bold text-slate-600 mb-0.5">manus + genspark</div>
|
| 105 |
+
<div className="text-xs" style={{ color: 'var(--text-muted)' }}>
|
| 106 |
+
Human Creativity × AI Capability = Divine Impact
|
| 107 |
+
</div>
|
| 108 |
+
</div>
|
| 109 |
+
</div>
|
| 110 |
+
</div>
|
| 111 |
+
</div>
|
| 112 |
+
)
|
| 113 |
+
}
|
frontend/components/pages/KnowledgePage.tsx
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { BookOpen, FileText, Globe, Code2, BarChart3, Search, Plus } from 'lucide-react'
|
| 5 |
+
|
| 6 |
+
const KNOWLEDGE_BASES = [
|
| 7 |
+
{ id: 1, name: 'Product Documentation', desc: 'Internal product specs and API docs', docs: 342, icon: FileText, color: '#6366f1', updated: '1h ago' },
|
| 8 |
+
{ id: 2, name: 'Market Intelligence', desc: 'Industry reports and competitor analysis', docs: 87, icon: Globe, color: '#22d3ee', updated: '2h ago' },
|
| 9 |
+
{ id: 3, name: 'Codebase Knowledge', desc: 'Source code patterns and architecture', docs: 1240, icon: Code2, color: '#34d399', updated: '30m ago' },
|
| 10 |
+
{ id: 4, name: 'Analytics Data', desc: 'Historical metrics and performance data', docs: 512, icon: BarChart3, color: '#a78bfa', updated: '15m ago' },
|
| 11 |
+
{ id: 5, name: 'Research Library', desc: 'Academic papers and research synthesis', docs: 234, icon: BookOpen, color: '#f59e0b', updated: '3h ago' },
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
export default function KnowledgePage() {
|
| 15 |
+
return (
|
| 16 |
+
<div className="h-full overflow-y-auto p-6">
|
| 17 |
+
<div className="flex items-center justify-between mb-6">
|
| 18 |
+
<div>
|
| 19 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 20 |
+
<BookOpen size={22} className="text-purple-400" /> Knowledge Base
|
| 21 |
+
</h1>
|
| 22 |
+
<p className="text-sm mt-1 text-slate-500">2,415 documents indexed across 5 knowledge bases</p>
|
| 23 |
+
</div>
|
| 24 |
+
<div className="flex items-center gap-3">
|
| 25 |
+
<div className="relative">
|
| 26 |
+
<Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500" />
|
| 27 |
+
<input placeholder="Search knowledge…" className="cmd-input pl-9 pr-4 py-2.5 text-sm w-56" />
|
| 28 |
+
</div>
|
| 29 |
+
<button className="flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-semibold text-white hover:opacity-90 transition-all"
|
| 30 |
+
style={{ background: 'linear-gradient(135deg, #7c3aed, #4f46e5)', boxShadow: '0 0 20px rgba(124,58,237,0.3)' }}>
|
| 31 |
+
<Plus size={15} /> Add Source
|
| 32 |
+
</button>
|
| 33 |
+
</div>
|
| 34 |
+
</div>
|
| 35 |
+
|
| 36 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
|
| 37 |
+
{KNOWLEDGE_BASES.map((kb, i) => (
|
| 38 |
+
<motion.div key={kb.id} initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }}
|
| 39 |
+
transition={{ delay: i * 0.07 }} className="card p-5 cursor-pointer group relative overflow-hidden">
|
| 40 |
+
<div className="absolute top-0 left-0 right-0 h-[2px]"
|
| 41 |
+
style={{ background: `linear-gradient(90deg, ${kb.color}, transparent)` }} />
|
| 42 |
+
|
| 43 |
+
<div className="flex items-start gap-4 mb-4">
|
| 44 |
+
<div className="w-11 h-11 rounded-2xl flex items-center justify-center flex-shrink-0"
|
| 45 |
+
style={{ background: `${kb.color}15`, border: `1px solid ${kb.color}25` }}>
|
| 46 |
+
<kb.icon size={18} style={{ color: kb.color }} />
|
| 47 |
+
</div>
|
| 48 |
+
<div className="flex-1">
|
| 49 |
+
<h3 className="font-semibold text-white group-hover:text-purple-300 transition-colors">{kb.name}</h3>
|
| 50 |
+
<p className="text-xs mt-1 text-slate-500">{kb.desc}</p>
|
| 51 |
+
</div>
|
| 52 |
+
</div>
|
| 53 |
+
|
| 54 |
+
<div className="flex items-center justify-between mb-2">
|
| 55 |
+
<span className="text-xs text-slate-500">Documents</span>
|
| 56 |
+
<span className="text-xs font-bold text-white">{kb.docs.toLocaleString()}</span>
|
| 57 |
+
</div>
|
| 58 |
+
<div className="progress-bar mb-3">
|
| 59 |
+
<div className="progress-fill" style={{ width: `${Math.min(100, kb.docs / 15)}%`, background: `linear-gradient(90deg, ${kb.color}50, ${kb.color})` }} />
|
| 60 |
+
</div>
|
| 61 |
+
<div className="text-xs text-slate-600">Updated {kb.updated}</div>
|
| 62 |
+
</motion.div>
|
| 63 |
+
))}
|
| 64 |
+
|
| 65 |
+
{/* Add Knowledge Base Card */}
|
| 66 |
+
<motion.div initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }}
|
| 67 |
+
transition={{ delay: KNOWLEDGE_BASES.length * 0.07 }}
|
| 68 |
+
className="card p-5 cursor-pointer group flex flex-col items-center justify-center min-h-[160px] border-dashed"
|
| 69 |
+
style={{ borderStyle: 'dashed', borderColor: 'rgba(124,58,237,0.2)', background: 'rgba(124,58,237,0.03)' }}>
|
| 70 |
+
<div className="w-10 h-10 rounded-xl flex items-center justify-center mb-3 group-hover:scale-110 transition-transform"
|
| 71 |
+
style={{ background: 'rgba(124,58,237,0.1)', border: '1px solid rgba(124,58,237,0.2)' }}>
|
| 72 |
+
<Plus size={18} className="text-purple-400" />
|
| 73 |
+
</div>
|
| 74 |
+
<span className="text-sm font-medium text-purple-400 group-hover:text-purple-300">Add Knowledge Base</span>
|
| 75 |
+
<span className="text-xs text-slate-600 mt-1">Connect a new data source</span>
|
| 76 |
+
</motion.div>
|
| 77 |
+
</div>
|
| 78 |
+
</div>
|
| 79 |
+
)
|
| 80 |
+
}
|
frontend/components/pages/MemoryPage.tsx
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { Brain, Database, Clock, Search, Tag } from 'lucide-react'
|
| 5 |
+
|
| 6 |
+
const MEMORIES = [
|
| 7 |
+
{ id: 1, title: 'Market Research — SaaS Competitors Q4', tags: ['research', 'market'], date: '2h ago', size: '48 KB', type: 'document', color: '#6366f1' },
|
| 8 |
+
{ id: 2, title: 'API Authentication Module Design', tags: ['code', 'architecture'], date: '5h ago', size: '12 KB', type: 'code', color: '#34d399' },
|
| 9 |
+
{ id: 3, title: 'Product Positioning Statement v3', tags: ['content', 'strategy'], date: '1d ago', size: '8 KB', type: 'text', color: '#a78bfa' },
|
| 10 |
+
{ id: 4, title: 'Database Schema — Users & Sessions', tags: ['code', 'database'], date: '2d ago', size: '22 KB', type: 'code', color: '#22d3ee' },
|
| 11 |
+
{ id: 5, title: 'Brand Voice Guidelines 2025', tags: ['content', 'brand'], date: '3d ago', size: '35 KB', type: 'document', color: '#f472b6' },
|
| 12 |
+
{ id: 6, title: 'Competitor Analysis Matrix', tags: ['research', 'strategy'], date: '4d ago', size: '61 KB', type: 'document', color: '#f59e0b' },
|
| 13 |
+
]
|
| 14 |
+
|
| 15 |
+
export default function MemoryPage() {
|
| 16 |
+
return (
|
| 17 |
+
<div className="h-full overflow-y-auto p-6">
|
| 18 |
+
<div className="flex items-center justify-between mb-6">
|
| 19 |
+
<div>
|
| 20 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 21 |
+
<Brain size={22} className="text-purple-400" /> Memory
|
| 22 |
+
</h1>
|
| 23 |
+
<p className="text-sm mt-1 text-slate-500">Persistent knowledge storage · 4,200 indexed documents</p>
|
| 24 |
+
</div>
|
| 25 |
+
<div className="flex items-center gap-2">
|
| 26 |
+
<div className="relative">
|
| 27 |
+
<Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-500" />
|
| 28 |
+
<input placeholder="Search memories…" className="cmd-input pl-9 pr-4 py-2.5 text-sm w-56" />
|
| 29 |
+
</div>
|
| 30 |
+
</div>
|
| 31 |
+
</div>
|
| 32 |
+
|
| 33 |
+
{/* Stats */}
|
| 34 |
+
<div className="grid grid-cols-3 gap-4 mb-6">
|
| 35 |
+
{[
|
| 36 |
+
{ label: 'Total Memories', value: '4,200', icon: Database, color: '#6366f1' },
|
| 37 |
+
{ label: 'Storage Used', value: '2.4 GB', icon: Database, color: '#22d3ee' },
|
| 38 |
+
{ label: 'Last Indexed', value: '3m ago', icon: Clock, color: '#a78bfa' },
|
| 39 |
+
].map(stat => (
|
| 40 |
+
<div key={stat.label} className="card p-4 flex items-center gap-3">
|
| 41 |
+
<div className="w-9 h-9 rounded-xl flex items-center justify-center flex-shrink-0"
|
| 42 |
+
style={{ background: `${stat.color}15` }}>
|
| 43 |
+
<stat.icon size={16} style={{ color: stat.color }} />
|
| 44 |
+
</div>
|
| 45 |
+
<div>
|
| 46 |
+
<div className="text-lg font-bold text-white">{stat.value}</div>
|
| 47 |
+
<div className="text-xs text-slate-500">{stat.label}</div>
|
| 48 |
+
</div>
|
| 49 |
+
</div>
|
| 50 |
+
))}
|
| 51 |
+
</div>
|
| 52 |
+
|
| 53 |
+
{/* Memory Grid */}
|
| 54 |
+
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-3">
|
| 55 |
+
{MEMORIES.map((m, i) => (
|
| 56 |
+
<motion.div key={m.id} initial={{ opacity: 0, y: 12 }} animate={{ opacity: 1, y: 0 }}
|
| 57 |
+
transition={{ delay: i * 0.06 }} className="card p-4 cursor-pointer group">
|
| 58 |
+
<div className="flex items-start gap-3 mb-3">
|
| 59 |
+
<div className="w-9 h-9 rounded-xl flex items-center justify-center flex-shrink-0"
|
| 60 |
+
style={{ background: `${m.color}15`, border: `1px solid ${m.color}20` }}>
|
| 61 |
+
<Database size={14} style={{ color: m.color }} />
|
| 62 |
+
</div>
|
| 63 |
+
<div className="flex-1 min-w-0">
|
| 64 |
+
<h3 className="text-sm font-semibold text-white leading-snug line-clamp-2 group-hover:text-purple-300 transition-colors">
|
| 65 |
+
{m.title}
|
| 66 |
+
</h3>
|
| 67 |
+
<div className="flex items-center gap-2 mt-1 text-xs text-slate-600">
|
| 68 |
+
<Clock size={10} /> {m.date} · {m.size}
|
| 69 |
+
</div>
|
| 70 |
+
</div>
|
| 71 |
+
</div>
|
| 72 |
+
<div className="flex flex-wrap gap-1.5">
|
| 73 |
+
{m.tags.map(tag => (
|
| 74 |
+
<span key={tag} className="flex items-center gap-1 text-xs px-2 py-0.5 rounded-full"
|
| 75 |
+
style={{ background: `${m.color}10`, color: m.color, border: `1px solid ${m.color}20` }}>
|
| 76 |
+
<Tag size={9} /> {tag}
|
| 77 |
+
</span>
|
| 78 |
+
))}
|
| 79 |
+
</div>
|
| 80 |
+
</motion.div>
|
| 81 |
+
))}
|
| 82 |
+
</div>
|
| 83 |
+
</div>
|
| 84 |
+
)
|
| 85 |
+
}
|
frontend/components/pages/SettingsPage.tsx
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useState } from 'react'
|
| 4 |
+
import { motion } from 'framer-motion'
|
| 5 |
+
import { Settings, Key, Zap, Bell, Shield, Cpu, ChevronRight, Check, Eye, EyeOff } from 'lucide-react'
|
| 6 |
+
|
| 7 |
+
const PROVIDER_CONFIGS = [
|
| 8 |
+
{ name: 'Gemini', model: 'gemini-2.0-flash', status: 'active', color: '#22d3ee', keys: 6, type: 'Primary' },
|
| 9 |
+
{ name: 'Sambanova', model: 'Meta-Llama-3.3-70B', status: 'active', color: '#a78bfa', keys: 9, type: 'Primary' },
|
| 10 |
+
{ name: 'GitHub Models', model: 'gpt-4o', status: 'active', color: '#34d399', keys: 9, type: 'Primary' },
|
| 11 |
+
]
|
| 12 |
+
|
| 13 |
+
const SETTING_SECTIONS = [
|
| 14 |
+
{ id: 'providers', label: 'AI Providers', icon: Cpu },
|
| 15 |
+
{ id: 'keys', label: 'API Keys', icon: Key },
|
| 16 |
+
{ id: 'notifications', label: 'Notifications', icon: Bell },
|
| 17 |
+
{ id: 'security', label: 'Security', icon: Shield },
|
| 18 |
+
]
|
| 19 |
+
|
| 20 |
+
function ApiKeyField({ label, value, color }: { label: string; value: string; color: string }) {
|
| 21 |
+
const [show, setShow] = useState(false)
|
| 22 |
+
const display = show ? value : value.slice(0, 8) + '••••••••••••••••' + value.slice(-4)
|
| 23 |
+
return (
|
| 24 |
+
<div className="flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white/[0.02] transition-colors" style={{ border: '1px solid rgba(255,255,255,0.06)' }}>
|
| 25 |
+
<div className="w-2 h-2 rounded-full flex-shrink-0" style={{ background: color }} />
|
| 26 |
+
<span className="text-sm text-slate-400 w-28 flex-shrink-0">{label}</span>
|
| 27 |
+
<code className="text-xs flex-1 text-slate-300 font-mono">{display}</code>
|
| 28 |
+
<button onClick={() => setShow(!show)} className="text-slate-600 hover:text-slate-400 transition-colors">
|
| 29 |
+
{show ? <EyeOff size={14} /> : <Eye size={14} />}
|
| 30 |
+
</button>
|
| 31 |
+
</div>
|
| 32 |
+
)
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
export default function SettingsPage() {
|
| 36 |
+
const [activeSection, setActiveSection] = useState('providers')
|
| 37 |
+
const [godModeToggle, setGodModeToggle] = useState(true)
|
| 38 |
+
const [autoRotate, setAutoRotate] = useState(true)
|
| 39 |
+
const [streamMode, setStreamMode] = useState(true)
|
| 40 |
+
|
| 41 |
+
return (
|
| 42 |
+
<div className="h-full overflow-y-auto p-6">
|
| 43 |
+
<div className="mb-6">
|
| 44 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 45 |
+
<Settings size={22} className="text-purple-400" /> Settings
|
| 46 |
+
</h1>
|
| 47 |
+
<p className="text-sm mt-1 text-slate-500">Configure God Agent OS — AI providers, keys, and preferences</p>
|
| 48 |
+
</div>
|
| 49 |
+
|
| 50 |
+
<div className="flex gap-6">
|
| 51 |
+
{/* Sidebar Nav */}
|
| 52 |
+
<div className="w-48 flex-shrink-0 space-y-1">
|
| 53 |
+
{SETTING_SECTIONS.map(sec => (
|
| 54 |
+
<button key={sec.id} onClick={() => setActiveSection(sec.id)}
|
| 55 |
+
className={`nav-item w-full text-left ${activeSection === sec.id ? 'active' : ''}`}>
|
| 56 |
+
<sec.icon size={15} />
|
| 57 |
+
{sec.label}
|
| 58 |
+
</button>
|
| 59 |
+
))}
|
| 60 |
+
</div>
|
| 61 |
+
|
| 62 |
+
{/* Content */}
|
| 63 |
+
<div className="flex-1 min-w-0 space-y-4">
|
| 64 |
+
|
| 65 |
+
{activeSection === 'providers' && (
|
| 66 |
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
| 67 |
+
<h2 className="text-sm font-bold text-white mb-4">AI Provider Configuration</h2>
|
| 68 |
+
|
| 69 |
+
<div className="space-y-3 mb-6">
|
| 70 |
+
{PROVIDER_CONFIGS.map(p => (
|
| 71 |
+
<div key={p.name} className="card p-4 flex items-center gap-4">
|
| 72 |
+
<div className="w-10 h-10 rounded-xl flex items-center justify-center text-lg flex-shrink-0"
|
| 73 |
+
style={{ background: `${p.color}15`, border: `1px solid ${p.color}25` }}>
|
| 74 |
+
<Cpu size={16} style={{ color: p.color }} />
|
| 75 |
+
</div>
|
| 76 |
+
<div className="flex-1">
|
| 77 |
+
<div className="flex items-center gap-2">
|
| 78 |
+
<span className="font-semibold text-white text-sm">{p.name}</span>
|
| 79 |
+
<span className="text-xs px-2 py-0.5 rounded-full font-semibold"
|
| 80 |
+
style={{ background: `${p.color}15`, color: p.color }}>{p.type}</span>
|
| 81 |
+
</div>
|
| 82 |
+
<div className="text-xs text-slate-500 mt-0.5">{p.model} · {p.keys} keys configured</div>
|
| 83 |
+
</div>
|
| 84 |
+
<div className="flex items-center gap-2">
|
| 85 |
+
<div className="w-2 h-2 rounded-full bg-green-400" />
|
| 86 |
+
<span className="text-xs text-green-400 font-medium">Active</span>
|
| 87 |
+
<Check size={14} className="text-green-400" />
|
| 88 |
+
</div>
|
| 89 |
+
</div>
|
| 90 |
+
))}
|
| 91 |
+
</div>
|
| 92 |
+
|
| 93 |
+
{/* Toggle settings */}
|
| 94 |
+
<div className="space-y-3">
|
| 95 |
+
{[
|
| 96 |
+
{ label: 'God Mode', desc: 'Full autonomous operation mode', state: godModeToggle, toggle: setGodModeToggle, color: '#a78bfa' },
|
| 97 |
+
{ label: 'Auto-Rotate Keys', desc: 'Automatically rotate API keys on rate limit', state: autoRotate, toggle: setAutoRotate, color: '#22d3ee' },
|
| 98 |
+
{ label: 'Stream Mode', desc: 'Real-time streaming output from all providers', state: streamMode, toggle: setStreamMode, color: '#34d399' },
|
| 99 |
+
].map(item => (
|
| 100 |
+
<div key={item.label} className="card p-4 flex items-center gap-4">
|
| 101 |
+
<div className="flex-1">
|
| 102 |
+
<div className="text-sm font-semibold text-white">{item.label}</div>
|
| 103 |
+
<div className="text-xs text-slate-500 mt-0.5">{item.desc}</div>
|
| 104 |
+
</div>
|
| 105 |
+
<button onClick={() => item.toggle(!item.state)}
|
| 106 |
+
className="w-10 h-5.5 rounded-full relative transition-all flex-shrink-0"
|
| 107 |
+
style={{
|
| 108 |
+
background: item.state ? item.color : 'rgba(255,255,255,0.1)',
|
| 109 |
+
width: 44, height: 24
|
| 110 |
+
}}>
|
| 111 |
+
<div className="absolute top-0.5 w-5 h-5 rounded-full bg-white shadow transition-all"
|
| 112 |
+
style={{ left: item.state ? 21 : 2 }} />
|
| 113 |
+
</button>
|
| 114 |
+
</div>
|
| 115 |
+
))}
|
| 116 |
+
</div>
|
| 117 |
+
</motion.div>
|
| 118 |
+
)}
|
| 119 |
+
|
| 120 |
+
{activeSection === 'keys' && (
|
| 121 |
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
| 122 |
+
<h2 className="text-sm font-bold text-white mb-4">API Key Management</h2>
|
| 123 |
+
<div className="card p-5 space-y-2">
|
| 124 |
+
<ApiKeyField label="Gemini Key 1" value="GEMINI_KEY_1_CONFIGURED" color="#22d3ee" />
|
| 125 |
+
<ApiKeyField label="Gemini Key 2" value="GEMINI_KEY_2_CONFIGURED" color="#22d3ee" />
|
| 126 |
+
<ApiKeyField label="Sambanova Key 1" value="SAMBANOVA_KEY_1_CONFIGURED" color="#a78bfa" />
|
| 127 |
+
<ApiKeyField label="GitHub Key 1" value="GITHUB_KEY_1_CONFIGURED" color="#34d399" />
|
| 128 |
+
</div>
|
| 129 |
+
<p className="text-xs text-slate-600 mt-3">Keys are stored securely in environment variables. Never commit to version control.</p>
|
| 130 |
+
</motion.div>
|
| 131 |
+
)}
|
| 132 |
+
|
| 133 |
+
{activeSection === 'notifications' && (
|
| 134 |
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
| 135 |
+
<h2 className="text-sm font-bold text-white mb-4">Notification Preferences</h2>
|
| 136 |
+
<div className="card p-5">
|
| 137 |
+
<p className="text-sm text-slate-500">Configure notification settings for agent activity, task completion, and system alerts.</p>
|
| 138 |
+
</div>
|
| 139 |
+
</motion.div>
|
| 140 |
+
)}
|
| 141 |
+
|
| 142 |
+
{activeSection === 'security' && (
|
| 143 |
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
| 144 |
+
<h2 className="text-sm font-bold text-white mb-4">Security Settings</h2>
|
| 145 |
+
<div className="card p-5">
|
| 146 |
+
<p className="text-sm text-slate-500">Manage authentication, access control, and audit logging.</p>
|
| 147 |
+
</div>
|
| 148 |
+
</motion.div>
|
| 149 |
+
)}
|
| 150 |
+
</div>
|
| 151 |
+
</div>
|
| 152 |
+
</div>
|
| 153 |
+
)
|
| 154 |
+
}
|
frontend/components/pages/TasksPage.tsx
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useState } from 'react'
|
| 4 |
+
import { motion } from 'framer-motion'
|
| 5 |
+
import { CheckSquare, Clock, Loader2, AlertCircle, Plus, ChevronRight } from 'lucide-react'
|
| 6 |
+
import { TASKS, Task } from '@/store/useAppStore'
|
| 7 |
+
import { cn } from '@/lib/utils'
|
| 8 |
+
|
| 9 |
+
const STATUS_CONFIG = {
|
| 10 |
+
running: { color: '#6366f1', label: 'Running', icon: Loader2, bg: 'rgba(99,102,241,0.12)' },
|
| 11 |
+
completed: { color: '#22c55e', label: 'Completed', icon: CheckSquare, bg: 'rgba(34,197,94,0.12)' },
|
| 12 |
+
pending: { color: '#94a3b8', label: 'Pending', icon: Clock, bg: 'rgba(148,163,184,0.1)' },
|
| 13 |
+
failed: { color: '#ef4444', label: 'Failed', icon: AlertCircle, bg: 'rgba(239,68,68,0.12)' },
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
function TaskRow({ task, delay }: { task: Task; delay: number }) {
|
| 17 |
+
const cfg = STATUS_CONFIG[task.status]
|
| 18 |
+
const Icon = cfg.icon
|
| 19 |
+
const isRunning = task.status === 'running'
|
| 20 |
+
const agentColor = '#6366f1'
|
| 21 |
+
|
| 22 |
+
return (
|
| 23 |
+
<motion.div
|
| 24 |
+
initial={{ opacity: 0, x: -12 }} animate={{ opacity: 1, x: 0 }}
|
| 25 |
+
transition={{ delay, duration: 0.3 }}
|
| 26 |
+
className="card p-4 group hover:border-white/10 transition-all cursor-pointer"
|
| 27 |
+
>
|
| 28 |
+
<div className="flex items-center gap-4">
|
| 29 |
+
<div className="w-8 h-8 rounded-xl flex items-center justify-center flex-shrink-0"
|
| 30 |
+
style={{ background: cfg.bg }}>
|
| 31 |
+
<Icon size={14} style={{ color: cfg.color }} className={isRunning ? 'animate-spin' : ''} />
|
| 32 |
+
</div>
|
| 33 |
+
|
| 34 |
+
<div className="flex-1 min-w-0">
|
| 35 |
+
<div className="flex items-center gap-2 mb-1">
|
| 36 |
+
<span className="text-sm font-semibold text-white truncate">{task.title}</span>
|
| 37 |
+
<span className="text-xs px-2 py-0.5 rounded-full flex-shrink-0 font-medium"
|
| 38 |
+
style={{ background: cfg.bg, color: cfg.color }}>{cfg.label}</span>
|
| 39 |
+
</div>
|
| 40 |
+
<div className="flex items-center gap-3">
|
| 41 |
+
<span className="text-xs text-slate-500">{task.agent}</span>
|
| 42 |
+
<span className="text-xs text-slate-600">· {task.createdAt}</span>
|
| 43 |
+
{task.completedAt && <span className="text-xs text-green-500">Completed {task.completedAt}</span>}
|
| 44 |
+
</div>
|
| 45 |
+
{task.status === 'running' && (
|
| 46 |
+
<div className="mt-2 flex items-center gap-2">
|
| 47 |
+
<div className="flex-1 progress-bar">
|
| 48 |
+
<motion.div className="progress-fill"
|
| 49 |
+
initial={{ width: 0 }} animate={{ width: `${task.progress}%` }}
|
| 50 |
+
transition={{ duration: 1, delay: 0.2 }}
|
| 51 |
+
style={{ background: 'linear-gradient(90deg, #6366f160, #6366f1)' }} />
|
| 52 |
+
</div>
|
| 53 |
+
<span className="text-xs font-bold text-purple-400 w-8 text-right">{task.progress}%</span>
|
| 54 |
+
</div>
|
| 55 |
+
)}
|
| 56 |
+
</div>
|
| 57 |
+
|
| 58 |
+
<ChevronRight size={15} className="text-slate-700 group-hover:text-purple-400 transition-colors flex-shrink-0" />
|
| 59 |
+
</div>
|
| 60 |
+
</motion.div>
|
| 61 |
+
)
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
export default function TasksPage() {
|
| 65 |
+
const [filter, setFilter] = useState<'all' | Task['status']>('all')
|
| 66 |
+
const filtered = filter === 'all' ? TASKS : TASKS.filter(t => t.status === filter)
|
| 67 |
+
|
| 68 |
+
const counts = {
|
| 69 |
+
all: TASKS.length,
|
| 70 |
+
running: TASKS.filter(t => t.status === 'running').length,
|
| 71 |
+
completed: TASKS.filter(t => t.status === 'completed').length,
|
| 72 |
+
pending: TASKS.filter(t => t.status === 'pending').length,
|
| 73 |
+
failed: TASKS.filter(t => t.status === 'failed').length,
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
return (
|
| 77 |
+
<div className="h-full overflow-y-auto p-6">
|
| 78 |
+
<div className="flex items-center justify-between mb-6">
|
| 79 |
+
<div>
|
| 80 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 81 |
+
<CheckSquare size={22} className="text-purple-400" /> Tasks
|
| 82 |
+
</h1>
|
| 83 |
+
<p className="text-sm mt-1 text-slate-500">{counts.running} running · {counts.pending} pending · {counts.completed} completed</p>
|
| 84 |
+
</div>
|
| 85 |
+
<button className="flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-semibold text-white hover:opacity-90 transition-all"
|
| 86 |
+
style={{ background: 'linear-gradient(135deg, #7c3aed, #4f46e5)', boxShadow: '0 0 20px rgba(124,58,237,0.3)' }}>
|
| 87 |
+
<Plus size={15} /> New Task
|
| 88 |
+
</button>
|
| 89 |
+
</div>
|
| 90 |
+
|
| 91 |
+
{/* Status Tabs */}
|
| 92 |
+
<div className="flex gap-2 mb-6 flex-wrap">
|
| 93 |
+
{(['all', 'running', 'completed', 'pending', 'failed'] as const).map(s => (
|
| 94 |
+
<button key={s} onClick={() => setFilter(s)}
|
| 95 |
+
className={cn('px-4 py-2 rounded-xl text-xs font-semibold capitalize transition-all',
|
| 96 |
+
filter === s
|
| 97 |
+
? 'bg-purple-600/20 text-purple-300 border border-purple-500/30'
|
| 98 |
+
: 'text-slate-500 border border-transparent hover:border-white/10 hover:text-slate-300'
|
| 99 |
+
)}>
|
| 100 |
+
{s} ({counts[s]})
|
| 101 |
+
</button>
|
| 102 |
+
))}
|
| 103 |
+
</div>
|
| 104 |
+
|
| 105 |
+
{/* Summary Stats */}
|
| 106 |
+
<div className="grid grid-cols-4 gap-4 mb-6">
|
| 107 |
+
{Object.entries(STATUS_CONFIG).map(([status, cfg]) => (
|
| 108 |
+
<div key={status} className="card p-4">
|
| 109 |
+
<div className="text-2xl font-bold text-white">{counts[status as keyof typeof counts] || 0}</div>
|
| 110 |
+
<div className="text-xs mt-1 font-semibold" style={{ color: cfg.color }}>{cfg.label}</div>
|
| 111 |
+
</div>
|
| 112 |
+
))}
|
| 113 |
+
</div>
|
| 114 |
+
|
| 115 |
+
{/* Tasks List */}
|
| 116 |
+
<div className="space-y-3">
|
| 117 |
+
{filtered.map((task, i) => <TaskRow key={task.id} task={task} delay={i * 0.05} />)}
|
| 118 |
+
{filtered.length === 0 && (
|
| 119 |
+
<div className="text-center py-16 text-slate-600">No tasks with this filter</div>
|
| 120 |
+
)}
|
| 121 |
+
</div>
|
| 122 |
+
</div>
|
| 123 |
+
)
|
| 124 |
+
}
|
frontend/components/pages/WorkflowsPage.tsx
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion } from 'framer-motion'
|
| 4 |
+
import { GitBranch, Play, Pause, Plus, Clock, CheckCircle2, Zap } from 'lucide-react'
|
| 5 |
+
|
| 6 |
+
const WORKFLOWS = [
|
| 7 |
+
{ id: 1, name: 'Daily Research Pipeline', desc: 'Research → Analyze → Summarize → Report', status: 'active', runs: 47, lastRun: '2h ago', color: '#6366f1', schedule: 'Daily 9:00 AM' },
|
| 8 |
+
{ id: 2, name: 'Code Review Automation', desc: 'PR Detect → AI Review → Comment → Approve', status: 'active', runs: 23, lastRun: '1h ago', color: '#34d399', schedule: 'On PR event' },
|
| 9 |
+
{ id: 3, name: 'Content Generation Loop', desc: 'Research → Write → Review → Publish', status: 'paused', runs: 12, lastRun: '1d ago', color: '#a78bfa', schedule: 'Weekly' },
|
| 10 |
+
{ id: 4, name: 'Deploy Pipeline', desc: 'Build → Test → Stage → Deploy → Monitor', status: 'active', runs: 89, lastRun: '30m ago', color: '#22d3ee', schedule: 'On push to main' },
|
| 11 |
+
{ id: 5, name: 'Market Intelligence', desc: 'Scrape → Parse → Analyze → Alert', status: 'idle', runs: 7, lastRun: '3d ago', color: '#f59e0b', schedule: 'Weekly' },
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
const STATUS_CONFIG = {
|
| 15 |
+
active: { color: '#22c55e', label: 'Active' },
|
| 16 |
+
paused: { color: '#f59e0b', label: 'Paused' },
|
| 17 |
+
idle: { color: '#94a3b8', label: 'Idle' },
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
export default function WorkflowsPage() {
|
| 21 |
+
return (
|
| 22 |
+
<div className="h-full overflow-y-auto p-6">
|
| 23 |
+
<div className="flex items-center justify-between mb-6">
|
| 24 |
+
<div>
|
| 25 |
+
<h1 className="text-xl font-bold text-white flex items-center gap-2">
|
| 26 |
+
<GitBranch size={22} className="text-purple-400" /> Workflows
|
| 27 |
+
</h1>
|
| 28 |
+
<p className="text-sm mt-1 text-slate-500">Autonomous multi-agent pipelines · {WORKFLOWS.filter(w => w.status === 'active').length} running</p>
|
| 29 |
+
</div>
|
| 30 |
+
<button className="flex items-center gap-2 px-4 py-2.5 rounded-xl text-sm font-semibold text-white hover:opacity-90 transition-all"
|
| 31 |
+
style={{ background: 'linear-gradient(135deg, #7c3aed, #4f46e5)', boxShadow: '0 0 20px rgba(124,58,237,0.3)' }}>
|
| 32 |
+
<Plus size={15} /> New Workflow
|
| 33 |
+
</button>
|
| 34 |
+
</div>
|
| 35 |
+
|
| 36 |
+
<div className="space-y-3">
|
| 37 |
+
{WORKFLOWS.map((wf, i) => {
|
| 38 |
+
const sc = STATUS_CONFIG[wf.status as keyof typeof STATUS_CONFIG]
|
| 39 |
+
return (
|
| 40 |
+
<motion.div key={wf.id} initial={{ opacity: 0, x: -12 }} animate={{ opacity: 1, x: 0 }}
|
| 41 |
+
transition={{ delay: i * 0.07 }} className="card p-5 group cursor-pointer">
|
| 42 |
+
<div className="flex items-center gap-4">
|
| 43 |
+
<div className="w-10 h-10 rounded-xl flex items-center justify-center flex-shrink-0"
|
| 44 |
+
style={{ background: `${wf.color}15`, border: `1px solid ${wf.color}25` }}>
|
| 45 |
+
<GitBranch size={18} style={{ color: wf.color }} />
|
| 46 |
+
</div>
|
| 47 |
+
|
| 48 |
+
<div className="flex-1 min-w-0">
|
| 49 |
+
<div className="flex items-center gap-2 mb-1">
|
| 50 |
+
<h3 className="font-semibold text-white">{wf.name}</h3>
|
| 51 |
+
<span className="text-xs px-2 py-0.5 rounded-full font-medium"
|
| 52 |
+
style={{ background: `${sc.color}12`, color: sc.color }}>
|
| 53 |
+
{sc.label}
|
| 54 |
+
</span>
|
| 55 |
+
</div>
|
| 56 |
+
<p className="text-xs text-slate-500 font-mono">{wf.desc}</p>
|
| 57 |
+
<div className="flex items-center gap-4 mt-2 text-xs text-slate-600">
|
| 58 |
+
<span className="flex items-center gap-1"><Zap size={10} /> {wf.runs} runs</span>
|
| 59 |
+
<span className="flex items-center gap-1"><Clock size={10} /> {wf.lastRun}</span>
|
| 60 |
+
<span>{wf.schedule}</span>
|
| 61 |
+
</div>
|
| 62 |
+
</div>
|
| 63 |
+
|
| 64 |
+
<div className="flex gap-2">
|
| 65 |
+
<button className="w-8 h-8 rounded-xl flex items-center justify-center transition-all hover:bg-white/10"
|
| 66 |
+
style={{ border: '1px solid rgba(255,255,255,0.08)' }}>
|
| 67 |
+
{wf.status === 'active' ? <Pause size={13} className="text-slate-400" /> : <Play size={13} className="text-green-400" />}
|
| 68 |
+
</button>
|
| 69 |
+
</div>
|
| 70 |
+
</div>
|
| 71 |
+
</motion.div>
|
| 72 |
+
)
|
| 73 |
+
})}
|
| 74 |
+
</div>
|
| 75 |
+
</div>
|
| 76 |
+
)
|
| 77 |
+
}
|
frontend/components/shared/Sidebar.tsx
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { motion, AnimatePresence } from 'framer-motion'
|
| 4 |
+
import {
|
| 5 |
+
LayoutDashboard, Bot, CheckSquare, Brain, BookOpen,
|
| 6 |
+
GitBranch, BarChart3, Settings, ChevronLeft, Zap,
|
| 7 |
+
Activity, Menu, X
|
| 8 |
+
} from 'lucide-react'
|
| 9 |
+
import { useAppStore, NavPage } from '@/store/useAppStore'
|
| 10 |
+
import { cn } from '@/lib/utils'
|
| 11 |
+
|
| 12 |
+
const NAV_ITEMS: { page: NavPage; label: string; icon: React.ElementType; badge?: string }[] = [
|
| 13 |
+
{ page: 'dashboard', label: 'Dashboard', icon: LayoutDashboard },
|
| 14 |
+
{ page: 'agents', label: 'Agents', icon: Bot, badge: '12' },
|
| 15 |
+
{ page: 'tasks', label: 'Tasks', icon: CheckSquare, badge: '3' },
|
| 16 |
+
{ page: 'memory', label: 'Memory', icon: Brain },
|
| 17 |
+
{ page: 'knowledge', label: 'Knowledge', icon: BookOpen },
|
| 18 |
+
{ page: 'workflows', label: 'Workflows', icon: GitBranch },
|
| 19 |
+
{ page: 'analytics', label: 'Analytics', icon: BarChart3 },
|
| 20 |
+
{ page: 'settings', label: 'Settings', icon: Settings },
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
export default function Sidebar() {
|
| 24 |
+
const { currentPage, setCurrentPage, sidebarCollapsed, toggleSidebar, godModeActive, toggleGodMode } = useAppStore()
|
| 25 |
+
|
| 26 |
+
return (
|
| 27 |
+
<motion.aside
|
| 28 |
+
animate={{ width: sidebarCollapsed ? 64 : 220 }}
|
| 29 |
+
transition={{ duration: 0.3, ease: [0.4, 0, 0.2, 1] }}
|
| 30 |
+
className="flex flex-col h-full flex-shrink-0 border-r overflow-hidden"
|
| 31 |
+
style={{ borderColor: 'var(--border)', background: 'rgba(10,12,22,0.95)', backdropFilter: 'blur(20px)' }}
|
| 32 |
+
>
|
| 33 |
+
{/* Logo */}
|
| 34 |
+
<div className="flex items-center gap-3 px-4 py-5 border-b" style={{ borderColor: 'var(--border)' }}>
|
| 35 |
+
<div className="relative flex-shrink-0">
|
| 36 |
+
<div className="w-8 h-8 rounded-xl flex items-center justify-center glow-purple"
|
| 37 |
+
style={{ background: 'linear-gradient(135deg, #7c3aed, #4f46e5)' }}>
|
| 38 |
+
<Zap size={16} className="text-white" />
|
| 39 |
+
</div>
|
| 40 |
+
{godModeActive && (
|
| 41 |
+
<div className="absolute -top-0.5 -right-0.5 w-2.5 h-2.5 rounded-full bg-green-400 border-2 border-[#0a0c16]" />
|
| 42 |
+
)}
|
| 43 |
+
</div>
|
| 44 |
+
<AnimatePresence>
|
| 45 |
+
{!sidebarCollapsed && (
|
| 46 |
+
<motion.div
|
| 47 |
+
initial={{ opacity: 0, x: -8 }}
|
| 48 |
+
animate={{ opacity: 1, x: 0 }}
|
| 49 |
+
exit={{ opacity: 0, x: -8 }}
|
| 50 |
+
transition={{ duration: 0.2 }}
|
| 51 |
+
className="min-w-0"
|
| 52 |
+
>
|
| 53 |
+
<div className="text-sm font-bold text-white leading-none">GOD AGENT OS</div>
|
| 54 |
+
<div className="text-xs mt-0.5" style={{ color: 'var(--text-muted)' }}>by manus + genspark</div>
|
| 55 |
+
</motion.div>
|
| 56 |
+
)}
|
| 57 |
+
</AnimatePresence>
|
| 58 |
+
<button
|
| 59 |
+
onClick={toggleSidebar}
|
| 60 |
+
className="ml-auto text-slate-500 hover:text-slate-300 transition-colors flex-shrink-0"
|
| 61 |
+
>
|
| 62 |
+
{sidebarCollapsed ? <Menu size={16} /> : <ChevronLeft size={16} />}
|
| 63 |
+
</button>
|
| 64 |
+
</div>
|
| 65 |
+
|
| 66 |
+
{/* Navigation */}
|
| 67 |
+
<nav className="flex-1 overflow-y-auto py-3 px-2 space-y-0.5">
|
| 68 |
+
{NAV_ITEMS.map(({ page, label, icon: Icon, badge }) => {
|
| 69 |
+
const isActive = currentPage === page
|
| 70 |
+
return (
|
| 71 |
+
<button
|
| 72 |
+
key={page}
|
| 73 |
+
onClick={() => setCurrentPage(page)}
|
| 74 |
+
className={cn(
|
| 75 |
+
'nav-item w-full text-left relative group',
|
| 76 |
+
isActive && 'active'
|
| 77 |
+
)}
|
| 78 |
+
title={sidebarCollapsed ? label : undefined}
|
| 79 |
+
>
|
| 80 |
+
<Icon size={17} className="flex-shrink-0" style={{ color: isActive ? '#a78bfa' : undefined }} />
|
| 81 |
+
<AnimatePresence>
|
| 82 |
+
{!sidebarCollapsed && (
|
| 83 |
+
<motion.span
|
| 84 |
+
initial={{ opacity: 0 }}
|
| 85 |
+
animate={{ opacity: 1 }}
|
| 86 |
+
exit={{ opacity: 0 }}
|
| 87 |
+
className="flex-1 text-left"
|
| 88 |
+
>
|
| 89 |
+
{label}
|
| 90 |
+
</motion.span>
|
| 91 |
+
)}
|
| 92 |
+
</AnimatePresence>
|
| 93 |
+
{badge && !sidebarCollapsed && (
|
| 94 |
+
<span className="ml-auto text-xs px-1.5 py-0.5 rounded-full font-semibold"
|
| 95 |
+
style={{ background: isActive ? 'rgba(124,58,237,0.3)' : 'rgba(255,255,255,0.07)', color: isActive ? '#c084fc' : 'var(--text-muted)' }}>
|
| 96 |
+
{badge}
|
| 97 |
+
</span>
|
| 98 |
+
)}
|
| 99 |
+
</button>
|
| 100 |
+
)
|
| 101 |
+
})}
|
| 102 |
+
</nav>
|
| 103 |
+
|
| 104 |
+
{/* System Status */}
|
| 105 |
+
<div className="px-2 pb-2">
|
| 106 |
+
<div className="border-t mb-2" style={{ borderColor: 'var(--border)' }} />
|
| 107 |
+
{!sidebarCollapsed && (
|
| 108 |
+
<div className="px-2 mb-2">
|
| 109 |
+
<div className="flex items-center gap-2 mb-1">
|
| 110 |
+
<Activity size={11} className="text-green-400" />
|
| 111 |
+
<span className="text-xs font-medium" style={{ color: 'var(--text-secondary)' }}>System Status</span>
|
| 112 |
+
</div>
|
| 113 |
+
<div className="flex items-center gap-2">
|
| 114 |
+
<div className="w-1.5 h-1.5 rounded-full bg-green-400 animate-pulse-glow" />
|
| 115 |
+
<span className="text-xs text-green-400 font-medium">All Systems Operational</span>
|
| 116 |
+
</div>
|
| 117 |
+
</div>
|
| 118 |
+
)}
|
| 119 |
+
|
| 120 |
+
{/* God Mode Toggle */}
|
| 121 |
+
<div className={cn(
|
| 122 |
+
'flex items-center gap-2 px-2 py-2 rounded-xl cursor-pointer transition-all',
|
| 123 |
+
sidebarCollapsed ? 'justify-center' : '',
|
| 124 |
+
godModeActive ? 'glass-purple' : 'glass'
|
| 125 |
+
)} onClick={toggleGodMode}>
|
| 126 |
+
<div className={cn('w-6 h-3.5 rounded-full relative transition-all flex-shrink-0',
|
| 127 |
+
godModeActive ? 'bg-purple-600' : 'bg-slate-700'
|
| 128 |
+
)}>
|
| 129 |
+
<div className={cn('absolute top-0.5 w-2.5 h-2.5 rounded-full transition-all',
|
| 130 |
+
godModeActive ? 'right-0.5 bg-white' : 'left-0.5 bg-slate-400'
|
| 131 |
+
)} />
|
| 132 |
+
</div>
|
| 133 |
+
{!sidebarCollapsed && (
|
| 134 |
+
<span className="text-xs font-semibold" style={{ color: godModeActive ? '#a78bfa' : 'var(--text-muted)' }}>
|
| 135 |
+
God Mode {godModeActive ? 'ON' : 'OFF'}
|
| 136 |
+
</span>
|
| 137 |
+
)}
|
| 138 |
+
</div>
|
| 139 |
+
</div>
|
| 140 |
+
</motion.aside>
|
| 141 |
+
)
|
| 142 |
+
}
|
frontend/components/shared/TopBar.tsx
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
'use client'
|
| 2 |
+
|
| 3 |
+
import { useState, useEffect, useRef } from 'react'
|
| 4 |
+
import { motion, AnimatePresence } from 'framer-motion'
|
| 5 |
+
import { Search, Bell, Command, Sparkles, X, ArrowRight, Bot, CheckSquare, FileText, Zap } from 'lucide-react'
|
| 6 |
+
import { useAppStore } from '@/store/useAppStore'
|
| 7 |
+
|
| 8 |
+
const QUICK_COMMANDS = [
|
| 9 |
+
{ icon: Bot, label: 'New Research Task', shortcut: '/research', page: 'agents' as const },
|
| 10 |
+
{ icon: CheckSquare, label: 'View Running Tasks', shortcut: '/tasks', page: 'tasks' as const },
|
| 11 |
+
{ icon: FileText, label: 'Generate Report', shortcut: '/report', page: 'analytics' as const },
|
| 12 |
+
{ icon: Zap, label: 'Deploy Application', shortcut: '/deploy', page: 'workflows' as const },
|
| 13 |
+
]
|
| 14 |
+
|
| 15 |
+
const NOTIFICATIONS = [
|
| 16 |
+
{ id: '1', title: 'Code Agent', message: 'Successfully deployed production API', time: '2m ago', color: '#34d399' },
|
| 17 |
+
{ id: '2', title: 'Research Agent', message: 'Market analysis complete — 47 insights found', time: '15m ago', color: '#6366f1' },
|
| 18 |
+
{ id: '3', title: 'Data Agent', message: 'Processed 1.2M data points', time: '1h ago', color: '#22d3ee' },
|
| 19 |
+
]
|
| 20 |
+
|
| 21 |
+
export default function TopBar() {
|
| 22 |
+
const { setCurrentPage, commandPaletteOpen, setCommandPaletteOpen } = useAppStore()
|
| 23 |
+
const [query, setQuery] = useState('')
|
| 24 |
+
const [notifOpen, setNotifOpen] = useState(false)
|
| 25 |
+
const inputRef = useRef<HTMLInputElement>(null)
|
| 26 |
+
|
| 27 |
+
useEffect(() => {
|
| 28 |
+
const handler = (e: KeyboardEvent) => {
|
| 29 |
+
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
|
| 30 |
+
e.preventDefault()
|
| 31 |
+
setCommandPaletteOpen(true)
|
| 32 |
+
setTimeout(() => inputRef.current?.focus(), 50)
|
| 33 |
+
}
|
| 34 |
+
if (e.key === 'Escape') {
|
| 35 |
+
setCommandPaletteOpen(false)
|
| 36 |
+
setNotifOpen(false)
|
| 37 |
+
setQuery('')
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
window.addEventListener('keydown', handler)
|
| 41 |
+
return () => window.removeEventListener('keydown', handler)
|
| 42 |
+
}, [setCommandPaletteOpen])
|
| 43 |
+
|
| 44 |
+
const filtered = QUICK_COMMANDS.filter(c =>
|
| 45 |
+
query === '' || c.label.toLowerCase().includes(query.toLowerCase()) || c.shortcut.includes(query)
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
return (
|
| 49 |
+
<header className="flex items-center gap-4 px-4 py-3 border-b flex-shrink-0 relative z-30"
|
| 50 |
+
style={{ borderColor: 'var(--border)', background: 'rgba(10,12,22,0.98)', backdropFilter: 'blur(20px)' }}>
|
| 51 |
+
|
| 52 |
+
{/* Search / Command Trigger */}
|
| 53 |
+
<div className="flex-1 max-w-xl mx-auto">
|
| 54 |
+
<button
|
| 55 |
+
onClick={() => { setCommandPaletteOpen(true); setTimeout(() => inputRef.current?.focus(), 50) }}
|
| 56 |
+
className="w-full flex items-center gap-3 px-4 py-2.5 rounded-xl text-left transition-all hover:border-purple-500/30"
|
| 57 |
+
style={{ background: 'rgba(255,255,255,0.04)', border: '1px solid rgba(255,255,255,0.08)' }}
|
| 58 |
+
>
|
| 59 |
+
<Search size={15} className="text-slate-500 flex-shrink-0" />
|
| 60 |
+
<span className="flex-1 text-sm" style={{ color: 'var(--text-muted)' }}>Search agents, tasks, docs…</span>
|
| 61 |
+
<div className="flex items-center gap-1 text-xs px-1.5 py-0.5 rounded-md"
|
| 62 |
+
style={{ background: 'rgba(255,255,255,0.06)', color: 'var(--text-muted)' }}>
|
| 63 |
+
<Command size={10} />
|
| 64 |
+
<span>K</span>
|
| 65 |
+
</div>
|
| 66 |
+
</button>
|
| 67 |
+
</div>
|
| 68 |
+
|
| 69 |
+
{/* Right Icons */}
|
| 70 |
+
<div className="flex items-center gap-2">
|
| 71 |
+
<button className="p-2 rounded-xl text-slate-500 hover:text-slate-300 hover:bg-white/5 transition-all">
|
| 72 |
+
<Sparkles size={17} />
|
| 73 |
+
</button>
|
| 74 |
+
|
| 75 |
+
{/* Notifications */}
|
| 76 |
+
<div className="relative">
|
| 77 |
+
<button
|
| 78 |
+
onClick={() => setNotifOpen(!notifOpen)}
|
| 79 |
+
className="relative p-2 rounded-xl text-slate-500 hover:text-slate-300 hover:bg-white/5 transition-all"
|
| 80 |
+
>
|
| 81 |
+
<Bell size={17} />
|
| 82 |
+
<div className="absolute top-1.5 right-1.5 w-2 h-2 rounded-full bg-purple-500 border border-[#0a0c16]" />
|
| 83 |
+
</button>
|
| 84 |
+
|
| 85 |
+
<AnimatePresence>
|
| 86 |
+
{notifOpen && (
|
| 87 |
+
<motion.div
|
| 88 |
+
initial={{ opacity: 0, y: 8, scale: 0.95 }}
|
| 89 |
+
animate={{ opacity: 1, y: 0, scale: 1 }}
|
| 90 |
+
exit={{ opacity: 0, y: 8, scale: 0.95 }}
|
| 91 |
+
transition={{ duration: 0.2 }}
|
| 92 |
+
className="absolute right-0 top-full mt-2 w-80 glass-card overflow-hidden z-50"
|
| 93 |
+
>
|
| 94 |
+
<div className="flex items-center justify-between px-4 py-3 border-b" style={{ borderColor: 'var(--border)' }}>
|
| 95 |
+
<span className="text-sm font-semibold text-white">Notifications</span>
|
| 96 |
+
<button onClick={() => setNotifOpen(false)} className="text-slate-500 hover:text-slate-300">
|
| 97 |
+
<X size={14} />
|
| 98 |
+
</button>
|
| 99 |
+
</div>
|
| 100 |
+
{NOTIFICATIONS.map((n) => (
|
| 101 |
+
<div key={n.id} className="flex gap-3 px-4 py-3 hover:bg-white/[0.03] transition-colors cursor-pointer border-b last:border-0"
|
| 102 |
+
style={{ borderColor: 'var(--border)' }}>
|
| 103 |
+
<div className="w-2 h-2 rounded-full flex-shrink-0 mt-1.5" style={{ background: n.color }} />
|
| 104 |
+
<div className="min-w-0">
|
| 105 |
+
<div className="text-xs font-semibold text-white">{n.title}</div>
|
| 106 |
+
<div className="text-xs mt-0.5 text-slate-400 line-clamp-1">{n.message}</div>
|
| 107 |
+
<div className="text-xs mt-1 text-slate-600">{n.time}</div>
|
| 108 |
+
</div>
|
| 109 |
+
</div>
|
| 110 |
+
))}
|
| 111 |
+
</motion.div>
|
| 112 |
+
)}
|
| 113 |
+
</AnimatePresence>
|
| 114 |
+
</div>
|
| 115 |
+
|
| 116 |
+
{/* Avatar */}
|
| 117 |
+
<div className="w-8 h-8 rounded-full overflow-hidden border-2 cursor-pointer"
|
| 118 |
+
style={{ borderColor: 'rgba(124,58,237,0.4)', background: 'linear-gradient(135deg, #7c3aed, #4f46e5)' }}>
|
| 119 |
+
<div className="w-full h-full flex items-center justify-center text-xs font-bold text-white">A</div>
|
| 120 |
+
</div>
|
| 121 |
+
</div>
|
| 122 |
+
|
| 123 |
+
{/* Command Palette Modal */}
|
| 124 |
+
<AnimatePresence>
|
| 125 |
+
{commandPaletteOpen && (
|
| 126 |
+
<>
|
| 127 |
+
<motion.div
|
| 128 |
+
initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}
|
| 129 |
+
className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50"
|
| 130 |
+
onClick={() => { setCommandPaletteOpen(false); setQuery('') }}
|
| 131 |
+
/>
|
| 132 |
+
<motion.div
|
| 133 |
+
initial={{ opacity: 0, scale: 0.96, y: -16 }}
|
| 134 |
+
animate={{ opacity: 1, scale: 1, y: 0 }}
|
| 135 |
+
exit={{ opacity: 0, scale: 0.96, y: -16 }}
|
| 136 |
+
transition={{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }}
|
| 137 |
+
className="fixed top-[20vh] left-1/2 -translate-x-1/2 w-full max-w-lg glass-card z-50 overflow-hidden"
|
| 138 |
+
>
|
| 139 |
+
<div className="flex items-center gap-3 px-4 py-3.5 border-b" style={{ borderColor: 'var(--border)' }}>
|
| 140 |
+
<Search size={16} className="text-slate-500" />
|
| 141 |
+
<input
|
| 142 |
+
ref={inputRef}
|
| 143 |
+
value={query}
|
| 144 |
+
onChange={e => setQuery(e.target.value)}
|
| 145 |
+
placeholder="Search agents, run commands…"
|
| 146 |
+
className="flex-1 bg-transparent text-sm text-white placeholder:text-slate-500 outline-none"
|
| 147 |
+
/>
|
| 148 |
+
<button onClick={() => { setCommandPaletteOpen(false); setQuery('') }}
|
| 149 |
+
className="text-slate-500 hover:text-slate-300 transition-colors">
|
| 150 |
+
<X size={14} />
|
| 151 |
+
</button>
|
| 152 |
+
</div>
|
| 153 |
+
<div className="py-2 max-h-64 overflow-y-auto">
|
| 154 |
+
{filtered.map(({ icon: Icon, label, shortcut, page }) => (
|
| 155 |
+
<button key={label}
|
| 156 |
+
onClick={() => { setCurrentPage(page); setCommandPaletteOpen(false); setQuery('') }}
|
| 157 |
+
className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-white/[0.04] transition-colors group">
|
| 158 |
+
<Icon size={15} className="text-purple-400 group-hover:text-purple-300" />
|
| 159 |
+
<span className="flex-1 text-sm text-left text-slate-300 group-hover:text-white">{label}</span>
|
| 160 |
+
<span className="text-xs font-mono px-2 py-0.5 rounded"
|
| 161 |
+
style={{ background: 'rgba(255,255,255,0.06)', color: 'var(--text-muted)' }}>{shortcut}</span>
|
| 162 |
+
<ArrowRight size={13} className="text-slate-600 group-hover:text-purple-400 transition-colors" />
|
| 163 |
+
</button>
|
| 164 |
+
))}
|
| 165 |
+
{filtered.length === 0 && (
|
| 166 |
+
<div className="px-4 py-6 text-center text-sm text-slate-600">No results for "{query}"</div>
|
| 167 |
+
)}
|
| 168 |
+
</div>
|
| 169 |
+
<div className="px-4 py-2 border-t flex items-center gap-4 text-xs text-slate-600"
|
| 170 |
+
style={{ borderColor: 'var(--border)' }}>
|
| 171 |
+
<span>↑↓ navigate</span>
|
| 172 |
+
<span>↵ select</span>
|
| 173 |
+
<span>esc close</span>
|
| 174 |
+
</div>
|
| 175 |
+
</motion.div>
|
| 176 |
+
</>
|
| 177 |
+
)}
|
| 178 |
+
</AnimatePresence>
|
| 179 |
+
</header>
|
| 180 |
+
)
|
| 181 |
+
}
|
frontend/hooks/useAgentStore.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { nanoid } from './nanoid'
|
|
| 9 |
export type Theme = 'dark' | 'light' | 'amoled' | 'neon' | 'glass'
|
| 10 |
export type Locale = 'en' | 'my'
|
| 11 |
export type AgentName = 'chat' | 'planner' | 'coding' | 'debug' | 'memory' | 'connector' | 'deploy' | 'workflow' | 'sandbox' | 'ui' | 'browser' | 'file' | 'git' | 'test' | 'vision' | 'reasoning'
|
| 12 |
-
export type ActivePanel = 'timeline' | 'tasks' | 'memory' | 'connectors' | 'sandbox' | 'files' | 'browser'
|
| 13 |
|
| 14 |
export interface Message {
|
| 15 |
id: string
|
|
|
|
| 9 |
export type Theme = 'dark' | 'light' | 'amoled' | 'neon' | 'glass'
|
| 10 |
export type Locale = 'en' | 'my'
|
| 11 |
export type AgentName = 'chat' | 'planner' | 'coding' | 'debug' | 'memory' | 'connector' | 'deploy' | 'workflow' | 'sandbox' | 'ui' | 'browser' | 'file' | 'git' | 'test' | 'vision' | 'reasoning'
|
| 12 |
+
export type ActivePanel = 'timeline' | 'tasks' | 'memory' | 'connectors' | 'sandbox' | 'files' | 'browser' | 'ai_router'
|
| 13 |
|
| 14 |
export interface Message {
|
| 15 |
id: string
|
frontend/lib/utils.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { type ClassValue, clsx } from 'clsx'
|
| 2 |
+
import { twMerge } from 'tailwind-merge'
|
| 3 |
+
|
| 4 |
+
export function cn(...inputs: ClassValue[]) {
|
| 5 |
+
return twMerge(clsx(inputs))
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
export function formatNumber(n: number): string {
|
| 9 |
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
|
| 10 |
+
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`
|
| 11 |
+
return n.toString()
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
export function getStatusColor(status: string): string {
|
| 15 |
+
switch (status) {
|
| 16 |
+
case 'active': return '#22c55e'
|
| 17 |
+
case 'processing': return '#f59e0b'
|
| 18 |
+
case 'idle': return '#94a3b8'
|
| 19 |
+
case 'error': return '#ef4444'
|
| 20 |
+
case 'running': return '#6366f1'
|
| 21 |
+
case 'completed': return '#22c55e'
|
| 22 |
+
case 'pending': return '#94a3b8'
|
| 23 |
+
case 'failed': return '#ef4444'
|
| 24 |
+
default: return '#94a3b8'
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
export function getStatusLabel(status: string): string {
|
| 29 |
+
return status.charAt(0).toUpperCase() + status.slice(1)
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
export function randomBetween(min: number, max: number): number {
|
| 33 |
+
return Math.floor(Math.random() * (max - min + 1)) + min
|
| 34 |
+
}
|
frontend/package-lock.json
CHANGED
|
@@ -8,6 +8,13 @@
|
|
| 8 |
"name": "god-mode-plus-ui",
|
| 9 |
"version": "3.0.0",
|
| 10 |
"dependencies": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
"clsx": "^2.1.1",
|
| 12 |
"date-fns": "^3.6.0",
|
| 13 |
"framer-motion": "^11.1.9",
|
|
@@ -58,6 +65,44 @@
|
|
| 58 |
"node": ">=6.9.0"
|
| 59 |
}
|
| 60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
"node_modules/@jridgewell/gen-mapping": {
|
| 62 |
"version": "0.3.13",
|
| 63 |
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
|
@@ -167,124 +212,948 @@
|
|
| 167 |
"node": ">= 10"
|
| 168 |
}
|
| 169 |
},
|
| 170 |
-
"node_modules/@next/swc-linux-x64-gnu": {
|
| 171 |
-
"version": "14.2.3",
|
| 172 |
-
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz",
|
| 173 |
-
"integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==",
|
| 174 |
-
"cpu": [
|
| 175 |
-
"x64"
|
| 176 |
-
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
"license": "MIT",
|
| 178 |
-
"
|
| 179 |
-
|
| 180 |
-
"
|
| 181 |
-
|
| 182 |
-
"
|
| 183 |
-
"
|
|
|
|
|
|
|
| 184 |
}
|
| 185 |
},
|
| 186 |
-
"node_modules/@
|
| 187 |
-
"version": "
|
| 188 |
-
"resolved": "https://registry.npmjs.org/@
|
| 189 |
-
"integrity": "sha512-
|
| 190 |
-
"cpu": [
|
| 191 |
-
"x64"
|
| 192 |
-
],
|
| 193 |
"license": "MIT",
|
| 194 |
-
"
|
| 195 |
-
|
| 196 |
-
"
|
| 197 |
-
|
| 198 |
-
"
|
| 199 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 200 |
}
|
| 201 |
},
|
| 202 |
-
"node_modules/@
|
| 203 |
-
"version": "
|
| 204 |
-
"resolved": "https://registry.npmjs.org/@
|
| 205 |
-
"integrity": "sha512-
|
| 206 |
-
"cpu": [
|
| 207 |
-
"arm64"
|
| 208 |
-
],
|
| 209 |
"license": "MIT",
|
| 210 |
-
"
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
}
|
| 217 |
},
|
| 218 |
-
"node_modules/@
|
| 219 |
-
"version": "
|
| 220 |
-
"resolved": "https://registry.npmjs.org/@
|
| 221 |
-
"integrity": "sha512-
|
| 222 |
-
"cpu": [
|
| 223 |
-
"ia32"
|
| 224 |
-
],
|
| 225 |
"license": "MIT",
|
| 226 |
-
"
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
}
|
| 233 |
},
|
| 234 |
-
"node_modules/@
|
| 235 |
-
"version": "
|
| 236 |
-
"resolved": "https://registry.npmjs.org/@
|
| 237 |
-
"integrity": "sha512-
|
| 238 |
-
"cpu": [
|
| 239 |
-
"x64"
|
| 240 |
-
],
|
| 241 |
"license": "MIT",
|
| 242 |
-
"
|
| 243 |
-
|
| 244 |
-
"
|
| 245 |
-
|
| 246 |
-
"
|
| 247 |
-
"
|
|
|
|
|
|
|
| 248 |
}
|
| 249 |
},
|
| 250 |
-
"node_modules/@
|
| 251 |
-
"version": "
|
| 252 |
-
"resolved": "https://registry.npmjs.org/@
|
| 253 |
-
"integrity": "sha512-
|
| 254 |
-
"dev": true,
|
| 255 |
"license": "MIT",
|
| 256 |
"dependencies": {
|
| 257 |
-
"@
|
| 258 |
-
"run-parallel": "^1.1.9"
|
| 259 |
},
|
| 260 |
-
"
|
| 261 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
}
|
| 263 |
},
|
| 264 |
-
"node_modules/@
|
| 265 |
-
"version": "
|
| 266 |
-
"resolved": "https://registry.npmjs.org/@
|
| 267 |
-
"integrity": "sha512-
|
| 268 |
-
"dev": true,
|
| 269 |
"license": "MIT",
|
| 270 |
-
"
|
| 271 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 272 |
}
|
| 273 |
},
|
| 274 |
-
"node_modules/@
|
| 275 |
-
"version": "1.2.
|
| 276 |
-
"resolved": "https://registry.npmjs.org/@
|
| 277 |
-
"integrity": "sha512-
|
| 278 |
-
"dev": true,
|
| 279 |
"license": "MIT",
|
| 280 |
"dependencies": {
|
| 281 |
-
"@
|
| 282 |
-
"fastq": "^1.6.0"
|
| 283 |
},
|
| 284 |
-
"
|
| 285 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 286 |
}
|
| 287 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
"node_modules/@reduxjs/toolkit": {
|
| 289 |
"version": "2.11.2",
|
| 290 |
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz",
|
|
@@ -490,7 +1359,7 @@
|
|
| 490 |
"version": "18.3.7",
|
| 491 |
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
| 492 |
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
| 493 |
-
"
|
| 494 |
"license": "MIT",
|
| 495 |
"peerDependencies": {
|
| 496 |
"@types/react": "^18.0.0"
|
|
@@ -565,6 +1434,18 @@
|
|
| 565 |
"dev": true,
|
| 566 |
"license": "MIT"
|
| 567 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 568 |
"node_modules/autoprefixer": {
|
| 569 |
"version": "10.5.0",
|
| 570 |
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
|
|
@@ -814,6 +1695,18 @@
|
|
| 814 |
"node": ">= 6"
|
| 815 |
}
|
| 816 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 817 |
"node_modules/client-only": {
|
| 818 |
"version": "0.0.1",
|
| 819 |
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
|
@@ -1044,6 +1937,12 @@
|
|
| 1044 |
"node": ">=6"
|
| 1045 |
}
|
| 1046 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1047 |
"node_modules/devlop": {
|
| 1048 |
"version": "1.1.0",
|
| 1049 |
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
|
@@ -1300,6 +2199,15 @@
|
|
| 1300 |
"url": "https://github.com/sponsors/ljharb"
|
| 1301 |
}
|
| 1302 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1303 |
"node_modules/glob-parent": {
|
| 1304 |
"version": "6.0.2",
|
| 1305 |
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
|
@@ -3182,6 +4090,75 @@
|
|
| 3182 |
}
|
| 3183 |
}
|
| 3184 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3185 |
"node_modules/react-syntax-highlighter": {
|
| 3186 |
"version": "15.6.6",
|
| 3187 |
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.6.tgz",
|
|
@@ -3986,6 +4963,49 @@
|
|
| 3986 |
"browserslist": ">= 4.21.0"
|
| 3987 |
}
|
| 3988 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3989 |
"node_modules/use-sync-external-store": {
|
| 3990 |
"version": "1.6.0",
|
| 3991 |
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
|
|
|
| 8 |
"name": "god-mode-plus-ui",
|
| 9 |
"version": "3.0.0",
|
| 10 |
"dependencies": {
|
| 11 |
+
"@radix-ui/react-dialog": "^1.1.15",
|
| 12 |
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
| 13 |
+
"@radix-ui/react-progress": "^1.1.8",
|
| 14 |
+
"@radix-ui/react-separator": "^1.1.8",
|
| 15 |
+
"@radix-ui/react-slot": "^1.2.4",
|
| 16 |
+
"@radix-ui/react-tooltip": "^1.2.8",
|
| 17 |
+
"class-variance-authority": "^0.7.1",
|
| 18 |
"clsx": "^2.1.1",
|
| 19 |
"date-fns": "^3.6.0",
|
| 20 |
"framer-motion": "^11.1.9",
|
|
|
|
| 65 |
"node": ">=6.9.0"
|
| 66 |
}
|
| 67 |
},
|
| 68 |
+
"node_modules/@floating-ui/core": {
|
| 69 |
+
"version": "1.7.5",
|
| 70 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
|
| 71 |
+
"integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
|
| 72 |
+
"license": "MIT",
|
| 73 |
+
"dependencies": {
|
| 74 |
+
"@floating-ui/utils": "^0.2.11"
|
| 75 |
+
}
|
| 76 |
+
},
|
| 77 |
+
"node_modules/@floating-ui/dom": {
|
| 78 |
+
"version": "1.7.6",
|
| 79 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
|
| 80 |
+
"integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
|
| 81 |
+
"license": "MIT",
|
| 82 |
+
"dependencies": {
|
| 83 |
+
"@floating-ui/core": "^1.7.5",
|
| 84 |
+
"@floating-ui/utils": "^0.2.11"
|
| 85 |
+
}
|
| 86 |
+
},
|
| 87 |
+
"node_modules/@floating-ui/react-dom": {
|
| 88 |
+
"version": "2.1.8",
|
| 89 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz",
|
| 90 |
+
"integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==",
|
| 91 |
+
"license": "MIT",
|
| 92 |
+
"dependencies": {
|
| 93 |
+
"@floating-ui/dom": "^1.7.6"
|
| 94 |
+
},
|
| 95 |
+
"peerDependencies": {
|
| 96 |
+
"react": ">=16.8.0",
|
| 97 |
+
"react-dom": ">=16.8.0"
|
| 98 |
+
}
|
| 99 |
+
},
|
| 100 |
+
"node_modules/@floating-ui/utils": {
|
| 101 |
+
"version": "0.2.11",
|
| 102 |
+
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
|
| 103 |
+
"integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
|
| 104 |
+
"license": "MIT"
|
| 105 |
+
},
|
| 106 |
"node_modules/@jridgewell/gen-mapping": {
|
| 107 |
"version": "0.3.13",
|
| 108 |
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
|
|
|
| 212 |
"node": ">= 10"
|
| 213 |
}
|
| 214 |
},
|
| 215 |
+
"node_modules/@next/swc-linux-x64-gnu": {
|
| 216 |
+
"version": "14.2.3",
|
| 217 |
+
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz",
|
| 218 |
+
"integrity": "sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w==",
|
| 219 |
+
"cpu": [
|
| 220 |
+
"x64"
|
| 221 |
+
],
|
| 222 |
+
"license": "MIT",
|
| 223 |
+
"optional": true,
|
| 224 |
+
"os": [
|
| 225 |
+
"linux"
|
| 226 |
+
],
|
| 227 |
+
"engines": {
|
| 228 |
+
"node": ">= 10"
|
| 229 |
+
}
|
| 230 |
+
},
|
| 231 |
+
"node_modules/@next/swc-linux-x64-musl": {
|
| 232 |
+
"version": "14.2.3",
|
| 233 |
+
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz",
|
| 234 |
+
"integrity": "sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ==",
|
| 235 |
+
"cpu": [
|
| 236 |
+
"x64"
|
| 237 |
+
],
|
| 238 |
+
"license": "MIT",
|
| 239 |
+
"optional": true,
|
| 240 |
+
"os": [
|
| 241 |
+
"linux"
|
| 242 |
+
],
|
| 243 |
+
"engines": {
|
| 244 |
+
"node": ">= 10"
|
| 245 |
+
}
|
| 246 |
+
},
|
| 247 |
+
"node_modules/@next/swc-win32-arm64-msvc": {
|
| 248 |
+
"version": "14.2.3",
|
| 249 |
+
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz",
|
| 250 |
+
"integrity": "sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A==",
|
| 251 |
+
"cpu": [
|
| 252 |
+
"arm64"
|
| 253 |
+
],
|
| 254 |
+
"license": "MIT",
|
| 255 |
+
"optional": true,
|
| 256 |
+
"os": [
|
| 257 |
+
"win32"
|
| 258 |
+
],
|
| 259 |
+
"engines": {
|
| 260 |
+
"node": ">= 10"
|
| 261 |
+
}
|
| 262 |
+
},
|
| 263 |
+
"node_modules/@next/swc-win32-ia32-msvc": {
|
| 264 |
+
"version": "14.2.3",
|
| 265 |
+
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz",
|
| 266 |
+
"integrity": "sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw==",
|
| 267 |
+
"cpu": [
|
| 268 |
+
"ia32"
|
| 269 |
+
],
|
| 270 |
+
"license": "MIT",
|
| 271 |
+
"optional": true,
|
| 272 |
+
"os": [
|
| 273 |
+
"win32"
|
| 274 |
+
],
|
| 275 |
+
"engines": {
|
| 276 |
+
"node": ">= 10"
|
| 277 |
+
}
|
| 278 |
+
},
|
| 279 |
+
"node_modules/@next/swc-win32-x64-msvc": {
|
| 280 |
+
"version": "14.2.3",
|
| 281 |
+
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz",
|
| 282 |
+
"integrity": "sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA==",
|
| 283 |
+
"cpu": [
|
| 284 |
+
"x64"
|
| 285 |
+
],
|
| 286 |
+
"license": "MIT",
|
| 287 |
+
"optional": true,
|
| 288 |
+
"os": [
|
| 289 |
+
"win32"
|
| 290 |
+
],
|
| 291 |
+
"engines": {
|
| 292 |
+
"node": ">= 10"
|
| 293 |
+
}
|
| 294 |
+
},
|
| 295 |
+
"node_modules/@nodelib/fs.scandir": {
|
| 296 |
+
"version": "2.1.5",
|
| 297 |
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
|
| 298 |
+
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
|
| 299 |
+
"dev": true,
|
| 300 |
+
"license": "MIT",
|
| 301 |
+
"dependencies": {
|
| 302 |
+
"@nodelib/fs.stat": "2.0.5",
|
| 303 |
+
"run-parallel": "^1.1.9"
|
| 304 |
+
},
|
| 305 |
+
"engines": {
|
| 306 |
+
"node": ">= 8"
|
| 307 |
+
}
|
| 308 |
+
},
|
| 309 |
+
"node_modules/@nodelib/fs.stat": {
|
| 310 |
+
"version": "2.0.5",
|
| 311 |
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
|
| 312 |
+
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
|
| 313 |
+
"dev": true,
|
| 314 |
+
"license": "MIT",
|
| 315 |
+
"engines": {
|
| 316 |
+
"node": ">= 8"
|
| 317 |
+
}
|
| 318 |
+
},
|
| 319 |
+
"node_modules/@nodelib/fs.walk": {
|
| 320 |
+
"version": "1.2.8",
|
| 321 |
+
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
|
| 322 |
+
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
|
| 323 |
+
"dev": true,
|
| 324 |
+
"license": "MIT",
|
| 325 |
+
"dependencies": {
|
| 326 |
+
"@nodelib/fs.scandir": "2.1.5",
|
| 327 |
+
"fastq": "^1.6.0"
|
| 328 |
+
},
|
| 329 |
+
"engines": {
|
| 330 |
+
"node": ">= 8"
|
| 331 |
+
}
|
| 332 |
+
},
|
| 333 |
+
"node_modules/@radix-ui/primitive": {
|
| 334 |
+
"version": "1.1.3",
|
| 335 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
| 336 |
+
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
| 337 |
+
"license": "MIT"
|
| 338 |
+
},
|
| 339 |
+
"node_modules/@radix-ui/react-arrow": {
|
| 340 |
+
"version": "1.1.7",
|
| 341 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
| 342 |
+
"integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
|
| 343 |
+
"license": "MIT",
|
| 344 |
+
"dependencies": {
|
| 345 |
+
"@radix-ui/react-primitive": "2.1.3"
|
| 346 |
+
},
|
| 347 |
+
"peerDependencies": {
|
| 348 |
+
"@types/react": "*",
|
| 349 |
+
"@types/react-dom": "*",
|
| 350 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 351 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 352 |
+
},
|
| 353 |
+
"peerDependenciesMeta": {
|
| 354 |
+
"@types/react": {
|
| 355 |
+
"optional": true
|
| 356 |
+
},
|
| 357 |
+
"@types/react-dom": {
|
| 358 |
+
"optional": true
|
| 359 |
+
}
|
| 360 |
+
}
|
| 361 |
+
},
|
| 362 |
+
"node_modules/@radix-ui/react-collection": {
|
| 363 |
+
"version": "1.1.7",
|
| 364 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
|
| 365 |
+
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
|
| 366 |
+
"license": "MIT",
|
| 367 |
+
"dependencies": {
|
| 368 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 369 |
+
"@radix-ui/react-context": "1.1.2",
|
| 370 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 371 |
+
"@radix-ui/react-slot": "1.2.3"
|
| 372 |
+
},
|
| 373 |
+
"peerDependencies": {
|
| 374 |
+
"@types/react": "*",
|
| 375 |
+
"@types/react-dom": "*",
|
| 376 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 377 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 378 |
+
},
|
| 379 |
+
"peerDependenciesMeta": {
|
| 380 |
+
"@types/react": {
|
| 381 |
+
"optional": true
|
| 382 |
+
},
|
| 383 |
+
"@types/react-dom": {
|
| 384 |
+
"optional": true
|
| 385 |
+
}
|
| 386 |
+
}
|
| 387 |
+
},
|
| 388 |
+
"node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-slot": {
|
| 389 |
+
"version": "1.2.3",
|
| 390 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
| 391 |
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
| 392 |
+
"license": "MIT",
|
| 393 |
+
"dependencies": {
|
| 394 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
| 395 |
+
},
|
| 396 |
+
"peerDependencies": {
|
| 397 |
+
"@types/react": "*",
|
| 398 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 399 |
+
},
|
| 400 |
+
"peerDependenciesMeta": {
|
| 401 |
+
"@types/react": {
|
| 402 |
+
"optional": true
|
| 403 |
+
}
|
| 404 |
+
}
|
| 405 |
+
},
|
| 406 |
+
"node_modules/@radix-ui/react-compose-refs": {
|
| 407 |
+
"version": "1.1.2",
|
| 408 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
| 409 |
+
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
| 410 |
+
"license": "MIT",
|
| 411 |
+
"peerDependencies": {
|
| 412 |
+
"@types/react": "*",
|
| 413 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 414 |
+
},
|
| 415 |
+
"peerDependenciesMeta": {
|
| 416 |
+
"@types/react": {
|
| 417 |
+
"optional": true
|
| 418 |
+
}
|
| 419 |
+
}
|
| 420 |
+
},
|
| 421 |
+
"node_modules/@radix-ui/react-context": {
|
| 422 |
+
"version": "1.1.2",
|
| 423 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
|
| 424 |
+
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
|
| 425 |
+
"license": "MIT",
|
| 426 |
+
"peerDependencies": {
|
| 427 |
+
"@types/react": "*",
|
| 428 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 429 |
+
},
|
| 430 |
+
"peerDependenciesMeta": {
|
| 431 |
+
"@types/react": {
|
| 432 |
+
"optional": true
|
| 433 |
+
}
|
| 434 |
+
}
|
| 435 |
+
},
|
| 436 |
+
"node_modules/@radix-ui/react-dialog": {
|
| 437 |
+
"version": "1.1.15",
|
| 438 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz",
|
| 439 |
+
"integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==",
|
| 440 |
+
"license": "MIT",
|
| 441 |
+
"dependencies": {
|
| 442 |
+
"@radix-ui/primitive": "1.1.3",
|
| 443 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 444 |
+
"@radix-ui/react-context": "1.1.2",
|
| 445 |
+
"@radix-ui/react-dismissable-layer": "1.1.11",
|
| 446 |
+
"@radix-ui/react-focus-guards": "1.1.3",
|
| 447 |
+
"@radix-ui/react-focus-scope": "1.1.7",
|
| 448 |
+
"@radix-ui/react-id": "1.1.1",
|
| 449 |
+
"@radix-ui/react-portal": "1.1.9",
|
| 450 |
+
"@radix-ui/react-presence": "1.1.5",
|
| 451 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 452 |
+
"@radix-ui/react-slot": "1.2.3",
|
| 453 |
+
"@radix-ui/react-use-controllable-state": "1.2.2",
|
| 454 |
+
"aria-hidden": "^1.2.4",
|
| 455 |
+
"react-remove-scroll": "^2.6.3"
|
| 456 |
+
},
|
| 457 |
+
"peerDependencies": {
|
| 458 |
+
"@types/react": "*",
|
| 459 |
+
"@types/react-dom": "*",
|
| 460 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 461 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 462 |
+
},
|
| 463 |
+
"peerDependenciesMeta": {
|
| 464 |
+
"@types/react": {
|
| 465 |
+
"optional": true
|
| 466 |
+
},
|
| 467 |
+
"@types/react-dom": {
|
| 468 |
+
"optional": true
|
| 469 |
+
}
|
| 470 |
+
}
|
| 471 |
+
},
|
| 472 |
+
"node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
|
| 473 |
+
"version": "1.2.3",
|
| 474 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
| 475 |
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
| 476 |
+
"license": "MIT",
|
| 477 |
+
"dependencies": {
|
| 478 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
| 479 |
+
},
|
| 480 |
+
"peerDependencies": {
|
| 481 |
+
"@types/react": "*",
|
| 482 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 483 |
+
},
|
| 484 |
+
"peerDependenciesMeta": {
|
| 485 |
+
"@types/react": {
|
| 486 |
+
"optional": true
|
| 487 |
+
}
|
| 488 |
+
}
|
| 489 |
+
},
|
| 490 |
+
"node_modules/@radix-ui/react-direction": {
|
| 491 |
+
"version": "1.1.1",
|
| 492 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
| 493 |
+
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
|
| 494 |
+
"license": "MIT",
|
| 495 |
+
"peerDependencies": {
|
| 496 |
+
"@types/react": "*",
|
| 497 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 498 |
+
},
|
| 499 |
+
"peerDependenciesMeta": {
|
| 500 |
+
"@types/react": {
|
| 501 |
+
"optional": true
|
| 502 |
+
}
|
| 503 |
+
}
|
| 504 |
+
},
|
| 505 |
+
"node_modules/@radix-ui/react-dismissable-layer": {
|
| 506 |
+
"version": "1.1.11",
|
| 507 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
| 508 |
+
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
| 509 |
+
"license": "MIT",
|
| 510 |
+
"dependencies": {
|
| 511 |
+
"@radix-ui/primitive": "1.1.3",
|
| 512 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 513 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 514 |
+
"@radix-ui/react-use-callback-ref": "1.1.1",
|
| 515 |
+
"@radix-ui/react-use-escape-keydown": "1.1.1"
|
| 516 |
+
},
|
| 517 |
+
"peerDependencies": {
|
| 518 |
+
"@types/react": "*",
|
| 519 |
+
"@types/react-dom": "*",
|
| 520 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 521 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 522 |
+
},
|
| 523 |
+
"peerDependenciesMeta": {
|
| 524 |
+
"@types/react": {
|
| 525 |
+
"optional": true
|
| 526 |
+
},
|
| 527 |
+
"@types/react-dom": {
|
| 528 |
+
"optional": true
|
| 529 |
+
}
|
| 530 |
+
}
|
| 531 |
+
},
|
| 532 |
+
"node_modules/@radix-ui/react-dropdown-menu": {
|
| 533 |
+
"version": "2.1.16",
|
| 534 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz",
|
| 535 |
+
"integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==",
|
| 536 |
+
"license": "MIT",
|
| 537 |
+
"dependencies": {
|
| 538 |
+
"@radix-ui/primitive": "1.1.3",
|
| 539 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 540 |
+
"@radix-ui/react-context": "1.1.2",
|
| 541 |
+
"@radix-ui/react-id": "1.1.1",
|
| 542 |
+
"@radix-ui/react-menu": "2.1.16",
|
| 543 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 544 |
+
"@radix-ui/react-use-controllable-state": "1.2.2"
|
| 545 |
+
},
|
| 546 |
+
"peerDependencies": {
|
| 547 |
+
"@types/react": "*",
|
| 548 |
+
"@types/react-dom": "*",
|
| 549 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 550 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 551 |
+
},
|
| 552 |
+
"peerDependenciesMeta": {
|
| 553 |
+
"@types/react": {
|
| 554 |
+
"optional": true
|
| 555 |
+
},
|
| 556 |
+
"@types/react-dom": {
|
| 557 |
+
"optional": true
|
| 558 |
+
}
|
| 559 |
+
}
|
| 560 |
+
},
|
| 561 |
+
"node_modules/@radix-ui/react-focus-guards": {
|
| 562 |
+
"version": "1.1.3",
|
| 563 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
|
| 564 |
+
"integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
|
| 565 |
+
"license": "MIT",
|
| 566 |
+
"peerDependencies": {
|
| 567 |
+
"@types/react": "*",
|
| 568 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 569 |
+
},
|
| 570 |
+
"peerDependenciesMeta": {
|
| 571 |
+
"@types/react": {
|
| 572 |
+
"optional": true
|
| 573 |
+
}
|
| 574 |
+
}
|
| 575 |
+
},
|
| 576 |
+
"node_modules/@radix-ui/react-focus-scope": {
|
| 577 |
+
"version": "1.1.7",
|
| 578 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
|
| 579 |
+
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
|
| 580 |
+
"license": "MIT",
|
| 581 |
+
"dependencies": {
|
| 582 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 583 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 584 |
+
"@radix-ui/react-use-callback-ref": "1.1.1"
|
| 585 |
+
},
|
| 586 |
+
"peerDependencies": {
|
| 587 |
+
"@types/react": "*",
|
| 588 |
+
"@types/react-dom": "*",
|
| 589 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 590 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 591 |
+
},
|
| 592 |
+
"peerDependenciesMeta": {
|
| 593 |
+
"@types/react": {
|
| 594 |
+
"optional": true
|
| 595 |
+
},
|
| 596 |
+
"@types/react-dom": {
|
| 597 |
+
"optional": true
|
| 598 |
+
}
|
| 599 |
+
}
|
| 600 |
+
},
|
| 601 |
+
"node_modules/@radix-ui/react-id": {
|
| 602 |
+
"version": "1.1.1",
|
| 603 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
| 604 |
+
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
|
| 605 |
+
"license": "MIT",
|
| 606 |
+
"dependencies": {
|
| 607 |
+
"@radix-ui/react-use-layout-effect": "1.1.1"
|
| 608 |
+
},
|
| 609 |
+
"peerDependencies": {
|
| 610 |
+
"@types/react": "*",
|
| 611 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 612 |
+
},
|
| 613 |
+
"peerDependenciesMeta": {
|
| 614 |
+
"@types/react": {
|
| 615 |
+
"optional": true
|
| 616 |
+
}
|
| 617 |
+
}
|
| 618 |
+
},
|
| 619 |
+
"node_modules/@radix-ui/react-menu": {
|
| 620 |
+
"version": "2.1.16",
|
| 621 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz",
|
| 622 |
+
"integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==",
|
| 623 |
+
"license": "MIT",
|
| 624 |
+
"dependencies": {
|
| 625 |
+
"@radix-ui/primitive": "1.1.3",
|
| 626 |
+
"@radix-ui/react-collection": "1.1.7",
|
| 627 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 628 |
+
"@radix-ui/react-context": "1.1.2",
|
| 629 |
+
"@radix-ui/react-direction": "1.1.1",
|
| 630 |
+
"@radix-ui/react-dismissable-layer": "1.1.11",
|
| 631 |
+
"@radix-ui/react-focus-guards": "1.1.3",
|
| 632 |
+
"@radix-ui/react-focus-scope": "1.1.7",
|
| 633 |
+
"@radix-ui/react-id": "1.1.1",
|
| 634 |
+
"@radix-ui/react-popper": "1.2.8",
|
| 635 |
+
"@radix-ui/react-portal": "1.1.9",
|
| 636 |
+
"@radix-ui/react-presence": "1.1.5",
|
| 637 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 638 |
+
"@radix-ui/react-roving-focus": "1.1.11",
|
| 639 |
+
"@radix-ui/react-slot": "1.2.3",
|
| 640 |
+
"@radix-ui/react-use-callback-ref": "1.1.1",
|
| 641 |
+
"aria-hidden": "^1.2.4",
|
| 642 |
+
"react-remove-scroll": "^2.6.3"
|
| 643 |
+
},
|
| 644 |
+
"peerDependencies": {
|
| 645 |
+
"@types/react": "*",
|
| 646 |
+
"@types/react-dom": "*",
|
| 647 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 648 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 649 |
+
},
|
| 650 |
+
"peerDependenciesMeta": {
|
| 651 |
+
"@types/react": {
|
| 652 |
+
"optional": true
|
| 653 |
+
},
|
| 654 |
+
"@types/react-dom": {
|
| 655 |
+
"optional": true
|
| 656 |
+
}
|
| 657 |
+
}
|
| 658 |
+
},
|
| 659 |
+
"node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": {
|
| 660 |
+
"version": "1.2.3",
|
| 661 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
| 662 |
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
| 663 |
+
"license": "MIT",
|
| 664 |
+
"dependencies": {
|
| 665 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
| 666 |
+
},
|
| 667 |
+
"peerDependencies": {
|
| 668 |
+
"@types/react": "*",
|
| 669 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 670 |
+
},
|
| 671 |
+
"peerDependenciesMeta": {
|
| 672 |
+
"@types/react": {
|
| 673 |
+
"optional": true
|
| 674 |
+
}
|
| 675 |
+
}
|
| 676 |
+
},
|
| 677 |
+
"node_modules/@radix-ui/react-popper": {
|
| 678 |
+
"version": "1.2.8",
|
| 679 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
| 680 |
+
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
|
| 681 |
+
"license": "MIT",
|
| 682 |
+
"dependencies": {
|
| 683 |
+
"@floating-ui/react-dom": "^2.0.0",
|
| 684 |
+
"@radix-ui/react-arrow": "1.1.7",
|
| 685 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 686 |
+
"@radix-ui/react-context": "1.1.2",
|
| 687 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 688 |
+
"@radix-ui/react-use-callback-ref": "1.1.1",
|
| 689 |
+
"@radix-ui/react-use-layout-effect": "1.1.1",
|
| 690 |
+
"@radix-ui/react-use-rect": "1.1.1",
|
| 691 |
+
"@radix-ui/react-use-size": "1.1.1",
|
| 692 |
+
"@radix-ui/rect": "1.1.1"
|
| 693 |
+
},
|
| 694 |
+
"peerDependencies": {
|
| 695 |
+
"@types/react": "*",
|
| 696 |
+
"@types/react-dom": "*",
|
| 697 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 698 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 699 |
+
},
|
| 700 |
+
"peerDependenciesMeta": {
|
| 701 |
+
"@types/react": {
|
| 702 |
+
"optional": true
|
| 703 |
+
},
|
| 704 |
+
"@types/react-dom": {
|
| 705 |
+
"optional": true
|
| 706 |
+
}
|
| 707 |
+
}
|
| 708 |
+
},
|
| 709 |
+
"node_modules/@radix-ui/react-portal": {
|
| 710 |
+
"version": "1.1.9",
|
| 711 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
|
| 712 |
+
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
|
| 713 |
+
"license": "MIT",
|
| 714 |
+
"dependencies": {
|
| 715 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 716 |
+
"@radix-ui/react-use-layout-effect": "1.1.1"
|
| 717 |
+
},
|
| 718 |
+
"peerDependencies": {
|
| 719 |
+
"@types/react": "*",
|
| 720 |
+
"@types/react-dom": "*",
|
| 721 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 722 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 723 |
+
},
|
| 724 |
+
"peerDependenciesMeta": {
|
| 725 |
+
"@types/react": {
|
| 726 |
+
"optional": true
|
| 727 |
+
},
|
| 728 |
+
"@types/react-dom": {
|
| 729 |
+
"optional": true
|
| 730 |
+
}
|
| 731 |
+
}
|
| 732 |
+
},
|
| 733 |
+
"node_modules/@radix-ui/react-presence": {
|
| 734 |
+
"version": "1.1.5",
|
| 735 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
| 736 |
+
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
| 737 |
+
"license": "MIT",
|
| 738 |
+
"dependencies": {
|
| 739 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 740 |
+
"@radix-ui/react-use-layout-effect": "1.1.1"
|
| 741 |
+
},
|
| 742 |
+
"peerDependencies": {
|
| 743 |
+
"@types/react": "*",
|
| 744 |
+
"@types/react-dom": "*",
|
| 745 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 746 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 747 |
+
},
|
| 748 |
+
"peerDependenciesMeta": {
|
| 749 |
+
"@types/react": {
|
| 750 |
+
"optional": true
|
| 751 |
+
},
|
| 752 |
+
"@types/react-dom": {
|
| 753 |
+
"optional": true
|
| 754 |
+
}
|
| 755 |
+
}
|
| 756 |
+
},
|
| 757 |
+
"node_modules/@radix-ui/react-primitive": {
|
| 758 |
+
"version": "2.1.3",
|
| 759 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
| 760 |
+
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
| 761 |
+
"license": "MIT",
|
| 762 |
+
"dependencies": {
|
| 763 |
+
"@radix-ui/react-slot": "1.2.3"
|
| 764 |
+
},
|
| 765 |
+
"peerDependencies": {
|
| 766 |
+
"@types/react": "*",
|
| 767 |
+
"@types/react-dom": "*",
|
| 768 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 769 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 770 |
+
},
|
| 771 |
+
"peerDependenciesMeta": {
|
| 772 |
+
"@types/react": {
|
| 773 |
+
"optional": true
|
| 774 |
+
},
|
| 775 |
+
"@types/react-dom": {
|
| 776 |
+
"optional": true
|
| 777 |
+
}
|
| 778 |
+
}
|
| 779 |
+
},
|
| 780 |
+
"node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": {
|
| 781 |
+
"version": "1.2.3",
|
| 782 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
| 783 |
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
| 784 |
+
"license": "MIT",
|
| 785 |
+
"dependencies": {
|
| 786 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
| 787 |
+
},
|
| 788 |
+
"peerDependencies": {
|
| 789 |
+
"@types/react": "*",
|
| 790 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 791 |
+
},
|
| 792 |
+
"peerDependenciesMeta": {
|
| 793 |
+
"@types/react": {
|
| 794 |
+
"optional": true
|
| 795 |
+
}
|
| 796 |
+
}
|
| 797 |
+
},
|
| 798 |
+
"node_modules/@radix-ui/react-progress": {
|
| 799 |
+
"version": "1.1.8",
|
| 800 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.8.tgz",
|
| 801 |
+
"integrity": "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA==",
|
| 802 |
+
"license": "MIT",
|
| 803 |
+
"dependencies": {
|
| 804 |
+
"@radix-ui/react-context": "1.1.3",
|
| 805 |
+
"@radix-ui/react-primitive": "2.1.4"
|
| 806 |
+
},
|
| 807 |
+
"peerDependencies": {
|
| 808 |
+
"@types/react": "*",
|
| 809 |
+
"@types/react-dom": "*",
|
| 810 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 811 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 812 |
+
},
|
| 813 |
+
"peerDependenciesMeta": {
|
| 814 |
+
"@types/react": {
|
| 815 |
+
"optional": true
|
| 816 |
+
},
|
| 817 |
+
"@types/react-dom": {
|
| 818 |
+
"optional": true
|
| 819 |
+
}
|
| 820 |
+
}
|
| 821 |
+
},
|
| 822 |
+
"node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-context": {
|
| 823 |
+
"version": "1.1.3",
|
| 824 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz",
|
| 825 |
+
"integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==",
|
| 826 |
+
"license": "MIT",
|
| 827 |
+
"peerDependencies": {
|
| 828 |
+
"@types/react": "*",
|
| 829 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 830 |
+
},
|
| 831 |
+
"peerDependenciesMeta": {
|
| 832 |
+
"@types/react": {
|
| 833 |
+
"optional": true
|
| 834 |
+
}
|
| 835 |
+
}
|
| 836 |
+
},
|
| 837 |
+
"node_modules/@radix-ui/react-progress/node_modules/@radix-ui/react-primitive": {
|
| 838 |
+
"version": "2.1.4",
|
| 839 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz",
|
| 840 |
+
"integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==",
|
| 841 |
+
"license": "MIT",
|
| 842 |
+
"dependencies": {
|
| 843 |
+
"@radix-ui/react-slot": "1.2.4"
|
| 844 |
+
},
|
| 845 |
+
"peerDependencies": {
|
| 846 |
+
"@types/react": "*",
|
| 847 |
+
"@types/react-dom": "*",
|
| 848 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 849 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 850 |
+
},
|
| 851 |
+
"peerDependenciesMeta": {
|
| 852 |
+
"@types/react": {
|
| 853 |
+
"optional": true
|
| 854 |
+
},
|
| 855 |
+
"@types/react-dom": {
|
| 856 |
+
"optional": true
|
| 857 |
+
}
|
| 858 |
+
}
|
| 859 |
+
},
|
| 860 |
+
"node_modules/@radix-ui/react-roving-focus": {
|
| 861 |
+
"version": "1.1.11",
|
| 862 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
|
| 863 |
+
"integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
|
| 864 |
+
"license": "MIT",
|
| 865 |
+
"dependencies": {
|
| 866 |
+
"@radix-ui/primitive": "1.1.3",
|
| 867 |
+
"@radix-ui/react-collection": "1.1.7",
|
| 868 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 869 |
+
"@radix-ui/react-context": "1.1.2",
|
| 870 |
+
"@radix-ui/react-direction": "1.1.1",
|
| 871 |
+
"@radix-ui/react-id": "1.1.1",
|
| 872 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 873 |
+
"@radix-ui/react-use-callback-ref": "1.1.1",
|
| 874 |
+
"@radix-ui/react-use-controllable-state": "1.2.2"
|
| 875 |
+
},
|
| 876 |
+
"peerDependencies": {
|
| 877 |
+
"@types/react": "*",
|
| 878 |
+
"@types/react-dom": "*",
|
| 879 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 880 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 881 |
+
},
|
| 882 |
+
"peerDependenciesMeta": {
|
| 883 |
+
"@types/react": {
|
| 884 |
+
"optional": true
|
| 885 |
+
},
|
| 886 |
+
"@types/react-dom": {
|
| 887 |
+
"optional": true
|
| 888 |
+
}
|
| 889 |
+
}
|
| 890 |
+
},
|
| 891 |
+
"node_modules/@radix-ui/react-separator": {
|
| 892 |
+
"version": "1.1.8",
|
| 893 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz",
|
| 894 |
+
"integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==",
|
| 895 |
+
"license": "MIT",
|
| 896 |
+
"dependencies": {
|
| 897 |
+
"@radix-ui/react-primitive": "2.1.4"
|
| 898 |
+
},
|
| 899 |
+
"peerDependencies": {
|
| 900 |
+
"@types/react": "*",
|
| 901 |
+
"@types/react-dom": "*",
|
| 902 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 903 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 904 |
+
},
|
| 905 |
+
"peerDependenciesMeta": {
|
| 906 |
+
"@types/react": {
|
| 907 |
+
"optional": true
|
| 908 |
+
},
|
| 909 |
+
"@types/react-dom": {
|
| 910 |
+
"optional": true
|
| 911 |
+
}
|
| 912 |
+
}
|
| 913 |
+
},
|
| 914 |
+
"node_modules/@radix-ui/react-separator/node_modules/@radix-ui/react-primitive": {
|
| 915 |
+
"version": "2.1.4",
|
| 916 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz",
|
| 917 |
+
"integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==",
|
| 918 |
+
"license": "MIT",
|
| 919 |
+
"dependencies": {
|
| 920 |
+
"@radix-ui/react-slot": "1.2.4"
|
| 921 |
+
},
|
| 922 |
+
"peerDependencies": {
|
| 923 |
+
"@types/react": "*",
|
| 924 |
+
"@types/react-dom": "*",
|
| 925 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 926 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 927 |
+
},
|
| 928 |
+
"peerDependenciesMeta": {
|
| 929 |
+
"@types/react": {
|
| 930 |
+
"optional": true
|
| 931 |
+
},
|
| 932 |
+
"@types/react-dom": {
|
| 933 |
+
"optional": true
|
| 934 |
+
}
|
| 935 |
+
}
|
| 936 |
+
},
|
| 937 |
+
"node_modules/@radix-ui/react-slot": {
|
| 938 |
+
"version": "1.2.4",
|
| 939 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz",
|
| 940 |
+
"integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==",
|
| 941 |
+
"license": "MIT",
|
| 942 |
+
"dependencies": {
|
| 943 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
| 944 |
+
},
|
| 945 |
+
"peerDependencies": {
|
| 946 |
+
"@types/react": "*",
|
| 947 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 948 |
+
},
|
| 949 |
+
"peerDependenciesMeta": {
|
| 950 |
+
"@types/react": {
|
| 951 |
+
"optional": true
|
| 952 |
+
}
|
| 953 |
+
}
|
| 954 |
+
},
|
| 955 |
+
"node_modules/@radix-ui/react-tooltip": {
|
| 956 |
+
"version": "1.2.8",
|
| 957 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz",
|
| 958 |
+
"integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==",
|
| 959 |
+
"license": "MIT",
|
| 960 |
+
"dependencies": {
|
| 961 |
+
"@radix-ui/primitive": "1.1.3",
|
| 962 |
+
"@radix-ui/react-compose-refs": "1.1.2",
|
| 963 |
+
"@radix-ui/react-context": "1.1.2",
|
| 964 |
+
"@radix-ui/react-dismissable-layer": "1.1.11",
|
| 965 |
+
"@radix-ui/react-id": "1.1.1",
|
| 966 |
+
"@radix-ui/react-popper": "1.2.8",
|
| 967 |
+
"@radix-ui/react-portal": "1.1.9",
|
| 968 |
+
"@radix-ui/react-presence": "1.1.5",
|
| 969 |
+
"@radix-ui/react-primitive": "2.1.3",
|
| 970 |
+
"@radix-ui/react-slot": "1.2.3",
|
| 971 |
+
"@radix-ui/react-use-controllable-state": "1.2.2",
|
| 972 |
+
"@radix-ui/react-visually-hidden": "1.2.3"
|
| 973 |
+
},
|
| 974 |
+
"peerDependencies": {
|
| 975 |
+
"@types/react": "*",
|
| 976 |
+
"@types/react-dom": "*",
|
| 977 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 978 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 979 |
+
},
|
| 980 |
+
"peerDependenciesMeta": {
|
| 981 |
+
"@types/react": {
|
| 982 |
+
"optional": true
|
| 983 |
+
},
|
| 984 |
+
"@types/react-dom": {
|
| 985 |
+
"optional": true
|
| 986 |
+
}
|
| 987 |
+
}
|
| 988 |
+
},
|
| 989 |
+
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": {
|
| 990 |
+
"version": "1.2.3",
|
| 991 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
| 992 |
+
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
| 993 |
+
"license": "MIT",
|
| 994 |
+
"dependencies": {
|
| 995 |
+
"@radix-ui/react-compose-refs": "1.1.2"
|
| 996 |
+
},
|
| 997 |
+
"peerDependencies": {
|
| 998 |
+
"@types/react": "*",
|
| 999 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1000 |
+
},
|
| 1001 |
+
"peerDependenciesMeta": {
|
| 1002 |
+
"@types/react": {
|
| 1003 |
+
"optional": true
|
| 1004 |
+
}
|
| 1005 |
+
}
|
| 1006 |
+
},
|
| 1007 |
+
"node_modules/@radix-ui/react-use-callback-ref": {
|
| 1008 |
+
"version": "1.1.1",
|
| 1009 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
| 1010 |
+
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
|
| 1011 |
"license": "MIT",
|
| 1012 |
+
"peerDependencies": {
|
| 1013 |
+
"@types/react": "*",
|
| 1014 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1015 |
+
},
|
| 1016 |
+
"peerDependenciesMeta": {
|
| 1017 |
+
"@types/react": {
|
| 1018 |
+
"optional": true
|
| 1019 |
+
}
|
| 1020 |
}
|
| 1021 |
},
|
| 1022 |
+
"node_modules/@radix-ui/react-use-controllable-state": {
|
| 1023 |
+
"version": "1.2.2",
|
| 1024 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
|
| 1025 |
+
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
|
|
|
|
|
|
|
|
|
|
| 1026 |
"license": "MIT",
|
| 1027 |
+
"dependencies": {
|
| 1028 |
+
"@radix-ui/react-use-effect-event": "0.0.2",
|
| 1029 |
+
"@radix-ui/react-use-layout-effect": "1.1.1"
|
| 1030 |
+
},
|
| 1031 |
+
"peerDependencies": {
|
| 1032 |
+
"@types/react": "*",
|
| 1033 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1034 |
+
},
|
| 1035 |
+
"peerDependenciesMeta": {
|
| 1036 |
+
"@types/react": {
|
| 1037 |
+
"optional": true
|
| 1038 |
+
}
|
| 1039 |
}
|
| 1040 |
},
|
| 1041 |
+
"node_modules/@radix-ui/react-use-effect-event": {
|
| 1042 |
+
"version": "0.0.2",
|
| 1043 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
|
| 1044 |
+
"integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
|
|
|
|
|
|
|
|
|
|
| 1045 |
"license": "MIT",
|
| 1046 |
+
"dependencies": {
|
| 1047 |
+
"@radix-ui/react-use-layout-effect": "1.1.1"
|
| 1048 |
+
},
|
| 1049 |
+
"peerDependencies": {
|
| 1050 |
+
"@types/react": "*",
|
| 1051 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1052 |
+
},
|
| 1053 |
+
"peerDependenciesMeta": {
|
| 1054 |
+
"@types/react": {
|
| 1055 |
+
"optional": true
|
| 1056 |
+
}
|
| 1057 |
}
|
| 1058 |
},
|
| 1059 |
+
"node_modules/@radix-ui/react-use-escape-keydown": {
|
| 1060 |
+
"version": "1.1.1",
|
| 1061 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
|
| 1062 |
+
"integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
|
|
|
|
|
|
|
|
|
|
| 1063 |
"license": "MIT",
|
| 1064 |
+
"dependencies": {
|
| 1065 |
+
"@radix-ui/react-use-callback-ref": "1.1.1"
|
| 1066 |
+
},
|
| 1067 |
+
"peerDependencies": {
|
| 1068 |
+
"@types/react": "*",
|
| 1069 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1070 |
+
},
|
| 1071 |
+
"peerDependenciesMeta": {
|
| 1072 |
+
"@types/react": {
|
| 1073 |
+
"optional": true
|
| 1074 |
+
}
|
| 1075 |
}
|
| 1076 |
},
|
| 1077 |
+
"node_modules/@radix-ui/react-use-layout-effect": {
|
| 1078 |
+
"version": "1.1.1",
|
| 1079 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
| 1080 |
+
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
|
|
|
|
|
|
|
|
|
| 1081 |
"license": "MIT",
|
| 1082 |
+
"peerDependencies": {
|
| 1083 |
+
"@types/react": "*",
|
| 1084 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1085 |
+
},
|
| 1086 |
+
"peerDependenciesMeta": {
|
| 1087 |
+
"@types/react": {
|
| 1088 |
+
"optional": true
|
| 1089 |
+
}
|
| 1090 |
}
|
| 1091 |
},
|
| 1092 |
+
"node_modules/@radix-ui/react-use-rect": {
|
| 1093 |
+
"version": "1.1.1",
|
| 1094 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
|
| 1095 |
+
"integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
|
|
|
|
| 1096 |
"license": "MIT",
|
| 1097 |
"dependencies": {
|
| 1098 |
+
"@radix-ui/rect": "1.1.1"
|
|
|
|
| 1099 |
},
|
| 1100 |
+
"peerDependencies": {
|
| 1101 |
+
"@types/react": "*",
|
| 1102 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1103 |
+
},
|
| 1104 |
+
"peerDependenciesMeta": {
|
| 1105 |
+
"@types/react": {
|
| 1106 |
+
"optional": true
|
| 1107 |
+
}
|
| 1108 |
}
|
| 1109 |
},
|
| 1110 |
+
"node_modules/@radix-ui/react-use-size": {
|
| 1111 |
+
"version": "1.1.1",
|
| 1112 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
|
| 1113 |
+
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
|
|
|
|
| 1114 |
"license": "MIT",
|
| 1115 |
+
"dependencies": {
|
| 1116 |
+
"@radix-ui/react-use-layout-effect": "1.1.1"
|
| 1117 |
+
},
|
| 1118 |
+
"peerDependencies": {
|
| 1119 |
+
"@types/react": "*",
|
| 1120 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1121 |
+
},
|
| 1122 |
+
"peerDependenciesMeta": {
|
| 1123 |
+
"@types/react": {
|
| 1124 |
+
"optional": true
|
| 1125 |
+
}
|
| 1126 |
}
|
| 1127 |
},
|
| 1128 |
+
"node_modules/@radix-ui/react-visually-hidden": {
|
| 1129 |
+
"version": "1.2.3",
|
| 1130 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
|
| 1131 |
+
"integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
|
|
|
|
| 1132 |
"license": "MIT",
|
| 1133 |
"dependencies": {
|
| 1134 |
+
"@radix-ui/react-primitive": "2.1.3"
|
|
|
|
| 1135 |
},
|
| 1136 |
+
"peerDependencies": {
|
| 1137 |
+
"@types/react": "*",
|
| 1138 |
+
"@types/react-dom": "*",
|
| 1139 |
+
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
| 1140 |
+
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
| 1141 |
+
},
|
| 1142 |
+
"peerDependenciesMeta": {
|
| 1143 |
+
"@types/react": {
|
| 1144 |
+
"optional": true
|
| 1145 |
+
},
|
| 1146 |
+
"@types/react-dom": {
|
| 1147 |
+
"optional": true
|
| 1148 |
+
}
|
| 1149 |
}
|
| 1150 |
},
|
| 1151 |
+
"node_modules/@radix-ui/rect": {
|
| 1152 |
+
"version": "1.1.1",
|
| 1153 |
+
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
|
| 1154 |
+
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
| 1155 |
+
"license": "MIT"
|
| 1156 |
+
},
|
| 1157 |
"node_modules/@reduxjs/toolkit": {
|
| 1158 |
"version": "2.11.2",
|
| 1159 |
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz",
|
|
|
|
| 1359 |
"version": "18.3.7",
|
| 1360 |
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
| 1361 |
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
| 1362 |
+
"devOptional": true,
|
| 1363 |
"license": "MIT",
|
| 1364 |
"peerDependencies": {
|
| 1365 |
"@types/react": "^18.0.0"
|
|
|
|
| 1434 |
"dev": true,
|
| 1435 |
"license": "MIT"
|
| 1436 |
},
|
| 1437 |
+
"node_modules/aria-hidden": {
|
| 1438 |
+
"version": "1.2.6",
|
| 1439 |
+
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
|
| 1440 |
+
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
|
| 1441 |
+
"license": "MIT",
|
| 1442 |
+
"dependencies": {
|
| 1443 |
+
"tslib": "^2.0.0"
|
| 1444 |
+
},
|
| 1445 |
+
"engines": {
|
| 1446 |
+
"node": ">=10"
|
| 1447 |
+
}
|
| 1448 |
+
},
|
| 1449 |
"node_modules/autoprefixer": {
|
| 1450 |
"version": "10.5.0",
|
| 1451 |
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz",
|
|
|
|
| 1695 |
"node": ">= 6"
|
| 1696 |
}
|
| 1697 |
},
|
| 1698 |
+
"node_modules/class-variance-authority": {
|
| 1699 |
+
"version": "0.7.1",
|
| 1700 |
+
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
|
| 1701 |
+
"integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
|
| 1702 |
+
"license": "Apache-2.0",
|
| 1703 |
+
"dependencies": {
|
| 1704 |
+
"clsx": "^2.1.1"
|
| 1705 |
+
},
|
| 1706 |
+
"funding": {
|
| 1707 |
+
"url": "https://polar.sh/cva"
|
| 1708 |
+
}
|
| 1709 |
+
},
|
| 1710 |
"node_modules/client-only": {
|
| 1711 |
"version": "0.0.1",
|
| 1712 |
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
|
|
|
| 1937 |
"node": ">=6"
|
| 1938 |
}
|
| 1939 |
},
|
| 1940 |
+
"node_modules/detect-node-es": {
|
| 1941 |
+
"version": "1.1.0",
|
| 1942 |
+
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
|
| 1943 |
+
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
|
| 1944 |
+
"license": "MIT"
|
| 1945 |
+
},
|
| 1946 |
"node_modules/devlop": {
|
| 1947 |
"version": "1.1.0",
|
| 1948 |
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
|
|
|
|
| 2199 |
"url": "https://github.com/sponsors/ljharb"
|
| 2200 |
}
|
| 2201 |
},
|
| 2202 |
+
"node_modules/get-nonce": {
|
| 2203 |
+
"version": "1.0.1",
|
| 2204 |
+
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
|
| 2205 |
+
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
|
| 2206 |
+
"license": "MIT",
|
| 2207 |
+
"engines": {
|
| 2208 |
+
"node": ">=6"
|
| 2209 |
+
}
|
| 2210 |
+
},
|
| 2211 |
"node_modules/glob-parent": {
|
| 2212 |
"version": "6.0.2",
|
| 2213 |
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
|
|
|
|
| 4090 |
}
|
| 4091 |
}
|
| 4092 |
},
|
| 4093 |
+
"node_modules/react-remove-scroll": {
|
| 4094 |
+
"version": "2.7.2",
|
| 4095 |
+
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
|
| 4096 |
+
"integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
|
| 4097 |
+
"license": "MIT",
|
| 4098 |
+
"dependencies": {
|
| 4099 |
+
"react-remove-scroll-bar": "^2.3.7",
|
| 4100 |
+
"react-style-singleton": "^2.2.3",
|
| 4101 |
+
"tslib": "^2.1.0",
|
| 4102 |
+
"use-callback-ref": "^1.3.3",
|
| 4103 |
+
"use-sidecar": "^1.1.3"
|
| 4104 |
+
},
|
| 4105 |
+
"engines": {
|
| 4106 |
+
"node": ">=10"
|
| 4107 |
+
},
|
| 4108 |
+
"peerDependencies": {
|
| 4109 |
+
"@types/react": "*",
|
| 4110 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
| 4111 |
+
},
|
| 4112 |
+
"peerDependenciesMeta": {
|
| 4113 |
+
"@types/react": {
|
| 4114 |
+
"optional": true
|
| 4115 |
+
}
|
| 4116 |
+
}
|
| 4117 |
+
},
|
| 4118 |
+
"node_modules/react-remove-scroll-bar": {
|
| 4119 |
+
"version": "2.3.8",
|
| 4120 |
+
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
|
| 4121 |
+
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
|
| 4122 |
+
"license": "MIT",
|
| 4123 |
+
"dependencies": {
|
| 4124 |
+
"react-style-singleton": "^2.2.2",
|
| 4125 |
+
"tslib": "^2.0.0"
|
| 4126 |
+
},
|
| 4127 |
+
"engines": {
|
| 4128 |
+
"node": ">=10"
|
| 4129 |
+
},
|
| 4130 |
+
"peerDependencies": {
|
| 4131 |
+
"@types/react": "*",
|
| 4132 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
| 4133 |
+
},
|
| 4134 |
+
"peerDependenciesMeta": {
|
| 4135 |
+
"@types/react": {
|
| 4136 |
+
"optional": true
|
| 4137 |
+
}
|
| 4138 |
+
}
|
| 4139 |
+
},
|
| 4140 |
+
"node_modules/react-style-singleton": {
|
| 4141 |
+
"version": "2.2.3",
|
| 4142 |
+
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
|
| 4143 |
+
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
|
| 4144 |
+
"license": "MIT",
|
| 4145 |
+
"dependencies": {
|
| 4146 |
+
"get-nonce": "^1.0.0",
|
| 4147 |
+
"tslib": "^2.0.0"
|
| 4148 |
+
},
|
| 4149 |
+
"engines": {
|
| 4150 |
+
"node": ">=10"
|
| 4151 |
+
},
|
| 4152 |
+
"peerDependencies": {
|
| 4153 |
+
"@types/react": "*",
|
| 4154 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
| 4155 |
+
},
|
| 4156 |
+
"peerDependenciesMeta": {
|
| 4157 |
+
"@types/react": {
|
| 4158 |
+
"optional": true
|
| 4159 |
+
}
|
| 4160 |
+
}
|
| 4161 |
+
},
|
| 4162 |
"node_modules/react-syntax-highlighter": {
|
| 4163 |
"version": "15.6.6",
|
| 4164 |
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.6.tgz",
|
|
|
|
| 4963 |
"browserslist": ">= 4.21.0"
|
| 4964 |
}
|
| 4965 |
},
|
| 4966 |
+
"node_modules/use-callback-ref": {
|
| 4967 |
+
"version": "1.3.3",
|
| 4968 |
+
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
|
| 4969 |
+
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
|
| 4970 |
+
"license": "MIT",
|
| 4971 |
+
"dependencies": {
|
| 4972 |
+
"tslib": "^2.0.0"
|
| 4973 |
+
},
|
| 4974 |
+
"engines": {
|
| 4975 |
+
"node": ">=10"
|
| 4976 |
+
},
|
| 4977 |
+
"peerDependencies": {
|
| 4978 |
+
"@types/react": "*",
|
| 4979 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
| 4980 |
+
},
|
| 4981 |
+
"peerDependenciesMeta": {
|
| 4982 |
+
"@types/react": {
|
| 4983 |
+
"optional": true
|
| 4984 |
+
}
|
| 4985 |
+
}
|
| 4986 |
+
},
|
| 4987 |
+
"node_modules/use-sidecar": {
|
| 4988 |
+
"version": "1.1.3",
|
| 4989 |
+
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
|
| 4990 |
+
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
|
| 4991 |
+
"license": "MIT",
|
| 4992 |
+
"dependencies": {
|
| 4993 |
+
"detect-node-es": "^1.1.0",
|
| 4994 |
+
"tslib": "^2.0.0"
|
| 4995 |
+
},
|
| 4996 |
+
"engines": {
|
| 4997 |
+
"node": ">=10"
|
| 4998 |
+
},
|
| 4999 |
+
"peerDependencies": {
|
| 5000 |
+
"@types/react": "*",
|
| 5001 |
+
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
|
| 5002 |
+
},
|
| 5003 |
+
"peerDependenciesMeta": {
|
| 5004 |
+
"@types/react": {
|
| 5005 |
+
"optional": true
|
| 5006 |
+
}
|
| 5007 |
+
}
|
| 5008 |
+
},
|
| 5009 |
"node_modules/use-sync-external-store": {
|
| 5010 |
"version": "1.6.0",
|
| 5011 |
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
frontend/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
-
"name": "god-
|
| 3 |
-
"version": "
|
| 4 |
"private": true,
|
| 5 |
"scripts": {
|
| 6 |
"dev": "next dev -p 3000",
|
|
@@ -9,6 +9,13 @@
|
|
| 9 |
"lint": "next lint"
|
| 10 |
},
|
| 11 |
"dependencies": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
"clsx": "^2.1.1",
|
| 13 |
"date-fns": "^3.6.0",
|
| 14 |
"framer-motion": "^11.1.9",
|
|
|
|
| 1 |
{
|
| 2 |
+
"name": "god-agent-os-ui",
|
| 3 |
+
"version": "8.0.0",
|
| 4 |
"private": true,
|
| 5 |
"scripts": {
|
| 6 |
"dev": "next dev -p 3000",
|
|
|
|
| 9 |
"lint": "next lint"
|
| 10 |
},
|
| 11 |
"dependencies": {
|
| 12 |
+
"@radix-ui/react-dialog": "^1.1.15",
|
| 13 |
+
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
| 14 |
+
"@radix-ui/react-progress": "^1.1.8",
|
| 15 |
+
"@radix-ui/react-separator": "^1.1.8",
|
| 16 |
+
"@radix-ui/react-slot": "^1.2.4",
|
| 17 |
+
"@radix-ui/react-tooltip": "^1.2.8",
|
| 18 |
+
"class-variance-authority": "^0.7.1",
|
| 19 |
"clsx": "^2.1.1",
|
| 20 |
"date-fns": "^3.6.0",
|
| 21 |
"framer-motion": "^11.1.9",
|
frontend/store/useAppStore.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { create } from 'zustand'
|
| 2 |
+
import { persist } from 'zustand/middleware'
|
| 3 |
+
|
| 4 |
+
export type NavPage = 'dashboard' | 'agents' | 'tasks' | 'memory' | 'knowledge' | 'workflows' | 'analytics' | 'settings'
|
| 5 |
+
|
| 6 |
+
export interface Agent {
|
| 7 |
+
id: string
|
| 8 |
+
name: string
|
| 9 |
+
role: string
|
| 10 |
+
status: 'active' | 'idle' | 'processing' | 'error'
|
| 11 |
+
color: string
|
| 12 |
+
icon: string
|
| 13 |
+
tasks: number
|
| 14 |
+
efficiency: number
|
| 15 |
+
uptime: number
|
| 16 |
+
lastAction: string
|
| 17 |
+
lastActionTime: string
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
export interface Task {
|
| 21 |
+
id: string
|
| 22 |
+
title: string
|
| 23 |
+
status: 'running' | 'completed' | 'pending' | 'failed'
|
| 24 |
+
agent: string
|
| 25 |
+
progress: number
|
| 26 |
+
createdAt: string
|
| 27 |
+
completedAt?: string
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
export interface ActivityItem {
|
| 31 |
+
id: string
|
| 32 |
+
agent: string
|
| 33 |
+
action: string
|
| 34 |
+
time: string
|
| 35 |
+
type: 'success' | 'processing' | 'info' | 'warning'
|
| 36 |
+
color: string
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
interface AppState {
|
| 40 |
+
// Navigation
|
| 41 |
+
currentPage: NavPage
|
| 42 |
+
sidebarCollapsed: boolean
|
| 43 |
+
commandPaletteOpen: boolean
|
| 44 |
+
godModeActive: boolean
|
| 45 |
+
|
| 46 |
+
// Data
|
| 47 |
+
agents: Agent[]
|
| 48 |
+
tasks: Task[]
|
| 49 |
+
activity: ActivityItem[]
|
| 50 |
+
metrics: {
|
| 51 |
+
totalAgents: number
|
| 52 |
+
tasksCompleted: number
|
| 53 |
+
timeSaved: number
|
| 54 |
+
successRate: number
|
| 55 |
+
}
|
| 56 |
+
systemResources: {
|
| 57 |
+
cpu: number
|
| 58 |
+
memory: number
|
| 59 |
+
storage: number
|
| 60 |
+
network: number
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
// Actions
|
| 64 |
+
setCurrentPage: (page: NavPage) => void
|
| 65 |
+
toggleSidebar: () => void
|
| 66 |
+
setCommandPaletteOpen: (open: boolean) => void
|
| 67 |
+
toggleGodMode: () => void
|
| 68 |
+
updateSystemResources: (resources: Partial<AppState['systemResources']>) => void
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
export const AGENTS: Agent[] = [
|
| 72 |
+
{ id: '1', name: 'Research Agent', role: 'Web Intelligence', status: 'active', color: '#6366f1', icon: '🔬', tasks: 47, efficiency: 92, uptime: 99.8, lastAction: 'Completed market research analysis', lastActionTime: '2m ago' },
|
| 73 |
+
{ id: '2', name: 'Data Agent', role: 'Data Processing', status: 'active', color: '#22d3ee', icon: '📊', tasks: 83, efficiency: 98, uptime: 99.5, lastAction: 'Processed 1.2M data points', lastActionTime: '12m ago' },
|
| 74 |
+
{ id: '3', name: 'Content Agent', role: 'Content Generation', status: 'active', color: '#a78bfa', icon: '✍️', tasks: 31, efficiency: 95, uptime: 98.2, lastAction: 'Generated blog draft', lastActionTime: '25m ago' },
|
| 75 |
+
{ id: '4', name: 'Code Agent', role: 'Software Development', status: 'active', color: '#34d399', icon: '💻', tasks: 62, efficiency: 99, uptime: 99.9, lastAction: 'Deployed production API', lastActionTime: '1h ago' },
|
| 76 |
+
{ id: '5', name: 'Design Agent', role: 'UI/UX Design', status: 'active', color: '#f472b6', icon: '🎨', tasks: 24, efficiency: 90, uptime: 97.8, lastAction: 'Created UI/UX mockups', lastActionTime: '2h ago' },
|
| 77 |
+
{ id: '6', name: 'Workflow Agent', role: 'Automation', status: 'processing', color: '#fb923c', icon: '⚙️', tasks: 19, efficiency: 93, uptime: 98.1, lastAction: 'Running automation pipeline', lastActionTime: 'now' },
|
| 78 |
+
{ id: '7', name: 'Memory Agent', role: 'Knowledge Storage', status: 'idle', color: '#fbbf24', icon: '🧠', tasks: 156, efficiency: 97, uptime: 99.9, lastAction: 'Indexed 4,200 documents', lastActionTime: '3h ago' },
|
| 79 |
+
{ id: '8', name: 'Deploy Agent', role: 'Cloud Deployment', status: 'idle', color: '#f87171', icon: '🚀', tasks: 12, efficiency: 100, uptime: 99.7, lastAction: 'Deployed to Vercel', lastActionTime: '5h ago' },
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
export const ACTIVITY: ActivityItem[] = [
|
| 83 |
+
{ id: '1', agent: 'Research Agent', action: 'Completed market research analysis', time: '2m ago', type: 'success', color: '#6366f1' },
|
| 84 |
+
{ id: '2', agent: 'Data Agent', action: 'Processed 1.2M data points', time: '12m ago', type: 'processing', color: '#22d3ee' },
|
| 85 |
+
{ id: '3', agent: 'Content Agent', action: 'Generated blog draft', time: '25m ago', type: 'success', color: '#a78bfa' },
|
| 86 |
+
{ id: '4', agent: 'Code Agent', action: 'Deployed production API', time: '1h ago', type: 'success', color: '#34d399' },
|
| 87 |
+
{ id: '5', agent: 'Design Agent', action: 'Created UI/UX mockups', time: '2h ago', type: 'info', color: '#f472b6' },
|
| 88 |
+
{ id: '6', agent: 'Workflow Agent', action: 'Initiated automation pipeline', time: '3h ago', type: 'processing', color: '#fb923c' },
|
| 89 |
+
]
|
| 90 |
+
|
| 91 |
+
export const TASKS: Task[] = [
|
| 92 |
+
{ id: 't1', title: 'Analyze competitor pricing strategy', status: 'completed', agent: 'Research Agent', progress: 100, createdAt: '2h ago', completedAt: '2m ago' },
|
| 93 |
+
{ id: 't2', title: 'Generate Q4 performance report', status: 'running', agent: 'Data Agent', progress: 67, createdAt: '30m ago' },
|
| 94 |
+
{ id: 't3', title: 'Refactor authentication module', status: 'running', agent: 'Code Agent', progress: 45, createdAt: '1h ago' },
|
| 95 |
+
{ id: 't4', title: 'Create landing page copy', status: 'pending', agent: 'Content Agent', progress: 0, createdAt: '5m ago' },
|
| 96 |
+
{ id: 't5', title: 'Design system components v2', status: 'pending', agent: 'Design Agent', progress: 0, createdAt: '10m ago' },
|
| 97 |
+
{ id: 't6', title: 'Set up CI/CD pipeline', status: 'completed', agent: 'Deploy Agent', progress: 100, createdAt: '5h ago', completedAt: '4h ago' },
|
| 98 |
+
]
|
| 99 |
+
|
| 100 |
+
export const useAppStore = create<AppState>()(
|
| 101 |
+
persist(
|
| 102 |
+
(set) => ({
|
| 103 |
+
currentPage: 'dashboard',
|
| 104 |
+
sidebarCollapsed: false,
|
| 105 |
+
commandPaletteOpen: false,
|
| 106 |
+
godModeActive: true,
|
| 107 |
+
agents: AGENTS,
|
| 108 |
+
tasks: TASKS,
|
| 109 |
+
activity: ACTIVITY,
|
| 110 |
+
metrics: {
|
| 111 |
+
totalAgents: 12,
|
| 112 |
+
tasksCompleted: 247,
|
| 113 |
+
timeSaved: 128,
|
| 114 |
+
successRate: 98.6,
|
| 115 |
+
},
|
| 116 |
+
systemResources: {
|
| 117 |
+
cpu: 32,
|
| 118 |
+
memory: 68,
|
| 119 |
+
storage: 54,
|
| 120 |
+
network: 29,
|
| 121 |
+
},
|
| 122 |
+
setCurrentPage: (page) => set({ currentPage: page }),
|
| 123 |
+
toggleSidebar: () => set((state) => ({ sidebarCollapsed: !state.sidebarCollapsed })),
|
| 124 |
+
setCommandPaletteOpen: (open) => set({ commandPaletteOpen: open }),
|
| 125 |
+
toggleGodMode: () => set((state) => ({ godModeActive: !state.godModeActive })),
|
| 126 |
+
updateSystemResources: (resources) =>
|
| 127 |
+
set((state) => ({ systemResources: { ...state.systemResources, ...resources } })),
|
| 128 |
+
}),
|
| 129 |
+
{ name: 'god-agent-os-store', partialize: (s) => ({ sidebarCollapsed: s.sidebarCollapsed, godModeActive: s.godModeActive }) }
|
| 130 |
+
)
|
| 131 |
+
)
|
frontend/tailwind.config.js
CHANGED
|
@@ -5,85 +5,68 @@ module.exports = {
|
|
| 5 |
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
| 6 |
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
| 7 |
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
|
|
|
| 8 |
],
|
| 9 |
theme: {
|
| 10 |
extend: {
|
| 11 |
colors: {
|
| 12 |
-
|
| 13 |
-
50: '#eef2ff',
|
| 14 |
-
100: '#e0e7ff',
|
| 15 |
-
200: '#c7d2fe',
|
| 16 |
-
300: '#a5b4fc',
|
| 17 |
-
400: '#818cf8',
|
| 18 |
-
500: '#6366f1',
|
| 19 |
-
600: '#4f46e5',
|
| 20 |
-
700: '#4338ca',
|
| 21 |
-
800: '#3730a3',
|
| 22 |
-
900: '#312e81',
|
| 23 |
-
},
|
| 24 |
surface: {
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
5: '#252640',
|
| 31 |
-
border: '#2a2b3d',
|
| 32 |
-
hover: '#2e2f4a',
|
| 33 |
-
},
|
| 34 |
-
agent: {
|
| 35 |
-
chat: '#22d3ee',
|
| 36 |
-
planner: '#a78bfa',
|
| 37 |
-
coding: '#34d399',
|
| 38 |
-
debug: '#f87171',
|
| 39 |
-
memory: '#fbbf24',
|
| 40 |
-
connector: '#60a5fa',
|
| 41 |
-
deploy: '#f472b6',
|
| 42 |
-
workflow: '#fb923c',
|
| 43 |
-
sandbox: '#4ade80',
|
| 44 |
-
ui: '#e879f9',
|
| 45 |
},
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
},
|
| 53 |
fontFamily: {
|
| 54 |
-
mono: ['JetBrains Mono', 'Fira Code', 'Cascadia Code', 'monospace'],
|
| 55 |
sans: ['Inter', 'system-ui', 'sans-serif'],
|
| 56 |
-
|
| 57 |
},
|
| 58 |
-
|
| 59 |
-
'
|
| 60 |
-
'
|
| 61 |
-
'
|
| 62 |
-
'slide-up': 'slideUp 0.3s ease-out',
|
| 63 |
-
'slide-right': 'slideRight 0.25s ease-out',
|
| 64 |
-
'glow': 'glow 2s ease-in-out infinite',
|
| 65 |
-
'shimmer': 'shimmer 2s linear infinite',
|
| 66 |
-
'spin-slow': 'spin 3s linear infinite',
|
| 67 |
-
'bounce-dot': 'bounceDot 1.4s ease-in-out infinite',
|
| 68 |
},
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
glow
|
| 75 |
-
|
| 76 |
-
|
| 77 |
},
|
| 78 |
-
|
| 79 |
-
'
|
| 80 |
-
'
|
| 81 |
-
'
|
| 82 |
-
'
|
| 83 |
-
'
|
|
|
|
|
|
|
|
|
|
| 84 |
},
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
},
|
| 88 |
},
|
| 89 |
},
|
|
|
|
| 5 |
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
|
| 6 |
'./components/**/*.{js,ts,jsx,tsx,mdx}',
|
| 7 |
'./app/**/*.{js,ts,jsx,tsx,mdx}',
|
| 8 |
+
'./store/**/*.{js,ts,jsx,tsx}',
|
| 9 |
],
|
| 10 |
theme: {
|
| 11 |
extend: {
|
| 12 |
colors: {
|
| 13 |
+
void: '#05060d',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
surface: {
|
| 15 |
+
1: '#0a0c16',
|
| 16 |
+
2: '#0e1121',
|
| 17 |
+
3: '#131729',
|
| 18 |
+
4: '#191e32',
|
| 19 |
+
5: '#1f263b',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
},
|
| 21 |
+
purple: {
|
| 22 |
+
DEFAULT: '#7c3aed',
|
| 23 |
+
bright: '#8b5cf6',
|
| 24 |
+
light: '#a78bfa',
|
| 25 |
+
dim: 'rgba(124,58,237,0.15)',
|
| 26 |
},
|
| 27 |
+
blue: { DEFAULT: '#3b82f6', bright: '#60a5fa' },
|
| 28 |
+
cyan: { DEFAULT: '#22d3ee', bright: '#67e8f9' },
|
| 29 |
+
green: { DEFAULT: '#22c55e', bright: '#4ade80' },
|
| 30 |
+
amber: { DEFAULT: '#f59e0b', bright: '#fbbf24' },
|
| 31 |
+
pink: { DEFAULT: '#ec4899', bright: '#f472b6' },
|
| 32 |
+
neon: { purple: '#bf00ff', blue: '#00d4ff', green: '#00ff88' },
|
| 33 |
},
|
| 34 |
fontFamily: {
|
|
|
|
| 35 |
sans: ['Inter', 'system-ui', 'sans-serif'],
|
| 36 |
+
mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
|
| 37 |
},
|
| 38 |
+
borderRadius: {
|
| 39 |
+
'2xl': '16px',
|
| 40 |
+
'3xl': '20px',
|
| 41 |
+
'4xl': '24px',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
},
|
| 43 |
+
backdropBlur: { xs: '2px', sm: '8px', md: '16px', lg: '24px', xl: '40px' },
|
| 44 |
+
boxShadow: {
|
| 45 |
+
'glow-purple': '0 0 20px rgba(124,58,237,0.3), 0 0 60px rgba(124,58,237,0.1)',
|
| 46 |
+
'glow-blue': '0 0 20px rgba(59,130,246,0.3)',
|
| 47 |
+
'glow-cyan': '0 0 20px rgba(34,211,238,0.3)',
|
| 48 |
+
'glow-green': '0 0 12px rgba(34,197,94,0.4)',
|
| 49 |
+
'card': '0 4px 24px rgba(0,0,0,0.3)',
|
| 50 |
+
'card-hover': '0 8px 40px rgba(0,0,0,0.4)',
|
| 51 |
},
|
| 52 |
+
animation: {
|
| 53 |
+
'fade-in-up': 'fadeInUp 0.4s ease-out forwards',
|
| 54 |
+
'fade-in': 'fadeIn 0.3s ease-out forwards',
|
| 55 |
+
'slide-left': 'slideInLeft 0.3s ease-out forwards',
|
| 56 |
+
'pulse-glow': 'pulseGlow 2s ease-in-out infinite',
|
| 57 |
+
'spin-slow': 'spin 8s linear infinite',
|
| 58 |
+
'orb-float': 'orbFloat 6s ease-in-out infinite',
|
| 59 |
+
'shimmer': 'shimmer 3s linear infinite',
|
| 60 |
+
'typing-dot': 'typingDot 1.4s ease-in-out infinite',
|
| 61 |
},
|
| 62 |
+
keyframes: {
|
| 63 |
+
fadeInUp: { from: { opacity: '0', transform: 'translateY(12px)' }, to: { opacity: '1', transform: 'translateY(0)' } },
|
| 64 |
+
fadeIn: { from: { opacity: '0' }, to: { opacity: '1' } },
|
| 65 |
+
slideInLeft: { from: { opacity: '0', transform: 'translateX(-16px)' }, to: { opacity: '1', transform: 'translateX(0)' } },
|
| 66 |
+
pulseGlow: { '0%,100%': { opacity: '0.6' }, '50%': { opacity: '1' } },
|
| 67 |
+
orbFloat: { '0%,100%': { transform: 'translateY(0px) rotate(0deg)' }, '33%': { transform: 'translateY(-8px) rotate(5deg)' }, '66%': { transform: 'translateY(4px) rotate(-3deg)' } },
|
| 68 |
+
shimmer: { '0%': { backgroundPosition: '-200% center' }, '100%': { backgroundPosition: '200% center' } },
|
| 69 |
+
typingDot: { '0%,80%,100%': { transform: 'scale(0)', opacity: '0.3' }, '40%': { transform: 'scale(1)', opacity: '1' } },
|
| 70 |
},
|
| 71 |
},
|
| 72 |
},
|
frontend/vercel.json
CHANGED
|
@@ -4,14 +4,16 @@
|
|
| 4 |
"installCommand": "npm install",
|
| 5 |
"framework": "nextjs",
|
| 6 |
"env": {
|
| 7 |
-
"NEXT_PUBLIC_API_URL": "https://PYAE1994-autonomous-coding-system.hf.space"
|
|
|
|
|
|
|
| 8 |
},
|
| 9 |
"headers": [
|
| 10 |
{
|
| 11 |
"source": "/(.*)",
|
| 12 |
"headers": [
|
| 13 |
{ "key": "X-Content-Type-Options", "value": "nosniff" },
|
| 14 |
-
{ "key": "X-Frame-Options", "value": "
|
| 15 |
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
|
| 16 |
]
|
| 17 |
}
|
|
|
|
| 4 |
"installCommand": "npm install",
|
| 5 |
"framework": "nextjs",
|
| 6 |
"env": {
|
| 7 |
+
"NEXT_PUBLIC_API_URL": "https://PYAE1994-autonomous-coding-system.hf.space",
|
| 8 |
+
"NEXT_PUBLIC_APP_VERSION": "8.0.0",
|
| 9 |
+
"NEXT_PUBLIC_APP_NAME": "GOD AGENT OS"
|
| 10 |
},
|
| 11 |
"headers": [
|
| 12 |
{
|
| 13 |
"source": "/(.*)",
|
| 14 |
"headers": [
|
| 15 |
{ "key": "X-Content-Type-Options", "value": "nosniff" },
|
| 16 |
+
{ "key": "X-Frame-Options", "value": "SAMEORIGIN" },
|
| 17 |
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" }
|
| 18 |
]
|
| 19 |
}
|