← back to Designer Wallcoverings
DW-Agents/dw-agents/agent-ui-manager/ui-manager-agent.ts.backup-auth-1762615744
982 lines
/**
* DW-Agents: UI Manager Agent
*
* Central UI/UX management system:
* - Unified design system and branding
* - Agent directory with live links
* - Theme customization and distribution
* - Style consistency across all agents
* - Central navigation hub
*
* Port: 7240
*/
import express, { Request, Response } from 'express';
import session from 'express-session';
import * as fs from 'fs';
import * as path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';
import { requireAuth as ssoAuth, handleLogin, SSO_TOKEN_NAME, SSO_TOKEN_VALUE } from '../shared-auth';
import cookieParser from 'cookie-parser';
const execAsync = promisify(exec);
import Anthropic from '@anthropic-ai/sdk';
// Import universal UI components
const { getUniversalHeader } = require('../shared-ui-components.js');
const app = express();
const PORT = 7240;
// Anthropic Claude
const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY || '';
const anthropic = new Anthropic({ apiKey: ANTHROPIC_API_KEY });
// Design system
const DESIGN_SYSTEM = {
colors: {
primary: '#667eea',
secondary: '#764ba2',
accent: '#f093fb',
success: '#27ae60',
warning: '#f39c12',
error: '#e74c3c',
dark: '#2c3e50',
light: '#ecf0f1',
},
fonts: {
primary: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
mono: "'Monaco', 'Courier New', monospace",
},
spacing: {
base: '20px',
small: '10px',
large: '40px',
},
borderRadius: {
small: '5px',
medium: '8px',
large: '10px',
},
shadows: {
small: '0 2px 5px rgba(0,0,0,0.05)',
medium: '0 2px 10px rgba(0,0,0,0.1)',
large: '0 10px 40px rgba(0,0,0,0.3)',
},
};
// Agent registry
const AGENTS = [
{ name: 'Task Orchestrator', port: 9900, path: '/', icon: '🎯', category: 'Core', description: 'Master task coordination' },
{ name: 'Shopify Store', port: 7238, path: '/', icon: '🛍️', category: 'E-Commerce', description: 'Store management' },
{ name: 'Log Monitor', port: 7239, path: '/', icon: '📋', category: 'Monitoring', description: 'Log analysis & error detection' },
{ name: 'Purchasing Office', port: 9880, path: '/', icon: '📦', category: 'Operations', description: 'Office supplies ordering' },
{ name: 'Accounting', port: 9882, path: '/', icon: '💰', category: 'Finance', description: 'Financial management' },
{ name: 'Marketing', port: 9881, path: '/', icon: '📢', category: 'Marketing', description: 'Campaign management' },
{ name: 'Zendesk Chat', port: 9884, path: '/', icon: '💬', category: 'Customer', description: 'Customer support' },
{ name: 'Digital Samples', port: 9879, path: '/', icon: '🎨', category: 'Customer', description: 'Sample management' },
{ name: 'Trend Research', port: 9883, path: '/', icon: '📊', category: 'Analytics', description: 'Market analysis' },
{ name: 'Legal Team', port: 9878, path: '/', icon: '⚖️', category: 'Legal', description: 'Legal & compliance' },
{ name: 'Master Hub', port: 9712, path: '/', icon: '🏠', category: 'Core', description: 'Central dashboard' },
{ name: 'UI Manager', port: 7240, path: '/', icon: '🎨', category: 'System', description: 'UI/UX management' },
];
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
declare module 'express-session' {
interface SessionData {
authenticated: boolean;
currentTheme: any;
chatHistory: Array<{ role: 'user' | 'assistant', content: string }>;
}
}
app.use(
session({
secret: 'dw-agents-ui-manager-2025',
resave: false,
saveUninitialized: true,
rolling: true,
cookie: {
secure: false,
httpOnly: true,
maxAge: 7 * 24 * 60 * 60 * 1000,
},
})
);
// Authentication
app.post('/login', handleLogin);
const requireAuth = (req: Request, res: Response, next: any) => {
// TEMPORARY: Disable auth for 4 hours (until 4 hours from server restart)
const serverStartTime = Date.now();
const fourHoursInMs = 4 * 60 * 60 * 1000;
if (Date.now() - serverStartTime < fourHoursInMs) {
return next();
}
if (req.cookies[SSO_TOKEN_NAME] === SSO_TOKEN_VALUE || req.session.authenticated) {
next();
} else {
res.redirect('/login');
}
};
app.get('/login', (req: Request, res: Response) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>UI Manager - Login</title>
<style>
body {
font-family: ${DESIGN_SYSTEM.fonts.primary};
background: linear-gradient(135deg, ${DESIGN_SYSTEM.colors.primary} 0%, ${DESIGN_SYSTEM.colors.secondary} 100%);
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.login-box {
background: white;
padding: 40px;
border-radius: ${DESIGN_SYSTEM.borderRadius.large};
box-shadow: ${DESIGN_SYSTEM.shadows.large};
width: 300px;
}
h2 { margin-top: 0; color: ${DESIGN_SYSTEM.colors.dark}; }
input {
width: 100%;
padding: 12px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
box-sizing: border-box;
}
button {
width: 100%;
padding: 12px;
background: ${DESIGN_SYSTEM.colors.primary};
color: white;
border: none;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
cursor: pointer;
font-size: 16px;
}
button:hover { background: ${DESIGN_SYSTEM.colors.secondary}; }
</style>
</head>
<body>
<div class="login-box">
<h2>🎨 UI Manager</h2>
<form method="POST" action="/login">
<input type="password" name="password" placeholder="Password" required autofocus />
<button type="submit">Login</button>
</form>
</div>
</body>
</html>
`);
});
// Check agent status
async function checkAgentStatus(port: number): Promise<boolean> {
try {
// Try /health first, then fallback to root / if health doesn't exist
const { stdout } = await execAsync(`curl -s -o /dev/null -w "%{http_code}" --max-time 2 http://localhost:${port}/health 2>/dev/null || curl -s -o /dev/null -w "%{http_code}" --max-time 2 http://localhost:${port}/ 2>/dev/null || echo "000"`);
const statusCode = stdout.trim();
return statusCode === '200' || statusCode.startsWith('2') || statusCode === '404' || statusCode === '302';
} catch (error) {
return false;
}
}
// Main dashboard
app.get('/', requireAuth, async (req: Request, res: Response) => {
// Check status of all agents
const agentStatuses = await Promise.all(
AGENTS.map(async (agent) => ({
...agent,
online: await checkAgentStatus(agent.port),
}))
);
const categories = [...new Set(AGENTS.map(a => a.category))];
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>UI Manager - Agent Directory</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: ${DESIGN_SYSTEM.fonts.primary};
background: ${DESIGN_SYSTEM.colors.light};
padding: 10px;
}
.header {
background: linear-gradient(135deg, ${DESIGN_SYSTEM.colors.primary} 0%, ${DESIGN_SYSTEM.colors.secondary} 100%);
color: white;
padding: ${DESIGN_SYSTEM.spacing.base};
box-shadow: ${DESIGN_SYSTEM.shadows.medium};
border-radius: 10px;
margin-bottom: 20px;
}
.header h1 { font-size: 28px; margin-bottom: 10px; }
.header p { font-size: 14px; opacity: 0.9; }
.nav {
background: white;
padding: 15px ${DESIGN_SYSTEM.spacing.base};
box-shadow: ${DESIGN_SYSTEM.shadows.small};
display: flex;
gap: 20px;
overflow-x: auto;
}
.nav-item {
padding: 10px 20px;
background: ${DESIGN_SYSTEM.colors.light};
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
cursor: pointer;
white-space: nowrap;
transition: all 0.3s;
}
.nav-item:hover { background: ${DESIGN_SYSTEM.colors.primary}; color: white; }
.nav-item.active { background: ${DESIGN_SYSTEM.colors.primary}; color: white; }
.content {
padding: 15px;
max-width: 1600px;
margin: 0 auto;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: ${DESIGN_SYSTEM.spacing.base};
margin-bottom: ${DESIGN_SYSTEM.spacing.base};
}
.stat-card {
background: white;
padding: ${DESIGN_SYSTEM.spacing.base};
border-radius: ${DESIGN_SYSTEM.borderRadius.medium};
box-shadow: ${DESIGN_SYSTEM.shadows.medium};
text-align: center;
}
.stat-card h3 { font-size: 14px; color: #666; margin-bottom: 10px; }
.stat-card p { font-size: 32px; font-weight: bold; color: ${DESIGN_SYSTEM.colors.primary}; }
.agent-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 12px;
}
.agent-card {
background: white;
border-radius: ${DESIGN_SYSTEM.borderRadius.medium};
box-shadow: ${DESIGN_SYSTEM.shadows.medium};
overflow: hidden;
transition: transform 0.3s, box-shadow 0.3s;
cursor: pointer;
}
.agent-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.agent-header {
background: linear-gradient(135deg, ${DESIGN_SYSTEM.colors.primary} 0%, ${DESIGN_SYSTEM.colors.secondary} 100%);
color: white;
padding: 12px 15px;
display: flex;
align-items: center;
gap: 10px;
}
.agent-icon {
font-size: 32px;
}
.agent-info h3 { font-size: 18px; margin-bottom: 5px; }
.agent-info p { font-size: 12px; opacity: 0.9; }
.agent-body {
padding: 12px 15px;
}
.agent-body p {
color: #666;
margin-bottom: 15px;
font-size: 14px;
}
.agent-footer {
display: flex;
gap: 8px;
padding: 0 15px 12px 15px;
}
.btn {
flex: 1;
padding: 8px;
border: none;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
cursor: pointer;
font-size: 12px;
transition: all 0.3s;
text-align: center;
text-decoration: none;
display: inline-block;
font-weight: 600;
}
.btn-primary {
background: ${DESIGN_SYSTEM.colors.primary};
color: white;
}
.btn-primary:hover { background: ${DESIGN_SYSTEM.colors.secondary}; }
.btn-secondary {
background: ${DESIGN_SYSTEM.colors.light};
color: ${DESIGN_SYSTEM.colors.dark};
}
.btn-secondary:hover { background: #ddd; }
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 11px;
font-weight: bold;
margin-left: auto;
}
.status-online {
background: ${DESIGN_SYSTEM.colors.success};
color: white;
}
.status-offline {
background: ${DESIGN_SYSTEM.colors.error};
color: white;
}
.category-section {
margin-bottom: 30px;
}
.category-title {
font-size: 20px;
font-weight: 600;
color: ${DESIGN_SYSTEM.colors.dark};
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid ${DESIGN_SYSTEM.colors.primary};
}
.design-system {
background: white;
padding: ${DESIGN_SYSTEM.spacing.base};
border-radius: ${DESIGN_SYSTEM.borderRadius.medium};
box-shadow: ${DESIGN_SYSTEM.shadows.medium};
margin-bottom: ${DESIGN_SYSTEM.spacing.base};
}
.color-palette {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.color-swatch {
width: 80px;
height: 80px;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
display: flex;
align-items: flex-end;
padding: 8px;
color: white;
font-size: 11px;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
.chat-container {
background: white;
padding: ${DESIGN_SYSTEM.spacing.base};
border-radius: ${DESIGN_SYSTEM.borderRadius.medium};
box-shadow: ${DESIGN_SYSTEM.shadows.medium};
height: calc(100vh - 250px);
display: flex;
flex-direction: column;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: ${DESIGN_SYSTEM.spacing.base};
background: #fafafa;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
margin-bottom: ${DESIGN_SYSTEM.spacing.base};
}
.chat-message {
margin-bottom: 15px;
padding: 12px;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
max-width: 80%;
}
.chat-message.user {
background: ${DESIGN_SYSTEM.colors.primary};
color: white;
margin-left: auto;
text-align: right;
}
.chat-message.assistant {
background: white;
box-shadow: ${DESIGN_SYSTEM.shadows.small};
}
.chat-input-area {
display: flex;
gap: 10px;
}
.chat-input {
flex: 1;
padding: 12px;
border: 2px solid ${DESIGN_SYSTEM.colors.primary};
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
font-size: 14px;
}
.chat-send {
padding: 12px 30px;
background: ${DESIGN_SYSTEM.colors.primary};
color: white;
border: none;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
cursor: pointer;
font-weight: 600;
}
.chat-send:hover {
background: ${DESIGN_SYSTEM.colors.secondary};
}
.chat-info {
background: ${DESIGN_SYSTEM.colors.light};
padding: 15px;
border-radius: ${DESIGN_SYSTEM.borderRadius.small};
margin-bottom: 15px;
font-size: 14px;
}
</style>
</head>
<body>
${getUniversalHeader('UI Manager', PORT, 5)}
<div class="header" style="margin-top: 20px;">
<h1>🎨 UI Manager - Agent Directory</h1>
<p>Central hub for all DW-Agents with unified design system</p>
</div>
<div class="nav">
<div class="nav-item active" onclick="showView('agents')">Agent Directory</div>
<div class="nav-item" onclick="showView('preview')">🎬 Live Preview</div>
<div class="nav-item" onclick="showView('design')">Design System</div>
<div class="nav-item" onclick="showView('functions')">Functions</div>
<div class="nav-item" onclick="showView('chat')">Universal Chat</div>
</div>
<div class="content">
<div id="agents-view">
<div class="stats">
<div class="stat-card">
<h3>Total Agents</h3>
<p>${AGENTS.length}</p>
</div>
<div class="stat-card">
<h3>Online</h3>
<p>${agentStatuses.filter(a => a.online).length}</p>
</div>
<div class="stat-card">
<h3>Offline</h3>
<p>${agentStatuses.filter(a => !a.online).length}</p>
</div>
<div class="stat-card">
<h3>Categories</h3>
<p>${categories.length}</p>
</div>
</div>
${categories.map(category => `
<div class="category-section">
<h2 class="category-title">${category}</h2>
<div class="agent-grid">
${agentStatuses.filter(a => a.category === category).map(agent => `
<div class="agent-card">
<div class="agent-header">
<div class="agent-icon">${agent.icon}</div>
<div class="agent-info">
<h3>${agent.name}</h3>
<p>Port ${agent.port}</p>
</div>
<span class="status-badge ${agent.online ? 'status-online' : 'status-offline'}">
${agent.online ? 'Online' : 'Offline'}
</span>
</div>
<div class="agent-body">
<p>${agent.description}</p>
</div>
<div class="agent-footer">
<a href="http://45.61.58.125:${agent.port}${agent.path}" target="_blank" class="btn btn-primary">
Open Dashboard
</a>
<button class="btn btn-secondary" onclick="checkHealth(${agent.port})">
Check Status
</button>
</div>
</div>
`).join('')}
</div>
</div>
`).join('')}
</div>
<div id="design-view" style="display: none;">
<div class="design-system">
<h2 style="margin-bottom: 20px;">Design System</h2>
<h3 style="margin: 20px 0 10px 0;">Color Palette</h3>
<div class="color-palette">
<div class="color-swatch" style="background: ${DESIGN_SYSTEM.colors.primary};">Primary</div>
<div class="color-swatch" style="background: ${DESIGN_SYSTEM.colors.secondary};">Secondary</div>
<div class="color-swatch" style="background: ${DESIGN_SYSTEM.colors.accent};">Accent</div>
<div class="color-swatch" style="background: ${DESIGN_SYSTEM.colors.success};">Success</div>
<div class="color-swatch" style="background: ${DESIGN_SYSTEM.colors.warning};">Warning</div>
<div class="color-swatch" style="background: ${DESIGN_SYSTEM.colors.error};">Error</div>
</div>
<h3 style="margin: 30px 0 10px 0;">Typography</h3>
<p><strong>Primary Font:</strong> ${DESIGN_SYSTEM.fonts.primary}</p>
<p><strong>Monospace Font:</strong> ${DESIGN_SYSTEM.fonts.mono}</p>
<h3 style="margin: 30px 0 10px 0;">Spacing</h3>
<p><strong>Base:</strong> ${DESIGN_SYSTEM.spacing.base}</p>
<p><strong>Small:</strong> ${DESIGN_SYSTEM.spacing.small}</p>
<p><strong>Large:</strong> ${DESIGN_SYSTEM.spacing.large}</p>
<h3 style="margin: 30px 0 10px 0;">Border Radius</h3>
<p><strong>Small:</strong> ${DESIGN_SYSTEM.borderRadius.small}</p>
<p><strong>Medium:</strong> ${DESIGN_SYSTEM.borderRadius.medium}</p>
<p><strong>Large:</strong> ${DESIGN_SYSTEM.borderRadius.large}</p>
</div>
</div>
<div id="functions-view" style="display: none;">
<div class="design-system">
<h2 style="margin-bottom: 20px;">UI Manager Functions</h2>
<h3>Available Functions:</h3>
<ul style="line-height: 2; margin: 20px 0;">
<li><strong>Agent Directory</strong> - Central hub linking to all agent dashboards</li>
<li><strong>Status Monitoring</strong> - Real-time health checks for all agents</li>
<li><strong>Design System</strong> - Unified color palette and styling guidelines</li>
<li><strong>Universal Chat</strong> - AI assistant that works across all agents</li>
<li><strong>Style Distribution</strong> - Generate CSS for consistent branding</li>
<li><strong>Theme Customization</strong> - Customize colors and styles</li>
<li><strong>Quick Navigation</strong> - One-click access to any agent</li>
<li><strong>Visual Organization</strong> - Agents grouped by category</li>
<li><strong>Responsive Design</strong> - Mobile-friendly layouts</li>
</ul>
<h3 style="margin-top: 30px;">API Endpoints:</h3>
<ul style="line-height: 2; margin: 20px 0; font-family: ${DESIGN_SYSTEM.fonts.mono}; font-size: 13px;">
<li>GET /api/agents - List all agents</li>
<li>GET /api/status - Check all agent statuses</li>
<li>GET /api/design-system - Get design tokens</li>
<li>POST /api/chat - Universal AI chat</li>
<li>POST /api/theme - Update theme</li>
<li>GET /api/css - Generate unified CSS</li>
</ul>
</div>
</div>
<div id="preview-view" style="display: none;">
<!-- Chat at top -->
<div style="background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-bottom: 20px;">
<h3 style="margin-bottom: 15px;">💬 UI Feedback Chat - Make Suggestions!</h3>
<div style="background: #fafafa; padding: 15px; border-radius: 5px; height: 150px; overflow-y: auto; margin-bottom: 15px;" id="previewChatMessages">
<div style="padding: 10px; background: white; border-radius: 5px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
<strong>UI Manager:</strong> Tell me what you think about the agent UIs below! I can help improve colors, layouts, consistency, etc.
</div>
</div>
<div style="display: flex; gap: 10px;">
<input type="text" id="previewChatInput" placeholder="e.g., 'Make all buttons the same color' or 'Add more spacing'" style="flex: 1; padding: 12px; border: 2px solid ${DESIGN_SYSTEM.colors.primary}; border-radius: 5px;" />
<button onclick="sendPreviewMessage()" style="padding: 12px 30px; background: ${DESIGN_SYSTEM.colors.primary}; color: white; border: none; border-radius: 5px; cursor: pointer; font-weight: 600;">Send Feedback</button>
</div>
</div>
<!-- Agent Preview Grid -->
<div class="design-system" style="padding: 20px;">
<h2 style="margin-bottom: 20px;">🎬 Live Agent UI Preview - All Running Agents</h2>
<p style="margin-bottom: 20px; color: #666;">View all agent interfaces side-by-side. Click any preview to open in full screen.</p>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 20px;">
${agentStatuses.filter(a => a.online).map(agent => `
<div style="background: white; border-radius: 10px; overflow: hidden; box-shadow: 0 2px 10px rgba(0,0,0,0.1);">
<div style="background: linear-gradient(135deg, ${DESIGN_SYSTEM.colors.primary} 0%, ${DESIGN_SYSTEM.colors.secondary} 100%); color: white; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<div>
<strong style="font-size: 16px;">${agent.icon} ${agent.name}</strong>
<div style="font-size: 12px; opacity: 0.9;">Port ${agent.port}</div>
</div>
<a href="http://45.61.58.125:${agent.port}${agent.path}" target="_blank" style="background: rgba(255,255,255,0.2); color: white; padding: 8px 16px; border-radius: 5px; text-decoration: none; font-size: 12px;">Open Full</a>
</div>
<div style="position: relative; padding-bottom: 75%; background: #f5f5f5;">
<iframe
src="http://45.61.58.125:${agent.port}${agent.path}"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: none;"
sandbox="allow-same-origin allow-scripts allow-forms"
loading="lazy"
></iframe>
</div>
<div style="padding: 15px; background: #fafafa; border-top: 1px solid #eee;">
<p style="margin: 0; font-size: 13px; color: #666;">${agent.description}</p>
</div>
</div>
`).join('')}
</div>
</div>
</div>
<div id="chat-view" style="display: none;">
<div class="chat-container">
<div class="chat-info">
<strong>🤖 Universal Chat - Your AI Assistant</strong><br>
Ask me anything about your agents, tasks, store data, logs, or system operations.
I can help you manage, monitor, and control all DW-Agents from one place!
</div>
<div class="chat-messages" id="chatMessages">
<div class="chat-message assistant">
👋 Hello! I'm your universal AI assistant for all DW-Agents. I can help you with:
<ul style="margin: 10px 0 0 20px;">
<li>Check agent status and health</li>
<li>Query Shopify store data</li>
<li>Review log issues</li>
<li>Create and assign tasks</li>
<li>Navigate to specific agents</li>
<li>Manage UI and styling</li>
</ul>
What would you like to know?
</div>
</div>
<div class="chat-input-area">
<input type="text" class="chat-input" id="chatInput" placeholder="Ask about agents, tasks, orders, logs, or anything else..." />
<button class="chat-send" onclick="sendMessage()">Send</button>
</div>
</div>
</div>
</div>
<script>
function showView(view) {
document.querySelectorAll('.nav-item').forEach(item => item.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('agents-view').style.display = 'none';
document.getElementById('preview-view').style.display = 'none';
document.getElementById('design-view').style.display = 'none';
document.getElementById('functions-view').style.display = 'none';
document.getElementById('chat-view').style.display = 'none';
document.getElementById(view + '-view').style.display = 'block';
}
async function checkHealth(port) {
try {
const res = await fetch(\`http://45.61.58.125:\${port}/health\`);
const data = await res.json();
alert(\`Agent Status:\\n\\n\` + JSON.stringify(data, null, 2));
} catch (error) {
alert('Agent is offline or unreachable');
}
}
async function sendMessage() {
const input = document.getElementById('chatInput');
const message = input.value.trim();
if (!message) return;
// Add user message
const messagesDiv = document.getElementById('chatMessages');
const userMsg = document.createElement('div');
userMsg.className = 'chat-message user';
userMsg.textContent = message;
messagesDiv.appendChild(userMsg);
input.value = '';
messagesDiv.scrollTop = messagesDiv.scrollHeight;
// Show thinking indicator
const thinkingMsg = document.createElement('div');
thinkingMsg.className = 'chat-message assistant';
thinkingMsg.innerHTML = '💭 Thinking...';
thinkingMsg.id = 'thinking';
messagesDiv.appendChild(thinkingMsg);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
try {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
});
const data = await res.json();
// Remove thinking indicator
document.getElementById('thinking').remove();
// Add assistant response
const assistantMsg = document.createElement('div');
assistantMsg.className = 'chat-message assistant';
assistantMsg.textContent = data.response;
messagesDiv.appendChild(assistantMsg);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
} catch (error) {
document.getElementById('thinking').remove();
const errorMsg = document.createElement('div');
errorMsg.className = 'chat-message assistant';
errorMsg.textContent = 'Error: ' + error.message;
messagesDiv.appendChild(errorMsg);
}
}
// Preview chat for UI feedback
async function sendPreviewMessage() {
const input = document.getElementById('previewChatInput');
const message = input.value.trim();
if (!message) return;
const messagesDiv = document.getElementById('previewChatMessages');
// Add user message
const userMsg = document.createElement('div');
userMsg.style.cssText = 'padding: 10px; background: ${DESIGN_SYSTEM.colors.primary}; color: white; border-radius: 5px; margin-bottom: 10px; text-align: right;';
userMsg.innerHTML = '<strong>You:</strong> ' + message;
messagesDiv.appendChild(userMsg);
input.value = '';
messagesDiv.scrollTop = messagesDiv.scrollHeight;
// Show thinking
const thinkingMsg = document.createElement('div');
thinkingMsg.style.cssText = 'padding: 10px; background: white; border-radius: 5px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);';
thinkingMsg.innerHTML = '<strong>UI Manager:</strong> 💭 Analyzing UI feedback...';
thinkingMsg.id = 'preview-thinking';
messagesDiv.appendChild(thinkingMsg);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
try {
const res = await fetch('/api/ui-feedback', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
});
const data = await res.json();
document.getElementById('preview-thinking').remove();
const assistantMsg = document.createElement('div');
assistantMsg.style.cssText = 'padding: 10px; background: white; border-radius: 5px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);';
assistantMsg.innerHTML = '<strong>UI Manager:</strong> ' + data.response;
messagesDiv.appendChild(assistantMsg);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
} catch (error) {
document.getElementById('preview-thinking').remove();
}
}
// Allow Enter key to send
document.addEventListener('DOMContentLoaded', function() {
const input = document.getElementById('chatInput');
if (input) {
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendMessage();
});
}
const previewInput = document.getElementById('previewChatInput');
if (previewInput) {
previewInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendPreviewMessage();
});
}
});
</script>
</body>
</html>
`);
});
// API: Get all agents
app.get('/api/agents', requireAuth, (req: Request, res: Response) => {
res.json({ agents: AGENTS });
});
// API: Check status of all agents
app.get('/api/status', requireAuth, async (req: Request, res: Response) => {
const statuses = await Promise.all(
AGENTS.map(async (agent) => ({
name: agent.name,
port: agent.port,
online: await checkAgentStatus(agent.port),
}))
);
res.json({ statuses });
});
// API: UI Feedback chat
app.post('/api/ui-feedback', requireAuth, async (req: Request, res: Response) => {
try {
const { message } = req.body;
const systemPrompt = `You are the UI Manager AI for DW-Agents. Users are giving you feedback about the UI/UX of various agent dashboards.
Your role:
- Analyze UI feedback and suggestions
- Provide actionable recommendations
- Suggest specific color codes, spacing values, or layout changes
- Be encouraging and helpful
- Reference the design system: Primary ${DESIGN_SYSTEM.colors.primary}, Secondary ${DESIGN_SYSTEM.colors.secondary}
Available agents to improve:
${AGENTS.map(a => `- ${a.name} (Port ${a.port})`).join('\n')}
Respond with specific, actionable suggestions. Use technical terms when appropriate (CSS, color codes, etc.).`;
const response = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 512,
system: systemPrompt,
messages: [{ role: 'user', content: message }],
});
const assistantMessage = response.content[0].type === 'text' ? response.content[0].text : '';
res.json({ response: assistantMessage });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// API: Universal chat
app.post('/api/chat', requireAuth, async (req: Request, res: Response) => {
try {
const { message } = req.body;
if (!req.session.chatHistory) {
req.session.chatHistory = [];
}
req.session.chatHistory.push({ role: 'user', content: message });
const systemPrompt = `You are the Universal AI Assistant for DW-Agents system. You have access to all agent information and can help users:
Available Agents:
${AGENTS.map(a => `- ${a.name} (Port ${a.port}): ${a.description}`).join('\n')}
You can help with:
- Checking agent status and health
- Navigating to specific agents
- Explaining agent functions
- Providing UI/UX guidance
- Helping with design system
- Creating tasks (coordinate with task-orchestrator)
- Querying Shopify store data (coordinate with shopify-store agent)
- Reviewing log issues (coordinate with log-monitor agent)
- Managing the overall system
Be helpful, concise, and actionable. Provide direct links to agents when relevant (http://45.61.58.125:[PORT]).`;
const response = await anthropic.messages.create({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 1024,
system: systemPrompt,
messages: req.session.chatHistory.slice(-10),
});
const assistantMessage = response.content[0].type === 'text' ? response.content[0].text : '';
req.session.chatHistory.push({ role: 'assistant', content: assistantMessage });
res.json({ response: assistantMessage });
} catch (error: any) {
res.status(500).json({ error: error.message });
}
});
// API: Get design system
app.get('/api/design-system', requireAuth, (req: Request, res: Response) => {
res.json({ designSystem: DESIGN_SYSTEM });
});
// API: Generate unified CSS
app.get('/api/css', requireAuth, (req: Request, res: Response) => {
const css = `
/* DW-Agents Unified Design System */
:root {
--color-primary: ${DESIGN_SYSTEM.colors.primary};
--color-secondary: ${DESIGN_SYSTEM.colors.secondary};
--color-accent: ${DESIGN_SYSTEM.colors.accent};
--color-success: ${DESIGN_SYSTEM.colors.success};
--color-warning: ${DESIGN_SYSTEM.colors.warning};
--color-error: ${DESIGN_SYSTEM.colors.error};
--color-dark: ${DESIGN_SYSTEM.colors.dark};
--color-light: ${DESIGN_SYSTEM.colors.light};
--font-primary: ${DESIGN_SYSTEM.fonts.primary};
--font-mono: ${DESIGN_SYSTEM.fonts.mono};
--spacing-base: ${DESIGN_SYSTEM.spacing.base};
--spacing-small: ${DESIGN_SYSTEM.spacing.small};
--spacing-large: ${DESIGN_SYSTEM.spacing.large};
--radius-small: ${DESIGN_SYSTEM.borderRadius.small};
--radius-medium: ${DESIGN_SYSTEM.borderRadius.medium};
--radius-large: ${DESIGN_SYSTEM.borderRadius.large};
--shadow-small: ${DESIGN_SYSTEM.shadows.small};
--shadow-medium: ${DESIGN_SYSTEM.shadows.medium};
--shadow-large: ${DESIGN_SYSTEM.shadows.large};
}
body {
font-family: var(--font-primary);
background: var(--color-light);
}
.btn-primary {
background: var(--color-primary);
color: white;
padding: 10px 20px;
border: none;
border-radius: var(--radius-small);
cursor: pointer;
}
.btn-primary:hover {
background: var(--color-secondary);
}
`;
res.setHeader('Content-Type', 'text/css');
res.send(css);
});
// Health check
app.get('/health', (req: Request, res: Response) => {
res.json({
status: 'healthy',
agent: 'ui-manager',
port: PORT,
managedAgents: AGENTS.length,
timestamp: new Date().toISOString()
});
});
// Start server
app.listen(PORT, () => {
console.log(`🎨 UI Manager Agent running on port ${PORT}`);
console.log(`📊 Dashboard: http://localhost:${PORT}`);
console.log(`🔗 Managing ${AGENTS.length} agents`);
});
// Graceful shutdown
process.on('SIGTERM', () => {
console.log('SIGTERM received, shutting down gracefully...');
process.exit(0);
});
process.on('SIGINT', () => {
console.log('SIGINT received, shutting down gracefully...');
process.exit(0);
});