From 604b4b7db4405ed966ed8cf89e5901c58ae04714 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 16 Feb 2026 12:21:12 +0000 Subject: [PATCH] feat: New MC with left sidebar + Horus AI Management --- components/ai-management/AIManagement.tsx | 183 ++++++++ .../MissionControlDashboard.tsx | 423 ++++++++++-------- lib/ai-management/types.ts | 66 +++ 3 files changed, 481 insertions(+), 191 deletions(-) create mode 100644 components/ai-management/AIManagement.tsx create mode 100644 lib/ai-management/types.ts diff --git a/components/ai-management/AIManagement.tsx b/components/ai-management/AIManagement.tsx new file mode 100644 index 0000000..a7cf517 --- /dev/null +++ b/components/ai-management/AIManagement.tsx @@ -0,0 +1,183 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { AISkill, ApiConfig, CronJob, defaultSkills, defaultApis, defaultCronJobs } from "@/lib/ai-management/types"; + +const STORAGE_KEYS = { + skills: "horus:skills", + apis: "horus:apis", + crons: "horus:crons", +}; + +export default function AIManagement() { + const [skills, setSkills] = useState(defaultSkills); + const [apis, setApis] = useState(defaultApis); + const [crons, setCrons] = useState(defaultCronJobs); + const [activeTab, setActiveTab] = useState<"skills" | "apis" | "crons">("skills"); + + // Load from localStorage + useEffect(() => { + if (typeof window === "undefined") return; + + const savedSkills = localStorage.getItem(STORAGE_KEYS.skills); + if (savedSkills) setSkills(JSON.parse(savedSkills)); + + const savedApis = localStorage.getItem(STORAGE_KEYS.apis); + if (savedApis) setApis(JSON.parse(savedApis)); + + const savedCrons = localStorage.getItem(STORAGE_KEYS.crons); + if (savedCrons) setCrons(JSON.parse(savedCrons)); + }, []); + + // Save changes + const toggleSkill = (id: string) => { + const updated = skills.map(s => s.id === id ? { ...s, enabled: !s.enabled } : s); + setSkills(updated); + localStorage.setItem(STORAGE_KEYS.skills, JSON.stringify(updated)); + }; + + const toggleCron = (id: string) => { + const updated = crons.map(c => c.id === id ? { ...c, enabled: !c.enabled } : c); + setCrons(updated); + localStorage.setItem(STORAGE_KEYS.crons, JSON.stringify(updated)); + }; + + const categoryColors: Record = { + development: "bg-blue-500/20 text-blue-400", + research: "bg-purple-500/20 text-purple-400", + automation: "bg-green-500/20 text-green-400", + communication: "bg-yellow-500/20 text-yellow-400", + }; + + return ( +
+ {/* Header */} +
+

🤖 Horus AI Management

+

Configure skills, APIs, and automation for your AI assistant

+
+ + {/* Tabs */} +
+ {[ + { id: "skills", label: "Skills", icon: "🧩" }, + { id: "apis", label: "APIs", icon: "🔑" }, + { id: "crons", label: "Automation", icon: "⏰" }, + ].map((tab) => ( + + ))} +
+ + {/* Skills Tab */} + {activeTab === "skills" && ( +
+ {skills.map((skill) => ( +
+
+
+ {skill.category} +
+
+

{skill.name}

+

{skill.description}

+
+
+ +
+ ))} +
+ )} + + {/* APIs Tab */} + {activeTab === "apis" && ( +
+ {apis.map((api) => ( +
+
+

+ {api.name} + {api.configured && ✓ Configured} +

+

{api.description}

+
+ +
+ ))} + +
+

+ 💡 To configure APIs, give me the keys or run: openclaw configure --section auth --set KEY=value +

+
+
+ )} + + {/* Automation/Crons Tab */} + {activeTab === "crons" && ( +
+ {crons.map((cron) => ( +
+
+

{cron.name}

+

+ {cron.schedule} + {cron.nextRun && Next: {cron.nextRun}} +

+
+ +
+ ))} +
+ )} +
+ ); +} diff --git a/components/mission-control/MissionControlDashboard.tsx b/components/mission-control/MissionControlDashboard.tsx index 34ac74e..ef6026b 100644 --- a/components/mission-control/MissionControlDashboard.tsx +++ b/components/mission-control/MissionControlDashboard.tsx @@ -4,6 +4,7 @@ import { useState } from "react"; import { useMissionControl } from "@/lib/mission-control/store"; import { TaskStatus } from "@/lib/mission-control/types"; import VoiceChat from "./VoiceChat"; +import AIManagement from "@/components/ai-management/AIManagement"; interface ProjectSummary { id: string; @@ -11,6 +12,7 @@ interface ProjectSummary { description: string; status: "active" | "paused" | "completed"; color: string; + icon: string; } const projects: ProjectSummary[] = [ @@ -20,6 +22,7 @@ const projects: ProjectSummary[] = [ description: "AI website platform for local businesses (B2B)", status: "active", color: "#ff7bc0", + icon: "🌐", }, { id: "holacompi", @@ -27,6 +30,7 @@ const projects: ProjectSummary[] = [ description: "AI ally for immigrants/consumers (B2C)", status: "paused", color: "#6366f1", + icon: "🤝", }, { id: "infrastructure", @@ -34,22 +38,35 @@ const projects: ProjectSummary[] = [ description: "Security, backups, APIs, and system config", status: "active", color: "#10b981", + icon: "🔒", + }, + { + id: "horus", + name: "Horus AI", + description: "Manage my skills, APIs, and automation", + status: "active", + color: "#f59e0b", + icon: "🤖", }, ]; -const statusConfig: Record = { - todo: { label: "To Do", color: "text-white/70", bg: "bg-white/10" }, - in_progress: { label: "In Progress", color: "text-yellow-400", bg: "bg-yellow-500/20" }, - done: { label: "Done", color: "text-green-400", bg: "bg-green-500/20" }, - blocked: { label: "Blocked", color: "text-red-400", bg: "bg-red-500/20" }, - paused: { label: "Paused", color: "text-gray-400", bg: "bg-gray-500/20" }, +const statusConfig: Record = { + todo: { label: "To Do", color: "text-white/70" }, + in_progress: { label: "In Progress", color: "text-yellow-400" }, + done: { label: "Done", color: "text-green-400" }, + blocked: { label: "Blocked", color: "text-red-400" }, + paused: { label: "Paused", color: "text-gray-400" }, }; +type ViewType = "tasks" | "horus"; + export default function MissionControlDashboard() { const { tasks, toggleTask, updateTaskStatus, getProjectProgress, getTasksByProject } = useMissionControl(); + const [selectedProject, setSelectedProject] = useState("sitemente"); const [filter, setFilter] = useState("all"); + const [view, setView] = useState("tasks"); const projectTasks = getTasksByProject(selectedProject as any); const filteredTasks = filter === "all" ? projectTasks : projectTasks.filter((t) => t.status === filter); @@ -57,6 +74,45 @@ export default function MissionControlDashboard() { const selectedProjectData = projects.find((p) => p.id === selectedProject)!; + // If viewing Horus AI management + if (view === "horus") { + return ( +
+ {/* Header */} +
+
+
+
+ 👁️ +
+
+

Mission Control

+

Horus AI Management

+
+
+ +
+
+ +
+ + + {/* Voice Chat */} +
+ +
+
+
+ ); + } + return (
{/* Header */} @@ -68,223 +124,208 @@ export default function MissionControlDashboard() {

Mission Control

-

SiteMente + HolaCompi

+

SiteMente + HolaCompi + Infrastructure

- {/* Navigation */} -

Total Progress

{progress}%

- - + +
-
- {/* Project Tabs */} -
- {projects.map((project) => { - const p = getProjectProgress(project.id as any); - return ( - - ); - })} -
- - {/* Stats Row */} -
- {(["todo", "in_progress", "done", "blocked"] as TaskStatus[]).map((status) => { - const count = projectTasks.filter((t) => t.status === status).length; - const config = statusConfig[status]; - return ( - - ); - })} -
- - {/* Task List */} -
-
-
-

- {selectedProjectData?.name} Tasks -

-

- {filteredTasks.filter((t) => t.status === "done").length} /{" "} - {filteredTasks.length} completed -

-
-
- -
- {filteredTasks.map((task) => { - const config = statusConfig[task.status]; - return ( -
+
+
+ {/* Left Sidebar */} + + + {/* Main Content */} +
+ {/* Project Tabs */} +
+ {projects.filter(p => p.id !== "horus").map((project) => { + const p = getProjectProgress(project.id as any); + return ( + + ); + })} +
+ + {/* Stats Row */} +
+ {(["todo", "in_progress", "done", "blocked"] as TaskStatus[]).map((status) => { + const count = projectTasks.filter((t) => t.status === status).length; + const config = statusConfig[status]; + return ( + + ); + })} +
+ + {/* Task List */} +
+
+
+

{selectedProjectData?.name} Tasks

+

+ {filteredTasks.filter((t) => t.status === "done").length} / {filteredTasks.length} done +

+
+
+ +
+ {filteredTasks.map((task) => { + const config = statusConfig[task.status]; + return ( +
+ + +
+

+ {task.title} +

+
+ {task.priority === "critical" && ( - + CRITICAL )} + +
-

{task.description}

-
+ ); + })} +
- + {filteredTasks.length === 0 && ( +
+ No tasks match the current filter.
- ); - })} -
- - {filteredTasks.length === 0 && ( -
- No tasks match the current filter. + )}
- )} -
- {/* Voice Chat */} -
- + {/* Voice Chat */} +
+ +
+
- - {/* Quick Actions */} -
- -
- + ); } diff --git a/lib/ai-management/types.ts b/lib/ai-management/types.ts new file mode 100644 index 0000000..2212c21 --- /dev/null +++ b/lib/ai-management/types.ts @@ -0,0 +1,66 @@ +// AI Management Types + +export interface AISkill { + id: string; + name: string; + description: string; + enabled: boolean; + category: "communication" | "research" | "development" | "automation"; +} + +export interface AIModel { + id: string; + name: string; + provider: string; + enabled: boolean; + isDefault: boolean; +} + +export interface ApiConfig { + id: string; + name: string; + key: string; + configured: boolean; + description: string; +} + +export interface CronJob { + id: string; + name: string; + schedule: string; + enabled: boolean; + lastRun?: string; + nextRun?: string; +} + +// Current configuration +export const defaultSkills: AISkill[] = [ + { id: "github", name: "GitHub", description: "Manage GitHub issues, PRs, and repos", enabled: true, category: "development" }, + { id: "healthcheck", name: "Health Check", description: "VPS security and hardening", enabled: true, category: "automation" }, + { id: "skill-creator", name: "Skill Creator", description: "Create and manage agent skills", enabled: false, category: "development" }, + { id: "tmux", name: "Tmux", description: "Remote terminal sessions", enabled: true, category: "development" }, + { id: "weather", name: "Weather", description: "Get weather and forecasts", enabled: true, category: "research" }, + { id: "automation-workflows", name: "Automation", description: "Design automation workflows", enabled: false, category: "automation" }, + { id: "docker-sandbox", name: "Docker Sandbox", description: "Safe code execution environment", enabled: false, category: "development" }, +]; + +export const defaultModels: AIModel[] = [ + { id: "minimax", name: "MiniMax M2.5", provider: "minimax", enabled: true, isDefault: true }, + { id: "sonnet", name: "Claude Sonnet 4.5", provider: "anthropic", enabled: true, isDefault: false }, + { id: "gemini-flash", name: "Gemini 3 Flash", provider: "google", enabled: false, isDefault: false }, +]; + +export const defaultApis: ApiConfig[] = [ + { id: "perplexity", name: "Perplexity AI", key: "PERPLEXITY_API_KEY", configured: false, description: "Web research and live information" }, + { id: "openweather", name: "OpenWeatherMap", key: "OPENWEATHER_API_KEY", configured: false, description: "Weather data for morning brief" }, + { id: "newsapi", name: "News API", key: "NEWS_API_KEY", configured: false, description: "AI and market news" }, + { id: "coingecko", name: "CoinGecko", key: "", configured: true, description: "Crypto prices (free, no key needed)" }, + { id: "alphavantage", name: "Alpha Vantage", key: "ALPHA_VANTAGE_API_KEY", configured: false, description: "Stock market data" }, + { id: "things3", name: "Things 3", key: "", configured: false, description: "Todoist as alternative" }, +]; + +export const defaultCronJobs: CronJob[] = [ + { id: "morning-brief", name: "Morning Brief", schedule: "6:00 AM CET", enabled: true, nextRun: "2026-02-17 06:00" }, + { id: "backup", name: "Daily Backup", schedule: "2:00 AM CET", enabled: false }, + { id: "healthcheck", name: "Weekly Security Audit", schedule: "Sunday 3:00 AM", enabled: false }, +];