Painel administrativo web para orquestração de agentes Claude Code com suporte a execução de tarefas, agendamento cron, pipelines sequenciais e terminal com streaming em tempo real via WebSocket.
73 lines
1.9 KiB
JavaScript
73 lines
1.9 KiB
JavaScript
import express from 'express';
|
|
import { createServer } from 'http';
|
|
import { WebSocketServer } from 'ws';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
import apiRouter, { setWsBroadcast } from './src/routes/api.js';
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
const PORT = process.env.PORT || 3000;
|
|
|
|
const app = express();
|
|
const httpServer = createServer(app);
|
|
const wss = new WebSocketServer({ server: httpServer });
|
|
|
|
app.use((req, res, next) => {
|
|
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
if (req.method === 'OPTIONS') return res.sendStatus(204);
|
|
next();
|
|
});
|
|
|
|
app.use(express.json());
|
|
app.use(express.static(join(__dirname, 'public')));
|
|
app.use('/api', apiRouter);
|
|
|
|
const connectedClients = new Set();
|
|
|
|
wss.on('connection', (ws) => {
|
|
connectedClients.add(ws);
|
|
|
|
ws.on('close', () => {
|
|
connectedClients.delete(ws);
|
|
});
|
|
|
|
ws.on('error', () => {
|
|
connectedClients.delete(ws);
|
|
});
|
|
});
|
|
|
|
function broadcast(message) {
|
|
const payload = JSON.stringify(message);
|
|
for (const client of connectedClients) {
|
|
if (client.readyState === 1) {
|
|
client.send(payload);
|
|
}
|
|
}
|
|
}
|
|
|
|
setWsBroadcast(broadcast);
|
|
|
|
function gracefulShutdown(signal) {
|
|
console.log(`\nSinal ${signal} recebido. Encerrando servidor...`);
|
|
|
|
httpServer.close(() => {
|
|
console.log('Servidor HTTP encerrado.');
|
|
process.exit(0);
|
|
});
|
|
|
|
setTimeout(() => {
|
|
console.error('Forçando encerramento após timeout.');
|
|
process.exit(1);
|
|
}, 10000);
|
|
}
|
|
|
|
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
|
|
httpServer.listen(PORT, () => {
|
|
console.log(`Painel administrativo disponível em http://localhost:${PORT}`);
|
|
console.log(`WebSocket server ativo na mesma porta.`);
|
|
});
|