Compare commits
6 Commits
main
...
4150f57628
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4150f57628 | ||
|
|
9bf9d2327f | ||
|
|
06487f9fbc | ||
|
|
ba8d707532 | ||
|
|
4e2a062b4c | ||
|
|
8efcb73cc1 |
@@ -1,8 +0,0 @@
|
|||||||
FROM node:20-alpine
|
|
||||||
WORKDIR /app
|
|
||||||
ENV HOST=0.0.0.0
|
|
||||||
ENV NODE_ENV=production
|
|
||||||
COPY . .
|
|
||||||
RUN npm install && npm run build
|
|
||||||
EXPOSE 3000
|
|
||||||
CMD ["node", ".next/standalone/server.js"]
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
import { NextResponse } from 'next/server';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
|
|
||||||
const DATA_DIR = '/app/data';
|
|
||||||
|
|
||||||
// Types
|
|
||||||
type CronJob = { name: string; enabled: boolean; status: string };
|
|
||||||
type Task = { id: string; title: string; created: string; priority: string; status: string; assignee: string };
|
|
||||||
type Memory = { id: string; title: string; date: string; preview: string };
|
|
||||||
|
|
||||||
// Helper to read files
|
|
||||||
function readDir(dir: string, pattern: string = '.md'): string[] {
|
|
||||||
if (!fs.existsSync(dir)) return [];
|
|
||||||
return fs.readdirSync(dir).filter(f => f.endsWith(pattern));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function GET(request: Request) {
|
|
||||||
const { searchParams } = new URL(request.url);
|
|
||||||
const type = searchParams.get('type') || 'tasks';
|
|
||||||
|
|
||||||
try {
|
|
||||||
// TASKS
|
|
||||||
if (type === 'tasks') {
|
|
||||||
const tasksDir = path.join(DATA_DIR, 'shared-context/jelena-neo-tasks/archive');
|
|
||||||
const tasks: Task[] = [];
|
|
||||||
|
|
||||||
if (fs.existsSync(tasksDir)) {
|
|
||||||
for (const file of readDir(tasksDir).slice(0, 20)) {
|
|
||||||
const content = fs.readFileSync(path.join(tasksDir, file), 'utf-8');
|
|
||||||
tasks.push({
|
|
||||||
id: file.replace('.md', ''),
|
|
||||||
title: content.match(/^# Task: (.+)$/m)?.[1] || file,
|
|
||||||
created: content.match(/Created: (.+)$/m)?.[1] || '',
|
|
||||||
priority: content.match(/Priority: (.+)$/m)?.[1] || 'normal',
|
|
||||||
status: 'done',
|
|
||||||
assignee: 'neo'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NextResponse.json(tasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRONS - from shared-context
|
|
||||||
if (type === 'crons') {
|
|
||||||
// Try multiple paths for cron jobs
|
|
||||||
const cronPaths = [
|
|
||||||
path.join(DATA_DIR, 'shared-context/.openclaw/cron/jobs.json'),
|
|
||||||
path.join(DATA_DIR, 'workspace-neo/.openclaw/cron/jobs.json'),
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const cronFile of cronPaths) {
|
|
||||||
if (fs.existsSync(cronFile)) {
|
|
||||||
const data = JSON.parse(fs.readFileSync(cronFile, 'utf-8'));
|
|
||||||
const jobs: CronJob[] = (data.jobs || []).map((job: any) => ({
|
|
||||||
name: job.name,
|
|
||||||
enabled: job.enabled,
|
|
||||||
status: job.state?.lastStatus || 'unknown'
|
|
||||||
}));
|
|
||||||
return NextResponse.json(jobs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NextResponse.json([]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MEMORY
|
|
||||||
if (type === 'memory') {
|
|
||||||
const memoryDir = path.join(DATA_DIR, 'memory');
|
|
||||||
const memories: Memory[] = [];
|
|
||||||
|
|
||||||
if (fs.existsSync(memoryDir)) {
|
|
||||||
for (const file of readDir(memoryDir).slice(0, 20)) {
|
|
||||||
const content = fs.readFileSync(path.join(memoryDir, file), 'utf-8');
|
|
||||||
memories.push({
|
|
||||||
id: file.replace('.md', ''),
|
|
||||||
title: content.match(/^# (.+)$/m)?.[1] || file,
|
|
||||||
date: file.substring(0, 10),
|
|
||||||
preview: content.substring(0, 150).replace(/[#*]/g, '')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NextResponse.json(memories);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SERVER STATUS - basic data only
|
|
||||||
if (type === 'server') {
|
|
||||||
return NextResponse.json({
|
|
||||||
status: 'ok',
|
|
||||||
note: 'Full stats coming soon'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// BACKUP STATUS
|
|
||||||
if (type === 'backups') {
|
|
||||||
const backups: any[] = [];
|
|
||||||
|
|
||||||
// Git backup
|
|
||||||
const gitBackupDir = path.join(DATA_DIR, 'workspace-neo/.git');
|
|
||||||
if (fs.existsSync(gitBackupDir)) {
|
|
||||||
const stats = fs.statSync(gitBackupDir);
|
|
||||||
backups.push({ name: 'Git Config', status: 'ok', lastRun: 'Today 10:49' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage backup
|
|
||||||
const storageDir = path.join(DATA_DIR, '../openclaw/jelena/backups/config');
|
|
||||||
if (fs.existsSync(storageDir)) {
|
|
||||||
const files = fs.readdirSync(storageDir);
|
|
||||||
if (files.length > 0) {
|
|
||||||
const latest = files.sort().pop();
|
|
||||||
backups.push({ name: 'Storage Box', status: 'ok', lastRun: latest?.replace('.tar.gz', '') || 'unknown' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json(backups);
|
|
||||||
}
|
|
||||||
|
|
||||||
// AGENT STATUS
|
|
||||||
if (type === 'agents') {
|
|
||||||
return NextResponse.json([
|
|
||||||
{ name: 'Jelena', role: 'Chief of Staff', status: 'online' },
|
|
||||||
{ name: 'Neo', role: 'CTO / DevOps', status: 'online' }
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHATSAPP BACKUP
|
|
||||||
if (type === 'whatsapp') {
|
|
||||||
const waDir = path.join(DATA_DIR, '../openclaw/jelena/whatsapp-chats');
|
|
||||||
if (fs.existsSync(waDir)) {
|
|
||||||
const chats = fs.readdirSync(waDir);
|
|
||||||
return NextResponse.json({
|
|
||||||
status: 'ok',
|
|
||||||
chats: chats.length,
|
|
||||||
lastUpdate: 'Today'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return NextResponse.json({ status: 'not_configured', chats: 0, lastUpdate: 'Never' });
|
|
||||||
}
|
|
||||||
|
|
||||||
return NextResponse.json({ error: 'Unknown type' }, { status: 400 });
|
|
||||||
} catch (e: any) {
|
|
||||||
return NextResponse.json({ error: e.message }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,53 +1,10 @@
|
|||||||
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap');
|
|
||||||
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
html, body {
|
|
||||||
background: #0a0a0f;
|
|
||||||
color: #e4e4e7;
|
|
||||||
font-family: 'JetBrains Mono', 'Fira Code', monospace;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
min-height: 100vh;
|
background: #0f0f23;
|
||||||
}
|
color: white;
|
||||||
|
|
||||||
/* Scrollbar */
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-track {
|
|
||||||
background: rgba(255,255,255,0.02);
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: rgba(255,255,255,0.1);
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: rgba(255,255,255,0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Selection */
|
|
||||||
::selection {
|
|
||||||
background: rgba(255, 0, 80, 0.3);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animations */
|
|
||||||
@keyframes pulse {
|
|
||||||
0%, 100% { opacity: 1; }
|
|
||||||
50% { opacity: 0.5; }
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes glow {
|
|
||||||
0%, 100% { box-shadow: 0 0 20px rgba(255, 0, 80, 0.3); }
|
|
||||||
50% { box-shadow: 0 0 40px rgba(255, 0, 80, 0.5); }
|
|
||||||
}
|
}
|
||||||
|
|||||||
245
app/page.tsx
245
app/page.tsx
@@ -1,36 +1,229 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
export default function Page() {
|
// Mission Control - Next.js App
|
||||||
const [tab, setTab] = useState('tasks');
|
// Track tasks, content, calendar, memory, team, and office
|
||||||
const [data, setData] = useState<any>(null);
|
|
||||||
const [loading, setLoading] = useState(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
// Types
|
||||||
setLoading(true);
|
type TaskStatus = 'todo' | 'in-progress' | 'done';
|
||||||
fetch('/api/data?type=' + tab)
|
type Task = { id: string; title: string; status: TaskStatus; assignee: 'me' | 'jelena' | 'neo' };
|
||||||
.then(r => r.json())
|
|
||||||
.then(d => { setData(d); setLoading(false); })
|
|
||||||
.catch(() => setLoading(false));
|
|
||||||
}, [tab]);
|
|
||||||
|
|
||||||
const tabs = ['tasks','crons','server','backups','agents','whatsapp','memory'];
|
type ContentStage = 'idea' | 'script' | 'thumbnail' | 'filming' | 'done';
|
||||||
|
type ContentItem = { id: string; title: string; stage: ContentStage; script?: string };
|
||||||
|
|
||||||
|
type CalendarEvent = { id: string; title: string; date: string; type: 'cron' | 'scheduled' };
|
||||||
|
|
||||||
|
type Memory = { id: string; title: string; date: string; preview: string };
|
||||||
|
|
||||||
|
type TeamMember = { id: string; name: string; role: string; status: 'working' | 'idle' };
|
||||||
|
|
||||||
|
export default function MissionControl() {
|
||||||
|
const [activeTab, setActiveTab] = useState('tasks');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{background:'#000',minHeight:'100vh',color:'#fff',fontFamily:'monospace',padding:'20px'}}>
|
<div style={{ fontFamily: 'system-ui, sans-serif', minHeight: '100vh', background: '#0f0f23', color: 'white' }}>
|
||||||
<h1 style={{fontSize:'20px',marginBottom:'15px'}}>MISSION CONTROL</h1>
|
<header style={{ padding: '20px 40px', borderBottom: '1px solid #1e1e3f', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
<div style={{display:'flex',gap:'5px',flexWrap:'wrap',marginBottom:'15px'}}>
|
<h1 style={{ fontSize: '1.8rem', fontWeight: 700 }}>🎯 Mission Control</h1>
|
||||||
{tabs.map(t => (
|
<nav style={{ display: 'flex', gap: '10px' }}>
|
||||||
<button key={t} onClick={()=>setTab(t)} style={{
|
{['tasks', 'content', 'calendar', 'memory', 'team', 'office'].map(tab => (
|
||||||
padding:'8px 12px',background:tab===t?'#f0f': '#333',
|
<button
|
||||||
color:'#fff',border:'none',borderRadius:'4px',fontSize:'12px'
|
key={tab}
|
||||||
}}>{t}</button>
|
onClick={() => setActiveTab(tab)}
|
||||||
))}
|
style={{
|
||||||
</div>
|
padding: '10px 20px',
|
||||||
<pre style={{background:'#111',padding:'15px',borderRadius:'8px',overflow:'auto'}}>
|
background: activeTab === tab ? '#e94560' : 'transparent',
|
||||||
{loading ? 'Loading...' : JSON.stringify(data,null,2)}
|
border: 'none',
|
||||||
</pre>
|
borderRadius: '8px',
|
||||||
|
color: 'white',
|
||||||
|
cursor: 'pointer',
|
||||||
|
textTransform: 'capitalize'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{tab}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<main style={{ padding: '40px' }}>
|
||||||
|
{activeTab === 'tasks' && <TasksBoard />}
|
||||||
|
{activeTab === 'content' && <ContentPipeline />}
|
||||||
|
{activeTab === 'calendar' && <Calendar />}
|
||||||
|
{activeTab === 'memory' && <Memory />}
|
||||||
|
{activeTab === 'team' && <Team />}
|
||||||
|
{activeTab === 'office' && <Office />}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function TasksBoard() {
|
||||||
|
const [tasks, setTasks] = useState<Task[]>([
|
||||||
|
{ id: '1', title: 'Fix git backup push', status: 'in-progress', assignee: 'neo' },
|
||||||
|
{ id: '2', title: 'Deploy nodecrew landing page', status: 'done', assignee: 'neo' },
|
||||||
|
{ id: '3', title: 'Fix YouTube backup', status: 'todo', assignee: 'neo' },
|
||||||
|
{ id: '4', title: 'Setup Mission Control', status: 'in-progress', assignee: 'jelena' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const columns: { status: TaskStatus; label: string; color: string }[] = [
|
||||||
|
{ status: 'todo', label: 'To Do', color: '#6b7280' },
|
||||||
|
{ status: 'in-progress', label: 'In Progress', color: '#e94560' },
|
||||||
|
{ status: 'done', label: 'Done', color: '#10b981' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}>
|
||||||
|
{columns.map(col => (
|
||||||
|
<div key={col.status} style={{ background: '#1a1a2e', borderRadius: '12px', padding: '20px' }}>
|
||||||
|
<h3 style={{ color: col.color, marginBottom: '20px' }}>{col.label}</h3>
|
||||||
|
{tasks.filter(t => t.status === col.status).map(task => (
|
||||||
|
<div key={task.id} style={{ background: '#16213e', padding: '15px', borderRadius: '8px', marginBottom: '10px' }}>
|
||||||
|
<p>{task.title}</p>
|
||||||
|
<span style={{ fontSize: '0.8rem', color: '#9ca3af' }}>@{task.assignee}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ContentPipeline() {
|
||||||
|
const [items, setItems] = useState<ContentItem[]>([
|
||||||
|
{ id: '1', title: 'ManoonOils Ad Copy', stage: 'script' },
|
||||||
|
{ id: '2', title: 'AI Agency Promo', stage: 'idea' },
|
||||||
|
{ id: '3', title: 'Product Launch Video', stage: 'thumbnail' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const stages: { stage: ContentStage; label: string }[] = [
|
||||||
|
{ stage: 'idea', label: '💡 Ideas' },
|
||||||
|
{ stage: 'script', label: '📝 Script' },
|
||||||
|
{ stage: 'thumbnail', label: '🖼️ Thumbnail' },
|
||||||
|
{ stage: 'filming', label: '🎬 Filming' },
|
||||||
|
{ stage: 'done', label: '✅ Done' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'flex', gap: '15px', overflowX: 'auto', paddingBottom: '20px' }}>
|
||||||
|
{stages.map(s => (
|
||||||
|
<div key={s.stage} style={{ minWidth: '250px', background: '#1a1a2e', borderRadius: '12px', padding: '20px' }}>
|
||||||
|
<h3 style={{ marginBottom: '15px' }}>{s.label}</h3>
|
||||||
|
{items.filter(i => i.stage === s.stage).map(item => (
|
||||||
|
<div key={item.id} style={{ background: '#16213e', padding: '15px', borderRadius: '8px', marginBottom: '10px' }}>
|
||||||
|
{item.title}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Calendar() {
|
||||||
|
const events: CalendarEvent[] = [
|
||||||
|
{ id: '1', title: 'Twitter Briefing', date: '2026-02-19 06:00', type: 'cron' },
|
||||||
|
{ id: '2', title: 'Infra Status Report', date: '2026-02-19 07:00', type: 'cron' },
|
||||||
|
{ id: '3', title: 'ManoonOils Analytics', date: '2026-02-19 08:00', type: 'cron' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ background: '#1a1a2e', borderRadius: '12px', padding: '30px' }}>
|
||||||
|
<h2 style={{ marginBottom: '30px' }}>📅 Scheduled Tasks & Cron Jobs</h2>
|
||||||
|
<table style={{ width: '100%', borderCollapse: 'collapse' }}>
|
||||||
|
<thead>
|
||||||
|
<tr style={{ borderBottom: '1px solid #2a2a4e' }}>
|
||||||
|
<th style={{ textAlign: 'left', padding: '15px', color: '#9ca3af' }}>Task</th>
|
||||||
|
<th style={{ textAlign: 'left', padding: '15px', color: '#9ca3af' }}>Date/Time</th>
|
||||||
|
<th style={{ textAlign: 'left', padding: '15px', color: '#9ca3af' }}>Type</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{events.map(event => (
|
||||||
|
<tr key={event.id} style={{ borderBottom: '1px solid #2a2a4e' }}>
|
||||||
|
<td style={{ padding: '15px' }}>{event.title}</td>
|
||||||
|
<td style={{ padding: '15px', color: '#9ca3af' }}>{event.date}</td>
|
||||||
|
<td style={{ padding: '15px' }}>
|
||||||
|
<span style={{ background: event.type === 'cron' ? '#e94560' : '#10b981', padding: '4px 12px', borderRadius: '20px', fontSize: '0.8rem' }}>
|
||||||
|
{event.type}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Memory() {
|
||||||
|
const memories: Memory[] = [
|
||||||
|
{ id: '1', title: 'ManoonOils Product Formula', date: '2026-02-07', preview: 'Professional formulation for anti-aging serum...' },
|
||||||
|
{ id: '2', title: 'Backup System Setup', date: '2026-02-05', preview: 'Storage Box mounted at /mnt/storagebox...' },
|
||||||
|
{ id: '3', title: 'Neo Agent Created', date: '2026-02-03', preview: 'Neo as CTO - infrastructure agent...' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: '20px' }}>
|
||||||
|
{memories.map(mem => (
|
||||||
|
<div key={mem.id} style={{ background: '#1a1a2e', borderRadius: '12px', padding: '20px' }}>
|
||||||
|
<h3>{mem.title}</h3>
|
||||||
|
<p style={{ color: '#9ca3af', fontSize: '0.9rem', marginTop: '10px' }}>{mem.preview}</p>
|
||||||
|
<span style={{ color: '#6b7280', fontSize: '0.8rem' }}>{mem.date}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Team() {
|
||||||
|
const members: TeamMember[] = [
|
||||||
|
{ id: '1', name: 'Jelena', role: 'Chief of Staff', status: 'working' },
|
||||||
|
{ id: '2', name: 'Neo', role: 'CTO / DevOps', status: 'working' },
|
||||||
|
{ id: '3', name: 'Agent 3', role: 'Sales Agent', status: 'idle' },
|
||||||
|
{ id: '4', name: 'Agent 4', role: 'Ad Manager', status: 'idle' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))', gap: '20px' }}>
|
||||||
|
{members.map(member => (
|
||||||
|
<div key={member.id} style={{ background: '#1a1a2e', borderRadius: '12px', padding: '25px', display: 'flex', alignItems: 'center', gap: '15px' }}>
|
||||||
|
<div style={{ width: '50px', height: '50px', borderRadius: '50%', background: member.status === 'working' ? '#10b981' : '#6b7280', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '1.5rem' }}>
|
||||||
|
{member.name[0]}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3>{member.name}</h3>
|
||||||
|
<p style={{ color: '#9ca3af', fontSize: '0.9rem' }}>{member.role}</p>
|
||||||
|
<span style={{ color: member.status === 'working' ? '#10b981' : '#6b7280', fontSize: '0.8rem' }}>
|
||||||
|
{member.status === 'working' ? '● Working' : '○ Idle'}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Office() {
|
||||||
|
const agents = [
|
||||||
|
{ name: 'Jelena', area: 'Executive Suite', working: true, task: 'Managing operations' },
|
||||||
|
{ name: 'Neo', area: 'Server Room', working: true, task: 'Infrastructure monitoring' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ background: '#1a1a2e', borderRadius: '12px', padding: '30px' }}>
|
||||||
|
<h2 style={{ marginBottom: '30px' }}>🏢 Digital Office</h2>
|
||||||
|
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '20px' }}>
|
||||||
|
{agents.map(agent => (
|
||||||
|
<div key={agent.name} style={{ background: '#16213e', borderRadius: '12px', padding: '25px' }}>
|
||||||
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||||
|
<h3>{agent.name}</h3>
|
||||||
|
<span style={{ width: '12px', height: '12px', borderRadius: '50%', background: agent.working ? '#10b981' : '#6b7280' }} />
|
||||||
|
</div>
|
||||||
|
<p style={{ color: '#9ca3af', marginTop: '10px' }}>📍 {agent.area}</p>
|
||||||
|
<p style={{ color: '#e94560', marginTop: '5px' }}>💻 {agent.task}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
5
next-env.d.ts
vendored
Normal file
5
next-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/image-types/global" />
|
||||||
|
|
||||||
|
// NOTE: This file should not be edited
|
||||||
|
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
||||||
498
package-lock.json
generated
Normal file
498
package-lock.json
generated
Normal file
@@ -0,0 +1,498 @@
|
|||||||
|
{
|
||||||
|
"name": "mission-control",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "mission-control",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"dependencies": {
|
||||||
|
"next": "14.2.35",
|
||||||
|
"react": "^18",
|
||||||
|
"react-dom": "^18"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20",
|
||||||
|
"@types/react": "^18",
|
||||||
|
"@types/react-dom": "^18",
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/env": {
|
||||||
|
"version": "14.2.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.35.tgz",
|
||||||
|
"integrity": "sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-darwin-arm64": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-darwin-x64": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-arm64-musl": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-x64-gnu": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-linux-x64-musl": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-win32-ia32-msvc": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==",
|
||||||
|
"cpu": [
|
||||||
|
"ia32"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@next/swc-win32-x64-msvc": {
|
||||||
|
"version": "14.2.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.33.tgz",
|
||||||
|
"integrity": "sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@swc/counter": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
||||||
|
"integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==",
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
},
|
||||||
|
"node_modules/@swc/helpers": {
|
||||||
|
"version": "0.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
|
||||||
|
"integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@swc/counter": "^0.1.3",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "20.19.33",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz",
|
||||||
|
"integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.21.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/prop-types": {
|
||||||
|
"version": "15.7.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
|
||||||
|
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@types/react": {
|
||||||
|
"version": "18.3.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz",
|
||||||
|
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/prop-types": "*",
|
||||||
|
"csstype": "^3.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/react-dom": {
|
||||||
|
"version": "18.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz",
|
||||||
|
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "^18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/busboy": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
|
||||||
|
"dependencies": {
|
||||||
|
"streamsearch": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.16.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/caniuse-lite": {
|
||||||
|
"version": "1.0.30001770",
|
||||||
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001770.tgz",
|
||||||
|
"integrity": "sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/browserslist"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "CC-BY-4.0"
|
||||||
|
},
|
||||||
|
"node_modules/client-only": {
|
||||||
|
"version": "0.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
|
||||||
|
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/csstype": {
|
||||||
|
"version": "3.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
|
||||||
|
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/graceful-fs": {
|
||||||
|
"version": "4.2.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/js-tokens": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/loose-envify": {
|
||||||
|
"version": "1.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||||
|
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"loose-envify": "cli.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||||
|
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/next": {
|
||||||
|
"version": "14.2.35",
|
||||||
|
"resolved": "https://registry.npmjs.org/next/-/next-14.2.35.tgz",
|
||||||
|
"integrity": "sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@next/env": "14.2.35",
|
||||||
|
"@swc/helpers": "0.5.5",
|
||||||
|
"busboy": "1.6.0",
|
||||||
|
"caniuse-lite": "^1.0.30001579",
|
||||||
|
"graceful-fs": "^4.2.11",
|
||||||
|
"postcss": "8.4.31",
|
||||||
|
"styled-jsx": "5.1.1"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"next": "dist/bin/next"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.17.0"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@next/swc-darwin-arm64": "14.2.33",
|
||||||
|
"@next/swc-darwin-x64": "14.2.33",
|
||||||
|
"@next/swc-linux-arm64-gnu": "14.2.33",
|
||||||
|
"@next/swc-linux-arm64-musl": "14.2.33",
|
||||||
|
"@next/swc-linux-x64-gnu": "14.2.33",
|
||||||
|
"@next/swc-linux-x64-musl": "14.2.33",
|
||||||
|
"@next/swc-win32-arm64-msvc": "14.2.33",
|
||||||
|
"@next/swc-win32-ia32-msvc": "14.2.33",
|
||||||
|
"@next/swc-win32-x64-msvc": "14.2.33"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@opentelemetry/api": "^1.1.0",
|
||||||
|
"@playwright/test": "^1.41.2",
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"sass": "^1.3.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@opentelemetry/api": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@playwright/test": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"sass": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.4.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
|
||||||
|
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.6",
|
||||||
|
"picocolors": "^1.0.0",
|
||||||
|
"source-map-js": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react": {
|
||||||
|
"version": "18.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
|
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-dom": {
|
||||||
|
"version": "18.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
|
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0",
|
||||||
|
"scheduler": "^0.23.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18.3.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/scheduler": {
|
||||||
|
"version": "0.23.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||||
|
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/streamsearch": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/styled-jsx": {
|
||||||
|
"version": "5.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
|
||||||
|
"integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"client-only": "0.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@babel/core": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"babel-plugin-macros": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
|
"license": "0BSD"
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "5.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
|
||||||
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||||
|
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>Mission Control</title>
|
|
||||||
<style>
|
|
||||||
body { background: #000; color: #fff; font-family: monospace; padding: 20px; margin: 0; }
|
|
||||||
h1 { font-size: 18px; margin-bottom: 15px; }
|
|
||||||
.nav { display: flex; gap: 5px; flex-wrap: wrap; margin-bottom: 15px; }
|
|
||||||
.nav button { padding: 8px 12px; background: #222; color: #888; border: none; cursor: pointer; font-size: 11px; }
|
|
||||||
.nav button.active { background: #f0f; color: #fff; }
|
|
||||||
pre { background: #111; padding: 15px; border-radius: 8px; overflow: auto; font-size: 10px; max-height: 70vh; }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>MISSION CONTROL</h1>
|
|
||||||
<div class="nav" id="nav"></div>
|
|
||||||
<pre id="out">Loading...</pre>
|
|
||||||
<script>
|
|
||||||
var tabs = ['tasks','crons','server','backups','agents','whatsapp','memory'];
|
|
||||||
var cur = 'tasks';
|
|
||||||
function rn() {
|
|
||||||
document.getElementById('nav').innerHTML = tabs.map(function(t){
|
|
||||||
return '<button class="'+(t===cur?'active':'')+'" onclick="ld(\''+t+'\')">'+t+'</button>';
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
function ld(t) {
|
|
||||||
cur = t; rn();
|
|
||||||
document.getElementById('out').textContent = 'Loading...';
|
|
||||||
fetch('/api/data?type='+t).then(function(r){return r.json();}).then(function(d){
|
|
||||||
document.getElementById('out').textContent = JSON.stringify(d,null,2);
|
|
||||||
})["catch"](function(e){document.getElementById('out').textContent = 'Error: '+e.message;});
|
|
||||||
}
|
|
||||||
rn(); ld('tasks');
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
Reference in New Issue
Block a user