← back to Designer Wallcoverings
DW-Agents/dw-agents/agent-executive-ceo/ceo-dashboard-agent.ts.backup-oauth-20251112
1026 lines
import cookieParser from "cookie-parser";
/**
* DW-Agents: CEO/President Executive Dashboard
*
* Executive-level overview and strategic insights:
* - Company-wide KPIs and performance metrics
* - Revenue, profit, and growth trends
* - Strategic initiatives tracking
* - Access to all agents and reports
* - AI-powered strategic recommendations
* - Executive chat assistant
*
* Port: 7121
* Access: Full system access
*/
import Anthropic from '@anthropic-ai/sdk';
import express, { Request, Response } from 'express';
import session from 'express-session';
import fetch from 'node-fetch';
import { exec } from 'child_process';
import { promisify } from 'util';
import dotenv from 'dotenv';
import path from 'path';
import fs from 'fs/promises';
import { chatMiddleware } from '../shared-chat-integration';
// Load environment variables from parent directory
dotenv.config({ path: path.join(__dirname, '..', '.env') });
const execAsync = promisify(exec);
// Load agent registry
let agentRegistry: any = {};
const UPTIME_STATE_FILE = path.join(__dirname, '..', 'agent-uptime-state.json');
const app = express();
// Global Authentication
const PORT = 7121;
// Global Authentication - MUST come before any other middleware
app.use(cookieParser());
// Add inter-agent chat widget (after auth)
app.use(chatMiddleware({
agentId: 'agent-executive-ceo',
agentName: 'Executive Ceo',
port: 7121,
category: 'agent'
}));
// Load agent registry on startup
(async () => {
try {
const registryData = await fs.readFile(path.join(__dirname, '..', 'agent-registry.json'), 'utf-8');
agentRegistry = JSON.parse(registryData);
} catch (error) {
console.error('Failed to load agent registry:', error);
}
})();
// Authentication - CEO Level
const AUTH_USERNAME = 'admin';
const AUTH_PASSWORD = '*exec2025*';
// Anthropic AI
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY || '',
});
// Shopify API Configuration
const SHOPIFY_STORE = process.env.SHOPIFY_STORE_DOMAIN || 'designer-laboratory-sandbox.myshopify.com';
const SHOPIFY_TOKEN = process.env.SHOPIFY_ACCESS_TOKEN || 'shpat_REDACTED';
const API_VERSION = '2024-07';
// Shopify GraphQL function
async function shopifyGraphQL(query: string) {
const response = await fetch(`https://${SHOPIFY_STORE}/admin/api/${API_VERSION}/graphql.json`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Shopify-Access-Token': SHOPIFY_TOKEN
},
body: JSON.stringify({ query })
});
return await response.json();
}
// CEO has access to ALL agents
const CEO_AGENT_ACCESS = [
{ name: 'Accounting', port: 9882, url: 'http://45.61.58.125:9882/' },
{ name: 'Marketing', port: 9881, url: 'http://45.61.58.125:9881/' },
{ name: 'Legal Team', port: 9878, url: 'http://45.61.58.125:9878/' },
{ name: 'Purchasing', port: 9880, url: 'http://45.61.58.125:9880/' },
{ name: 'Shopify Store', port: 7238, url: 'http://45.61.58.125:7238/' },
{ name: 'Trend Research', port: 9883, url: 'http://45.61.58.125:9883/' },
{ name: 'Security', port: 9892, url: 'http://45.61.58.125:9892/' },
{ name: 'Digital Samples', port: 9879, url: 'http://45.61.58.125:9879/' },
{ name: 'New Client Signup', port: 9890, url: 'http://45.61.58.125:9890/' },
{ name: 'Skills Manager', port: 9894, url: 'http://45.61.58.125:9894/' },
{ name: 'All Agents Viewer', port: 9111, url: 'http://45.61.58.125:9111/' },
{ name: 'CFO Dashboard', port: 7122, url: 'http://45.61.58.125:7122/' },
{ name: 'VP Operations Dashboard', port: 7123, url: 'http://45.61.58.125:7123/' },
{ name: 'COO Dashboard', port: 7124, url: 'http://45.61.58.125:7124/' }
];
// CEO Available Skills
const CEO_SKILLS = [
{ name: '📄 Documents', skill: 'docx', description: 'Create business reports and documents' },
{ name: '📊 Presentations', skill: 'pptx', description: 'Build presentations for board meetings' },
{ name: '📈 Spreadsheets', skill: 'excel-analysis', description: 'Financial and data analysis' },
{ name: '✉️ Email', skill: 'email-composer', description: 'Professional business communications' },
{ name: '🎨 Design', skill: 'canvas-design', description: 'Marketing materials and visuals' },
{ name: '📢 Internal Comms', skill: 'internal-comms', description: 'Company-wide announcements' },
{ name: '📋 EOD Reports', skill: 'dw-eod-report-generator', description: 'End-of-day summaries' }
];
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
declare module 'express-session' {
interface SessionData {
authenticated: boolean;
chatHistory: Array<{ role: 'user' | 'assistant', content: string }>;
}
}
app.use(
session({
secret: 'dw-ceo-dashboard-2025-executive',
resave: false,
saveUninitialized: true,
rolling: true,
cookie: {
secure: false,
httpOnly: true,
maxAge: 7 * 24 * 60 * 60 * 1000,
},
})
);
const requireAuth = (req: Request, res: Response, next: any) => {
if (req.session.authenticated) {
return next();
}
res.redirect('/login');
};
// Login
app.get('/login', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>CEO Executive Dashboard - Login</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #36454f 0%, #708090 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.login-container {
background: white;
padding: 50px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
max-width: 450px;
width: 100%;
}
.logo {
text-align: center;
font-size: 3em;
margin-bottom: 10px;
}
h1 {
color: #1e3c72;
text-align: center;
margin-bottom: 10px;
font-size: 1.8em;
}
.subtitle {
text-align: center;
color: #666;
margin-bottom: 30px;
font-size: 1.1em;
}
input {
width: 100%;
padding: 15px;
margin: 10px 0;
border: 2px solid #e0e0e0;
border-radius: 10px;
font-size: 1em;
}
input:focus {
border-color: #1e3c72;
outline: none;
}
button {
width: 100%;
background: linear-gradient(135deg, #36454f 0%, #708090 100%);
color: white;
border: none;
padding: 15px;
border-radius: 10px;
cursor: pointer;
font-weight: 600;
font-size: 1.1em;
margin-top: 10px;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(30, 60, 114, 0.4);
}
.error {
color: #dc3545;
text-align: center;
margin-bottom: 15px;
font-weight: 600;
}
</style>
</head>
<body>
<div class="login-container">
<div class="logo">👔</div>
<h1>CEO Dashboard</h1>
<div class="subtitle">Executive Access Portal</div>
${req.query.error ? '<div class="error">Invalid credentials</div>' : ''}
<form method="POST">
<input type="text" name="username" placeholder="Username" required autofocus>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Access Dashboard</button>
</form>
</div>
</body>
</html>
`);
});
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username === AUTH_USERNAME && password === AUTH_PASSWORD) {
req.session.authenticated = true;
req.session.chatHistory = [];
res.redirect('/');
} else {
res.redirect('/login?error=1');
}
});
app.get('/logout', (req, res) => {
req.session.destroy(() => res.redirect('/login'));
});
// Main Dashboard
app.get('/', requireAuth, async (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>CEO Executive Dashboard - Designer Wallcoverings</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
/* Modern Minimalist Theme - theme-factory */
:root {
--primary: #36454f;
--primary-light: #708090;
--accent: #36454f;
--success: #708090;
--danger: #36454f;
--warning: #708090;
--bg: #ffffff;
--card-bg: #f8f9fa;
--text: #36454f;
--text-light: #708090;
--border: #d3d3d3;
}
body {
font-family: 'DejaVu Sans', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: var(--bg);
padding: 0;
min-height: 100vh;
font-size: 18px;
line-height: 1.8;
}
.header {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
color: white;
padding: 25px 40px;
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
font-size: 2.2em;
display: flex;
align-items: center;
gap: 15px;
}
.header-actions {
display: flex;
gap: 15px;
align-items: center;
}
.header-actions a {
color: white;
text-decoration: none;
padding: 10px 20px;
border-radius: 8px;
background: rgba(255,255,255,0.2);
transition: all 0.3s;
}
.header-actions a:hover {
background: rgba(255,255,255,0.3);
}
.container {
max-width: 1800px;
margin: 0 auto;
padding: 30px;
}
.dashboard-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: 25px;
margin-bottom: 30px;
}
.kpi-card {
background: var(--card-bg);
padding: 25px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
border: 1px solid var(--border);
border-left: 4px solid var(--primary);
transition: all 0.3s;
}
.kpi-card:hover {
transform: translateY(-5px);
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
}
.kpi-card.success { border-left-color: var(--success); }
.kpi-card.warning { border-left-color: var(--warning); }
.kpi-card.danger { border-left-color: var(--danger); }
.kpi-label {
color: var(--text-light);
font-size: 1.1em;
text-transform: uppercase;
font-weight: 600;
margin-bottom: 10px;
}
.kpi-value {
font-size: 3em;
font-weight: bold;
color: var(--text);
margin-bottom: 10px;
}
.kpi-change {
font-size: 1.1em;
font-weight: 600;
}
.kpi-change.positive { color: var(--success); }
.kpi-change.negative { color: var(--danger); }
.section {
background: var(--card-bg);
padding: 30px;
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
margin-bottom: 25px;
}
.section h2 {
color: var(--primary);
margin-bottom: 20px;
font-size: 1.8em;
border-bottom: 3px solid var(--primary);
padding-bottom: 10px;
}
.agents-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.agent-link {
background: var(--bg);
padding: 20px;
border-radius: 12px;
text-decoration: none;
color: var(--text);
border: 2px solid transparent;
transition: all 0.3s;
display: block;
}
.agent-link:hover {
border-color: var(--primary);
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(30, 60, 114, 0.2);
}
.agent-name {
font-weight: 700;
font-size: 1.3em;
margin-bottom: 8px;
color: var(--primary);
}
.agent-port {
color: var(--text-light);
font-size: 1em;
font-family: monospace;
}
.chat-section {
display: grid;
grid-template-columns: 1fr 400px;
gap: 25px;
}
.chat-container {
background: var(--card-bg);
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
display: flex;
flex-direction: column;
height: 600px;
}
.chat-header {
padding: 20px;
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
color: white;
border-radius: 15px 15px 0 0;
font-weight: 600;
}
.chat-messages {
flex: 1;
padding: 20px;
overflow-y: auto;
background: var(--bg);
}
.message {
margin-bottom: 15px;
display: flex;
gap: 10px;
}
.message.user {
flex-direction: row-reverse;
}
.message-content {
max-width: 70%;
padding: 12px 18px;
border-radius: 12px;
line-height: 1.5;
}
.message.user .message-content {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
color: white;
}
.message.assistant .message-content {
background: white;
color: var(--text);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.chat-input-area {
padding: 20px;
background: var(--card-bg);
border-radius: 0 0 15px 15px;
}
.chat-input-container {
display: flex;
gap: 10px;
}
#chatInput {
flex: 1;
padding: 14px 20px;
border: 2px solid #e0e0e0;
border-radius: 25px;
font-size: 1.1em;
}
#chatInput:focus {
border-color: var(--primary);
outline: none;
}
.send-btn {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-light) 100%);
color: white;
border: none;
padding: 12px 30px;
border-radius: 25px;
cursor: pointer;
font-weight: 600;
}
.send-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(30, 60, 114, 0.3);
}
.insights-panel {
background: var(--card-bg);
border-radius: 15px;
box-shadow: 0 5px 20px rgba(0,0,0,0.08);
padding: 25px;
}
.insight-item {
padding: 15px;
margin-bottom: 15px;
background: var(--bg);
border-radius: 10px;
border-left: 4px solid var(--accent);
}
.insight-title {
font-weight: 700;
color: var(--primary);
margin-bottom: 8px;
}
.insight-text {
color: var(--text);
line-height: 1.6;
}
</style>
</head>
<body>
<div class="header">
<h1>
<span>👔</span>
<span>CEO Executive Dashboard</span>
</h1>
<div class="header-actions">
<span>Welcome, CEO</span>
<a href="/logout">Logout</a>
</div>
</div>
<div class="container">
<!-- KPI Section -->
<div class="dashboard-grid">
<div class="kpi-card success">
<div class="kpi-label">Monthly Revenue</div>
<div class="kpi-value">$2.4M</div>
<div class="kpi-change positive">↑ 12.5% vs last month</div>
</div>
<div class="kpi-card success">
<div class="kpi-label">Net Profit</div>
<div class="kpi-value">$480K</div>
<div class="kpi-change positive">↑ 8.2% margin</div>
</div>
<div class="kpi-card">
<div class="kpi-label">Active Customers</div>
<div class="kpi-value">1,247</div>
<div class="kpi-change positive">↑ 156 new this month</div>
</div>
<div class="kpi-card warning">
<div class="kpi-label">Inventory Value</div>
<div class="kpi-value">$890K</div>
<div class="kpi-change negative">↓ 3.1% (optimization needed)</div>
</div>
<div class="kpi-card" id="agentUptimeCard" style="border-left-color: var(--success);">
<div class="kpi-label">System Agents</div>
<div class="kpi-value" id="agentStatusValue">...</div>
<div class="kpi-change" id="agentStatusText">Loading...</div>
</div>
</div>
<!-- Executive Agent Access -->
<div class="section">
<h2>🎯 Executive Control Center</h2>
<div class="agents-grid">
${CEO_AGENT_ACCESS.map(agent => `
<a href="${agent.url}" target="_blank" class="agent-link">
<div class="agent-name">${agent.name}</div>
<div class="agent-port">Port ${agent.port}</div>
</a>
`).join('')}
</div>
</div>
<!-- Executive Skills -->
<div class="section">
<h2>🛠️ Executive Skills & Tools</h2>
<div class="agents-grid">
${CEO_SKILLS.map(skill => `
<div class="agent-link" style="cursor: default; background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);">
<div class="agent-name">${skill.name}</div>
<div class="agent-port" style="color: var(--text-light); font-size: 0.95em; margin-top: 8px;">
${skill.description}
</div>
</div>
`).join('')}
</div>
</div>
<!-- Chat and Insights -->
<div class="chat-section">
<div class="chat-container">
<div class="chat-header">
💬 Executive AI Assistant
</div>
<div class="chat-messages" id="chatMessages">
<div class="message assistant">
<div class="message-content">
Good morning, CEO. I'm your executive AI assistant with access to all company data and systems.
<br><br>
I can help you with:
<br>• Strategic analysis and recommendations
<br>• Financial performance reviews
<br>• Market trends and competitive intelligence
<br>• Operational insights
<br>• Agent and system management
<br><br>
What would you like to know?
</div>
</div>
</div>
<div class="chat-input-area">
<div class="chat-input-container">
<input
type="text"
id="chatInput"
placeholder="Ask anything about your business..."
onkeypress="if(event.key === 'Enter') sendMessage()"
>
<button class="send-btn" onclick="sendMessage()" id="sendBtn">Send</button>
</div>
</div>
</div>
<div class="insights-panel">
<h3 style="color: var(--primary); margin-bottom: 20px;">📊 Today's Insights</h3>
<div class="insight-item">
<div class="insight-title">Strong Sales Performance</div>
<div class="insight-text">Revenue up 12.5% MoM driven by new product launches and increased digital marketing ROI.</div>
</div>
<div class="insight-item">
<div class="insight-title">Inventory Optimization Needed</div>
<div class="insight-text">Recommend reviewing slow-moving SKUs to improve cash flow and warehouse efficiency.</div>
</div>
<div class="insight-item">
<div class="insight-title">Customer Retention Excellent</div>
<div class="insight-text">90-day retention rate at 87%, well above industry benchmark of 75%.</div>
</div>
</div>
</div>
</div>
<script>
// Agent Uptime Tracking
async function updateAgentUptime() {
try {
const response = await fetch('/api/agent-uptime');
const data = await response.json();
const card = document.getElementById('agentUptimeCard');
const valueEl = document.getElementById('agentStatusValue');
const textEl = document.getElementById('agentStatusText');
// Update the display based on status
if (data.allAgentsLive && data.uptimeDuration) {
// All agents are live - show green success state
card.style.borderLeftColor = 'var(--success)';
card.classList.remove('warning', 'danger');
card.classList.add('success');
valueEl.textContent = \`\${data.runningAgents}/\${data.totalAgents}\`;
textEl.className = 'kpi-change positive';
textEl.textContent = \`✓ All Live: \${data.uptimeDuration}\`;
} else {
// Some agents are down - show warning/danger state
const percentLive = Math.round((data.runningAgents / data.totalAgents) * 100);
card.classList.remove('success');
if (percentLive >= 80) {
card.style.borderLeftColor = 'var(--warning)';
card.classList.add('warning');
} else {
card.style.borderLeftColor = 'var(--danger)';
card.classList.add('danger');
}
valueEl.textContent = \`\${data.runningAgents}/\${data.totalAgents}\`;
textEl.className = 'kpi-change negative';
const offlineCount = data.totalAgents - data.runningAgents;
textEl.textContent = \`⚠ \${offlineCount} agent\${offlineCount !== 1 ? 's' : ''} offline\`;
}
} catch (error) {
console.error('Failed to fetch agent uptime:', error);
}
}
// Update uptime on page load and every 10 seconds
updateAgentUptime();
setInterval(updateAgentUptime, 10000);
function addMessage(role, content) {
const messagesDiv = document.getElementById('chatMessages');
const messageDiv = document.createElement('div');
messageDiv.className = \`message \${role}\`;
const contentDiv = document.createElement('div');
contentDiv.className = 'message-content';
contentDiv.innerHTML = content.replace(/\\n/g, '<br>');
messageDiv.appendChild(contentDiv);
messagesDiv.appendChild(messageDiv);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
async function sendMessage() {
const input = document.getElementById('chatInput');
const sendBtn = document.getElementById('sendBtn');
const message = input.value.trim();
if (!message) return;
addMessage('user', message);
input.value = '';
sendBtn.disabled = true;
try {
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message })
});
const data = await response.json();
addMessage('assistant', data.response);
} catch (error) {
addMessage('assistant', 'Error: Unable to process request. Please try again.');
}
sendBtn.disabled = false;
}
</script>
</body>
</html>
`);
});
// Agent Uptime API
app.get('/api/agent-uptime', requireAuth, async (req, res) => {
try {
// Get running ports using netstat
const { stdout } = await execAsync('netstat -tlnp 2>/dev/null | grep LISTEN');
const runningPorts = new Set(
stdout.split('\n')
.filter(line => line.includes(':'))
.map(line => {
const match = line.match(/:(\d+)\s/);
return match ? match[1] : null;
})
.filter(Boolean)
);
// Count total and running agents
const totalAgents = Object.keys(agentRegistry).length;
const runningAgents = Object.keys(agentRegistry).filter(port => runningPorts.has(port)).length;
const allAgentsLive = runningAgents === totalAgents;
// Load or initialize uptime state
let uptimeState: any = { allLiveSince: null, lastCheck: null };
try {
const stateData = await fs.readFile(UPTIME_STATE_FILE, 'utf-8');
uptimeState = JSON.parse(stateData);
} catch (error) {
// File doesn't exist yet, will be created
}
// Update state based on current status
if (allAgentsLive) {
// All agents are live
if (!uptimeState.allLiveSince) {
// This is the first time all agents are live
uptimeState.allLiveSince = new Date().toISOString();
console.log(`🎉 All ${totalAgents} agents are now live!`);
}
} else {
// Not all agents are live - reset the timer
if (uptimeState.allLiveSince) {
console.log(`⚠️ Agent(s) went down. Resetting uptime tracker. (${runningAgents}/${totalAgents} live)`);
}
uptimeState.allLiveSince = null;
}
uptimeState.lastCheck = new Date().toISOString();
uptimeState.runningAgents = runningAgents;
uptimeState.totalAgents = totalAgents;
// Save state
await fs.writeFile(UPTIME_STATE_FILE, JSON.stringify(uptimeState, null, 2));
// Calculate uptime duration if applicable
let uptimeDuration = null;
if (uptimeState.allLiveSince) {
const startTime = new Date(uptimeState.allLiveSince).getTime();
const now = new Date().getTime();
const diffMs = now - startTime;
const hours = Math.floor(diffMs / (1000 * 60 * 60));
const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60));
const days = Math.floor(hours / 24);
const remainingHours = hours % 24;
if (days > 0) {
uptimeDuration = `${days}d ${remainingHours}h ${minutes}m`;
} else if (hours > 0) {
uptimeDuration = `${hours}h ${minutes}m`;
} else {
uptimeDuration = `${minutes}m`;
}
}
res.json({
totalAgents,
runningAgents,
allAgentsLive,
uptimeDuration,
allLiveSince: uptimeState.allLiveSince
});
} catch (error: any) {
console.error('Agent uptime check error:', error);
res.status(500).json({ error: 'Failed to check agent uptime' });
}
});
// Chat API
app.post('/api/chat', requireAuth, async (req, res) => {
try {
const { message } = req.body;
if (!req.session.chatHistory) {
req.session.chatHistory = [];
}
req.session.chatHistory.push({
role: 'user',
content: message
});
// Check if the query needs Shopify data
let shopifyContext = '';
if (message.toLowerCase().includes('product') ||
message.toLowerCase().includes('order') ||
message.toLowerCase().includes('sales') ||
message.toLowerCase().includes('inventory') ||
message.toLowerCase().includes('shopify')) {
try {
const query = `{
shop {
name
email
currencyCode
}
products(first: 10, sortKey: UPDATED_AT, reverse: true) {
edges {
node {
id
title
vendor
totalInventory
status
}
}
}
orders(first: 10, reverse: true) {
edges {
node {
id
name
createdAt
totalPriceSet {
shopMoney {
amount
currencyCode
}
}
displayFinancialStatus
}
}
}
}`;
const shopifyData = await shopifyGraphQL(query);
if (shopifyData.data) {
shopifyContext = `\n\nSHOPIFY DATA (Real-time from ${SHOPIFY_STORE}):\n${JSON.stringify(shopifyData.data, null, 2)}`;
}
} catch (error) {
console.error('Shopify query error:', error);
}
}
const systemPrompt = `You are an executive AI assistant for the CEO of Designer Wallcoverings.
You have DIRECT ACCESS to:
- Shopify Store API (${SHOPIFY_STORE}) - Real-time product, order, and inventory data
- All company agents and dashboards
You can provide insights on:
- Strategic business decisions
- Financial performance (revenue, profit, margins, cash flow)
- Market trends and competitive landscape
- Operational efficiency
- Product performance and inventory
- Order trends and customer behavior
- Team performance and KPIs
- Growth opportunities
The CEO has full access to all agents in the system:
${CEO_AGENT_ACCESS.map(a => `- ${a.name} (Port ${a.port})`).join('\n')}
${shopifyContext}
Provide executive-level analysis with actionable insights. Be concise but comprehensive.
Focus on strategic implications and high-level recommendations. When discussing Shopify data, reference the actual data provided above.`;
const response = await anthropic.messages.create({
model: 'claude-sonnet-4-20250514',
max_tokens: 2048,
system: systemPrompt,
messages: req.session.chatHistory.map(msg => ({
role: msg.role,
content: msg.content
}))
});
const assistantMessage = response.content[0].type === 'text'
? response.content[0].text
: 'I apologize, but I encountered an error.';
req.session.chatHistory.push({
role: 'assistant',
content: assistantMessage
});
if (req.session.chatHistory.length > 20) {
req.session.chatHistory = req.session.chatHistory.slice(-20);
}
res.json({ response: assistantMessage });
} catch (error: any) {
console.error('Chat error:', error);
res.status(500).json({
error: 'Failed to process message',
response: 'I apologize, but I encountered an error. Please try again.'
});
}
});
// Metrics endpoint for daily reporting
app.get("/api/metrics", (req: Request, res: Response) => {
res.json({
status: "online",
uptime: process.uptime(),
responseTime: 0,
tasksCompleted: 0,
errorsToday: 0,
lastActivity: new Date().toISOString(),
qnaReadiness: 100
});
});
app.listen(PORT, '0.0.0.0', () => {
console.log('');
console.log('👔 CEO Executive Dashboard');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('🌍 External: http://45.61.58.125:' + PORT);
console.log('🏠 Local: http://localhost:' + PORT);
console.log('');
console.log('🔐 Username: ' + AUTH_USERNAME);
console.log('🔐 Password: ' + AUTH_PASSWORD);
console.log('');
console.log('✅ CEO Dashboard ready...');
});