← back to Designer Wallcoverings
DW-Agents/create-agent-template.ts
330 lines
#!/usr/bin/env tsx
/**
* Agent Template Creator
* Quickly create new DW-Agents with standard structure
*/
import { promises as fs } from 'fs';
import path from 'path';
interface AgentConfig {
name: string;
port: number;
description: string;
features: string[];
}
async function createAgent(config: AgentConfig) {
const agentDir = `/root/DW-Agents/dw-agents`;
const fileName = `${config.name.toLowerCase().replace(/\s+/g, '-')}-agent.ts`;
const filePath = path.join(agentDir, fileName);
const template = `#!/usr/bin/env tsx
/**
* ${config.name} Agent
* ${config.description}
*
* Features:
${config.features.map(f => ` * - ${f}`).join('\n')}
*/
import express from 'express';
import { exec } from 'child_process';
import { promises as fs } from 'fs';
import path from 'path';
import { promisify } from 'util';
const execAsync = promisify(exec);
const app = express();
const PORT = process.env.PORT || ${config.port};
// Agent state
let isRunning = false;
let lastUpdate = new Date();
const agentData: any[] = [];
// Middleware
app.use(express.json());
app.use(express.static(path.join(__dirname, 'public')));
// CORS middleware
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
next();
});
// Routes
app.get('/', (req, res) => {
res.json({
agent: '${config.name}',
status: isRunning ? 'online' : 'offline',
lastUpdate: lastUpdate.toISOString(),
port: PORT,
endpoints: [
'GET / - This status endpoint',
'GET /health - Health check',
'GET /data - Get agent data',
'POST /action - Trigger agent action',
'GET /dashboard - HTML dashboard'
]
});
});
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
uptime: process.uptime(),
memory: process.memoryUsage(),
timestamp: new Date().toISOString()
});
});
app.get('/data', (req, res) => {
res.json({
data: agentData,
count: agentData.length,
lastUpdate: lastUpdate.toISOString()
});
});
app.post('/action', async (req, res) => {
try {
const { action, params } = req.body;
console.log(\`📡 ${config.name} received action: \${action}\`);
// Handle different actions
switch (action) {
case 'start':
await startAgent();
break;
case 'stop':
await stopAgent();
break;
case 'refresh':
await refreshData();
break;
default:
return res.status(400).json({ error: 'Unknown action' });
}
res.json({ success: true, action, timestamp: new Date().toISOString() });
} catch (error) {
console.error('❌ Action failed:', error);
res.status(500).json({ error: error.message });
}
});
app.get('/dashboard', (req, res) => {
const html = \`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${config.name} Dashboard</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
.container { max-width: 1200px; margin: 0 auto; }
.header { background: #2c3e50; color: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; }
.card { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.status { padding: 8px 16px; border-radius: 4px; color: white; }
.online { background: #27ae60; }
.offline { background: #e74c3c; }
button { background: #3498db; color: white; border: none; padding: 10px 20px; border-radius: 4px; cursor: pointer; margin: 5px; }
button:hover { background: #2980b9; }
.data-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🤖 ${config.name}</h1>
<p>${config.description}</p>
</div>
<div class="card">
<h2>Agent Status</h2>
<span class="status \${isRunning ? 'online' : 'offline'}">
\${isRunning ? 'ONLINE' : 'OFFLINE'}
</span>
<p>Last Update: \${lastUpdate.toLocaleString()}</p>
<p>Data Points: \${agentData.length}</p>
<div style="margin-top: 20px;">
<button onclick="triggerAction('start')">Start</button>
<button onclick="triggerAction('stop')">Stop</button>
<button onclick="triggerAction('refresh')">Refresh</button>
<button onclick="location.reload()">Reload Page</button>
</div>
</div>
<div class="card">
<h2>Features</h2>
<ul>
${config.features.map(f => ` <li>${f}</li>`).join('\n')}
</ul>
</div>
<div class="card">
<h2>Recent Data</h2>
<div id="data-display">Loading...</div>
</div>
</div>
<script>
async function triggerAction(action) {
try {
const response = await fetch('/action', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action })
});
if (response.ok) {
alert(\`Action '\${action}' completed successfully!\`);
location.reload();
} else {
alert(\`Action '\${action}' failed!\`);
}
} catch (error) {
alert(\`Error: \${error.message}\`);
}
}
async function loadData() {
try {
const response = await fetch('/data');
const data = await response.json();
const display = document.getElementById('data-display');
if (data.data.length === 0) {
display.innerHTML = '<p>No data available</p>';
} else {
display.innerHTML = '<pre>' + JSON.stringify(data.data.slice(-5), null, 2) + '</pre>';
}
} catch (error) {
document.getElementById('data-display').innerHTML = \`<p>Error loading data: \${error.message}</p>\`;
}
}
loadData();
setInterval(loadData, 5000); // Refresh every 5 seconds
</script>
</body>
</html>
\`;
res.send(html);
});
// Agent functions
async function startAgent() {
console.log(\`🚀 Starting ${config.name}...\`);
isRunning = true;
lastUpdate = new Date();
// Add your agent logic here
// Example: monitoring, data collection, processing, etc.
}
async function stopAgent() {
console.log(\`🛑 Stopping ${config.name}...\`);
isRunning = false;
lastUpdate = new Date();
}
async function refreshData() {
console.log(\`🔄 Refreshing ${config.name} data...\`);
try {
// Add your data refresh logic here
// Example:
const newData = {
timestamp: new Date().toISOString(),
value: Math.random(),
status: 'collected'
};
agentData.push(newData);
// Keep only last 100 records
if (agentData.length > 100) {
agentData.shift();
}
lastUpdate = new Date();
console.log(\`✅ Data refreshed: \${agentData.length} records\`);
} catch (error) {
console.error('❌ Data refresh failed:', error);
throw error;
}
}
// Auto-refresh data every 60 seconds
setInterval(() => {
if (isRunning) {
refreshData().catch(console.error);
}
}, 60000);
// Start server
app.listen(PORT, () => {
console.log(\`🤖 ${config.name} running on http://45.61.58.125:\${PORT}\`);
console.log(\`📊 Dashboard: http://45.61.58.125:\${PORT}/dashboard\`);
// Auto-start the agent
startAgent().catch(console.error);
});
// Handle graceful shutdown
process.on('SIGTERM', async () => {
console.log(\`👋 ${config.name} shutting down...\`);
await stopAgent();
process.exit(0);
});
process.on('SIGINT', async () => {
console.log(\`👋 ${config.name} shutting down...\`);
await stopAgent();
process.exit(0);
});
export default app;
`;
await fs.writeFile(filePath, template);
await fs.chmod(filePath, '755'); // Make executable
console.log(`✅ Created agent: ${filePath}`);
console.log(`🚀 To run: PORT=${config.port} pm2 start ${fileName} --name "${config.name.toLowerCase().replace(/\s+/g, '-')}" --interpreter npx --interpreter-args tsx`);
console.log(`🌐 Dashboard: http://45.61.58.125:${config.port}/dashboard`);
return filePath;
}
// Example usage
if (require.main === module) {
const agentConfig: AgentConfig = {
name: process.argv[2] || 'Test Agent',
port: parseInt(process.argv[3]) || 9999,
description: process.argv[4] || 'A test agent for demonstration purposes',
features: [
'Real-time monitoring',
'Data collection and storage',
'Web dashboard interface',
'REST API endpoints',
'Automated reporting'
]
};
createAgent(agentConfig).then((path) => {
console.log(`Agent created successfully at: ${path}`);
});
}
export { createAgent };