Kraft102's picture
Fix: Make Notion routes optional (try/catch dynamic import)
22839e7 verified
// Load environment variables FIRST - before any other imports
import { config } from 'dotenv';
import { resolve } from 'path';
import { fileURLToPath } from 'url';
// Polyfills for PDF parsing environment (pdfjs-dist v4+ compatibility)
// @ts-ignore
if (typeof global.DOMMatrix === 'undefined') {
// @ts-ignore
global.DOMMatrix = class DOMMatrix {
a = 1; b = 0; c = 0; d = 1; e = 0; f = 0;
constructor() { }
};
}
// @ts-ignore
if (typeof global.ImageData === 'undefined') {
// @ts-ignore
global.ImageData = class ImageData {
data: Uint8ClampedArray;
width: number;
height: number;
constructor(width: number, height: number) {
this.width = width;
this.height = height;
this.data = new Uint8ClampedArray(width * height * 4);
}
};
}
// @ts-ignore
if (typeof global.Path2D === 'undefined') {
// @ts-ignore
global.Path2D = class Path2D { };
}
const __dirname = typeof import.meta !== 'undefined' && import.meta.url
? new URL('.', import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1')
: process.cwd();
// Load .env from backend directory, or root if not found
config({ path: resolve(__dirname, '../.env') });
config({ path: resolve(__dirname, '../../../.env') });
// --- SAFETY CHECK: VISUAL CONFIRMATION ---
const ENV_MODE = process.env.NODE_ENV || 'unknown';
const DB_HOST = process.env.POSTGRES_HOST || 'unknown';
const NEO_URI = process.env.NEO4J_URI || 'unknown';
console.log('\n\n');
if (ENV_MODE === 'production') {
console.error('╔══════════════════════════════════════════════════════════════╗');
console.error('║ WARNING: PRODUCTION MODE ║');
console.error('║ You are running against LIVE DATA. Use extreme caution. ║');
console.error('╚══════════════════════════════════════════════════════════════╝');
} else {
console.log('╔══════════════════════════════════════════════════════════════╗');
console.log('║ SAFE MODE: LOCAL DEVELOPMENT ║');
console.log('║ ║');
console.log(`║ • Environment: ${ENV_MODE.padEnd(28)} ║`);
console.log(`║ • Postgres: ${DB_HOST.padEnd(28)} ║`);
console.log(`║ • Neo4j: ${NEO_URI.padEnd(28)} ║`);
console.log('╚══════════════════════════════════════════════════════════════╝');
}
console.log('\n');
// -----------------------------------------
import express from 'express';
import cors from 'cors';
import path from 'path';
import { createServer } from 'http';
import { initializeDatabase } from './database/index.js';
import { mcpRouter } from './mcp/mcpRouter.js';
import { mcpRegistry } from './mcp/mcpRegistry.js';
import { MCPWebSocketServer } from './mcp/mcpWebsocketServer.js';
import { WebSocketServer as LogsWebSocketServer, WebSocket as LogsWebSocket } from 'ws';
import { memoryRouter } from './services/memory/memoryController.js';
import { sragRouter } from './services/srag/sragController.js';
import { evolutionRouter } from './services/evolution/evolutionController.js';
import { palRouter } from './services/pal/palController.js';
import datasourcesRouter from './routes/datasources.js';
import {
cmaContextHandler,
cmaIngestHandler,
cmaMemoryStoreHandler,
cmaMemoryRetrieveHandler,
sragQueryHandler,
sragGovernanceCheckHandler,
evolutionReportHandler,
evolutionGetPromptHandler,
evolutionAnalyzePromptsHandler,
palEventHandler,
palBoardActionHandler,
palOptimizeWorkflowHandler,
palAnalyzeSentimentHandler,
notesListHandler,
notesCreateHandler,
notesUpdateHandler,
notesDeleteHandler,
notesGetHandler,
widgetsInvokeHandler,
widgetsOsintInvestigateHandler,
widgetsThreatHuntHandler,
widgetsOrchestratorCoordinateHandler,
widgetsUpdateStateHandler,
visionaryGenerateHandler,
dataAnalysisHandler
} from './mcp/toolHandlers.js';
import { securityRouter } from './services/security/securityController.js';
import { AgentOrchestratorServer } from './mcp/servers/AgentOrchestratorServer.js';
import {
inputValidationMiddleware,
csrfProtectionMiddleware,
rateLimitingMiddleware
} from './middleware/inputValidation.js';
import { dataScheduler } from './services/ingestion/DataScheduler.js';
// 🧠 NEURAL ORGANS - Phase B: Knowledge Synthesis
import { neuralCompiler } from './services/NeuralCompiler.js';
import { neuralBus } from './services/NeuralBus.js';
import { vectorService } from './services/VectorService.js';
// 🐝 SWARM & EVOLUTION - Advanced Neural Systems
import { swarmControl } from './agents/SwarmControl.js';
import { handoverWatchdog } from './services/HandoverWatchdog.js';
import { AngelProxy } from './middleware/AngelProxy.js';
import { prometheus } from './services/Prometheus.js';
import { logStream } from './services/logging/logStream.js';
const app = express();
const PORT = parseInt(process.env.PORT || '7860', 10);
// CORS Configuration
const corsOrigin = process.env.CORS_ORIGIN || '*';
app.use(cors({
origin: corsOrigin === '*' ? '*' : corsOrigin.split(',').map(o => o.trim()),
credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
}));
app.use(express.json({ limit: '10mb' }));
app.use(rateLimitingMiddleware);
app.use(inputValidationMiddleware);
app.use(csrfProtectionMiddleware);
// CRITICAL: Start server only after database is initialized
async function startServer() {
try {
// ═══════════════════════════════════════════════════════════════════
// EARLY SERVER START - Start accepting connections ASAP
// ═══════════════════════════════════════════════════════════════════
const server = createServer(app);
const wsServer = new MCPWebSocketServer(server);
// ═══════════════════════════════════════════════════════════════════
// 🧠 NEURAL STREAM BRIDGE
// Forward internal NeuralStream events to Frontend via WebSocket AND Notion
// ═══════════════════════════════════════════════════════════════════
const { neuralStream } = await import('./services/NeuralStream.js');
const { notionService } = await import('./services/external/NotionService.js');
neuralStream.on('*', (event) => {
// 1. Send to Frontend (Real-time)
wsServer.sendToAll({
type: 'NEURAL_STREAM_EVENT',
payload: event
});
// 2. Send to Notion Command Center (Persistent Log)
// Only High/Critical events are pushed to avoid rate limits
notionService.logEvent(event);
});
// Health check endpoint - FAST response
app.get('/health', async (req, res) => {
// Basic process health - registeredTools count fetched dynamically
res.json({
status: 'healthy', // Always return healthy if process is up
timestamp: new Date().toISOString(),
uptime: process.uptime(),
environment: process.env.NODE_ENV,
registeredTools: mcpRegistry.getRegisteredTools().length
});
});
// Readiness/Liveness checks
app.get('/ready', (req, res) => res.json({ ready: true }));
app.get('/live', (req, res) => res.json({ live: true }));
// Start server IMMEDIATELY
// Use PORT from environment (HF Spaces uses 7860), fallback to 3001 for local dev
const PORT = parseInt(process.env.PORT || '3001', 10);
server.listen(PORT, '0.0.0.0', () => {
console.log(`🚀 Backend server running on http://0.0.0.0:${PORT}`);
console.log(`📡 MCP WebSocket available at ws://0.0.0.0:${PORT}/mcp/ws`);
console.log(`✨ [SYSTEM] Neural Singularity aligned on Port ${PORT}`);
// ACTIVATING AUTONOMOUS REFLEXES
handoverWatchdog.startWatch();
// Listen for signals (This is where we hook into the Orchestrator later)
handoverWatchdog.on('handover_signal', (signal) => {
console.log(`🔔 [SYSTEM] ORCHESTRATOR ALERT: Activating ${signal.target}...`);
// TODO: Integrate with agentOrchestrator.triggerAgent(signal.target);
});
});
// ============================================
// 🧠 NEURAL ORGANS INITIALIZATION
// Phase B: Knowledge Synthesis
// ============================================
// 1. Initialize Vector Service (Dark Matter)
vectorService.init().then(() => {
console.log('🌑 [DARK MATTER] Vector Engine Ready (384 dimensions)');
}).catch(err => {
console.warn('🌑 [DARK MATTER] Vector init deferred:', err.message);
});
// 2. Attach Neural Bus (Telepathy) to HTTP server
neuralBus.attach(server);
console.log('🐝 [HIVE] Neural Telepathy Bus Attached');
// 3. Start Knowledge Compiler (Brain) - Watch DropZone
const DROPZONE_PATH = process.env.DROPZONE_PATH ||
(process.platform === 'win32'
? 'C:\\Users\\claus\\Desktop\\WidgeTDC_DropZone'
: '/app/data/dropzone');
neuralCompiler.startWatching(DROPZONE_PATH).then(() => {
console.log(`📚 [BRAIN] Neural Compiler watching: ${DROPZONE_PATH}`);
}).catch(err => {
console.warn('📚 [BRAIN] Neural Compiler deferred:', err.message);
});
console.log('✨ [OMEGA] Neural Singularity Sequence Initiated');
// 4. Initialize Swarm Consciousness (The Borg)
swarmControl.registerAgent('SYSTEM_CORE', 'ARCHITECT', 3);
swarmControl.registerAgent('PROMETHEUS', 'ARCHITECT', 2);
swarmControl.registerAgent('KNOWLEDGE_COMPILER', 'EXECUTOR', 1);
swarmControl.registerAgent('ANGEL_PROXY', 'GUARDIAN', 2);
console.log('🐝 [HIVE] Swarm Consciousness Initialized');
// 5. Start Prometheus Code Scanner (every hour)
const SCAN_INTERVAL = parseInt(process.env.PROMETHEUS_SCAN_INTERVAL || '3600000');
setTimeout(() => {
prometheus.scanAndPropose(path.join(__dirname, 'services')).catch(() => { });
}, 10000); // Initial scan after 10s
setInterval(() => {
prometheus.scanAndPropose(path.join(__dirname, 'services')).catch(() => { });
}, SCAN_INTERVAL);
console.log('🔥 [PROMETHEUS] Code Evolution Scanner Active');
console.log('');
console.log('╔══════════════════════════════════════════════════════════════╗');
console.log('║ 🧠 NEURAL SINGULARITY FULLY OPERATIONAL 🧠 ║');
console.log('║ ║');
console.log('║ SEGA ✓ Knowledge Graph Active ║');
console.log('║ THG ✓ Temporal Hypergraphs Ready ║');
console.log('║ SCE ✓ Swarm Consciousness Online ║');
console.log('║ PTAM ✓ Angel Security Shield Active ║');
console.log('║ CDMM ✓ Vector Dark Matter Engine ║');
console.log('║ APD ✓ Prometheus Evolution Watching ║');
console.log('║ QEK ✓ Neural Telepathy Bus Connected ║');
console.log('╚══════════════════════════════════════════════════════════════╝');
console.log('');
// Setup Logs WebSocket
const logsWsServer = new LogsWebSocketServer({ server, path: '/api/logs/stream' });
logsWsServer.on('connection', (socket: LogsWebSocket) => {
try {
// Send recent logs buffer
socket.send(JSON.stringify({ type: 'bootstrap', entries: logStream.getRecent({ limit: 50 }) }));
} catch (err) {
console.error('Failed to send initial log buffer:', err);
}
const listener = (entry: any) => {
if (socket.readyState === LogsWebSocket.OPEN) {
socket.send(JSON.stringify({ type: 'log', entry }));
}
};
logStream.on('log', listener);
socket.on('close', () => logStream.off('log', listener));
});
// Wire up WebSocket (async)
(async () => {
try {
const { setWebSocketServer } = await import('./mcp/autonomousRouter.js');
setWebSocketServer(wsServer);
} catch (err) { /* ignore */ }
})();
// Show environment banner
const isProd = process.env.NODE_ENV === 'production';
const neo4jUri = process.env.NEO4J_URI || 'bolt://localhost:7687';
const isAuraDB = neo4jUri.includes('neo4j.io') || neo4jUri.startsWith('neo4j+s://');
console.log('');
console.log('═══════════════════════════════════════════════════════════');
if (isProd || isAuraDB) {
console.log(' 🔴 WIDGETTDC - PRODUCTION MODE');
console.log(' Neo4j: AuraDB Cloud');
} else {
console.log(' 🟢 WIDGETTDC - DEVELOPMENT MODE');
console.log(' Neo4j: Local Docker');
}
console.log(` URI: ${neo4jUri}`);
console.log('═══════════════════════════════════════════════════════════');
console.log('');
// Step 0: Always initialize sql.js (used by CognitiveMemory, etc)
await initializeDatabase();
console.log('🗄️ SQLite (sql.js) initialized for memory systems');
// Step 1: Initialize Prisma (PostgreSQL + pgvector) - Primary database
try {
const { getDatabaseAdapter } = await import('./platform/db/PrismaDatabaseAdapter.js');
const prismaAdapter = getDatabaseAdapter();
await prismaAdapter.initialize();
console.log('🐘 PostgreSQL + pgvector initialized via Prisma');
} catch (prismaError) {
console.warn('⚠️ Prisma/PostgreSQL not available:', prismaError);
console.log(' Using SQLite (sql.js) as fallback for all storage');
}
// Step 1.5: Initialize Neo4j Graph Database
try {
const { getNeo4jGraphAdapter } = await import('./platform/graph/Neo4jGraphAdapter.js');
const neo4jAdapter = getNeo4jGraphAdapter();
await neo4jAdapter.initialize();
console.log('🕸️ Neo4j Graph Database initialized');
// Also connect Neo4jService (used by GraphMemoryService)
const { neo4jService } = await import('./database/Neo4jService.js');
await neo4jService.connect();
console.log('🕸️ Neo4j Service connected');
// Run initialization if database is empty
const stats = await neo4jAdapter.getStatistics();
if (stats.nodeCount < 5) {
console.log('📦 Neo4j database appears empty, running initialization...');
const { initializeNeo4j } = await import('./scripts/initNeo4j.js');
await initializeNeo4j();
}
} catch (error) {
console.warn('⚠️ Neo4j not available (optional):', error);
console.log(' Continuing without Neo4j - using implicit graph patterns');
}
// Step 1.6: Initialize Transformers.js Embeddings
try {
const { getTransformersEmbeddings } = await import('./platform/embeddings/TransformersEmbeddings.js');
const embeddings = getTransformersEmbeddings();
await embeddings.initialize();
console.log('🧠 Transformers.js Embeddings initialized');
} catch (error) {
console.warn('⚠️ Transformers.js not available (optional):', error);
console.log(' Continuing without local embeddings');
}
// Step 2: Register MCP tools (repositories can now safely use getDatabase())
mcpRegistry.registerTool('cma.context', cmaContextHandler);
mcpRegistry.registerTool('cma.ingest', cmaIngestHandler);
mcpRegistry.registerTool('cma.memory.store', cmaMemoryStoreHandler);
mcpRegistry.registerTool('cma.memory.retrieve', cmaMemoryRetrieveHandler);
mcpRegistry.registerTool('srag.query', sragQueryHandler);
mcpRegistry.registerTool('srag.governance-check', sragGovernanceCheckHandler);
mcpRegistry.registerTool('evolution.report-run', evolutionReportHandler);
mcpRegistry.registerTool('evolution.get-prompt', evolutionGetPromptHandler);
mcpRegistry.registerTool('evolution.analyze-prompts', evolutionAnalyzePromptsHandler);
mcpRegistry.registerTool('pal.event', palEventHandler);
mcpRegistry.registerTool('pal.board-action', palBoardActionHandler);
mcpRegistry.registerTool('pal.optimize-workflow', palOptimizeWorkflowHandler);
mcpRegistry.registerTool('pal.analyze-sentiment', palAnalyzeSentimentHandler);
mcpRegistry.registerTool('notes.list', notesListHandler);
mcpRegistry.registerTool('notes.create', notesCreateHandler);
mcpRegistry.registerTool('notes.update', notesUpdateHandler);
mcpRegistry.registerTool('notes.delete', notesDeleteHandler);
mcpRegistry.registerTool('notes.get', notesGetHandler);
mcpRegistry.registerTool('widgets.invoke', widgetsInvokeHandler);
mcpRegistry.registerTool('widgets.osint.investigate', widgetsOsintInvestigateHandler);
mcpRegistry.registerTool('widgets.threat.hunt', widgetsThreatHuntHandler);
mcpRegistry.registerTool('widgets.orchestrator.coordinate', widgetsOrchestratorCoordinateHandler);
mcpRegistry.registerTool('widgets.update_state', widgetsUpdateStateHandler);
mcpRegistry.registerTool('visionary.generate', visionaryGenerateHandler);
mcpRegistry.registerTool('data.analysis', dataAnalysisHandler);
// Project Memory tools
const {
projectMemoryLogEventHandler,
projectMemoryGetEventsHandler,
projectMemoryAddFeatureHandler,
projectMemoryUpdateFeatureHandler,
projectMemoryGetFeaturesHandler
} = await import('./mcp/projectMemoryHandlers.js');
mcpRegistry.registerTool('project.log_event', projectMemoryLogEventHandler);
mcpRegistry.registerTool('project.get_events', projectMemoryGetEventsHandler);
mcpRegistry.registerTool('project.add_feature', projectMemoryAddFeatureHandler);
mcpRegistry.registerTool('project.update_feature', projectMemoryUpdateFeatureHandler);
mcpRegistry.registerTool('project.get_features', projectMemoryGetFeaturesHandler);
// Data Ingestion tools
const {
ingestionStartHandler,
ingestionStatusHandler,
ingestionConfigureHandler,
ingestionCrawlHandler,
ingestionHarvestHandler,
ingestionScribdHandler,
ingestionM365Handler
} = await import('./mcp/ingestionHandlers.js');
mcpRegistry.registerTool('ingestion.start', ingestionStartHandler);
mcpRegistry.registerTool('ingestion.status', ingestionStatusHandler);
mcpRegistry.registerTool('ingestion.configure', ingestionConfigureHandler);
mcpRegistry.registerTool('ingestion.crawl', ingestionCrawlHandler);
mcpRegistry.registerTool('ingestion.harvest', ingestionHarvestHandler);
mcpRegistry.registerTool('ingestion.scribd', ingestionScribdHandler);
mcpRegistry.registerTool('ingestion.m365', ingestionM365Handler);
// Autonomous Cognitive Tools
const {
autonomousGraphRAGHandler,
autonomousStateGraphHandler,
autonomousEvolutionHandler,
autonomousAgentTeamHandler,
autonomousAgentTeamCoordinateHandler
} = await import('./mcp/toolHandlers.js');
mcpRegistry.registerTool('autonomous.graphrag', autonomousGraphRAGHandler);
mcpRegistry.registerTool('autonomous.stategraph', autonomousStateGraphHandler);
mcpRegistry.registerTool('autonomous.evolve', autonomousEvolutionHandler);
mcpRegistry.registerTool('autonomous.agentteam', autonomousAgentTeamHandler);
mcpRegistry.registerTool('autonomous.agentteam.coordinate', autonomousAgentTeamCoordinateHandler);
// Vidensarkiv (Knowledge Archive) Tools - Persistent vector database
const {
vidensarkivSearchHandler,
vidensarkivAddHandler,
vidensarkivBatchAddHandler,
vidensarkivGetRelatedHandler,
vidensarkivListHandler,
vidensarkivStatsHandler,
vidensarkivReadHandler,
vidensarkivListFilesHandler,
vidensarkivReadFileHandler
} = await import('./mcp/toolHandlers.js');
mcpRegistry.registerTool('vidensarkiv.search', vidensarkivSearchHandler);
mcpRegistry.registerTool('vidensarkiv.add', vidensarkivAddHandler);
mcpRegistry.registerTool('vidensarkiv.batch_add', vidensarkivBatchAddHandler);
mcpRegistry.registerTool('vidensarkiv.get_related', vidensarkivGetRelatedHandler);
mcpRegistry.registerTool('vidensarkiv.list', vidensarkivListHandler);
mcpRegistry.registerTool('vidensarkiv.stats', vidensarkivStatsHandler);
mcpRegistry.registerTool('vidensarkiv.read', vidensarkivReadHandler);
mcpRegistry.registerTool('vidensarkiv.list_files', vidensarkivListFilesHandler);
mcpRegistry.registerTool('vidensarkiv.read_file', vidensarkivReadFileHandler);
// TaskRecorder Tools
const {
taskRecorderGetSuggestionsHandler,
taskRecorderApproveHandler,
taskRecorderRejectHandler,
taskRecorderExecuteHandler,
taskRecorderGetPatternsHandler,
emailRagHandler
} = await import('./mcp/toolHandlers.js');
mcpRegistry.registerTool('taskrecorder.get_suggestions', taskRecorderGetSuggestionsHandler);
mcpRegistry.registerTool('taskrecorder.approve', taskRecorderApproveHandler);
mcpRegistry.registerTool('taskrecorder.reject', taskRecorderRejectHandler);
mcpRegistry.registerTool('taskrecorder.execute', taskRecorderExecuteHandler);
mcpRegistry.registerTool('taskrecorder.get_patterns', taskRecorderGetPatternsHandler);
mcpRegistry.registerTool('email.rag', emailRagHandler);
// Document Generator Tools
const {
docgenPowerpointCreateHandler,
docgenWordCreateHandler,
docgenExcelCreateHandler,
docgenStatusHandler
} = await import('./mcp/toolHandlers.js');
mcpRegistry.registerTool('docgen.powerpoint.create', docgenPowerpointCreateHandler);
mcpRegistry.registerTool('docgen.word.create', docgenWordCreateHandler);
mcpRegistry.registerTool('docgen.excel.create', docgenExcelCreateHandler);
mcpRegistry.registerTool('docgen.status', docgenStatusHandler);
// DevTools Guardian Tools
const { handleDevToolsRequest } = await import('./mcp/devToolsHandlers.js');
mcpRegistry.registerTool('devtools-status', handleDevToolsRequest);
mcpRegistry.registerTool('devtools-scan', handleDevToolsRequest);
mcpRegistry.registerTool('devtools-validate', handleDevToolsRequest);
const { tdcGeneratePresentationHandler } = await import('./mcp/tdcHandlers.js');
mcpRegistry.registerTool('tdc.generate_presentation', tdcGeneratePresentationHandler);
// Serve public files (for generated presentations)
app.use(express.static('public'));
// Step 3: Initialize Agent Orchestrator
const orchestrator = new AgentOrchestratorServer();
mcpRegistry.registerServer(orchestrator);
console.log('🤖 Agent Orchestrator initialized');
// Step 3.5: Initialize Autonomous Intelligence System
const { initCognitiveMemory } = await import('./mcp/memory/CognitiveMemory.js');
const { getSourceRegistry } = await import('./mcp/SourceRegistry.js');
const { initAutonomousAgent, startAutonomousLearning } = await import('./mcp/autonomousRouter.js');
const { autonomousRouter } = await import('./mcp/autonomousRouter.js');
const { getSqlJsDatabase } = await import('./database/index.js');
const { existsSync } = await import('fs');
const { readFileSync } = await import('fs');
const yaml = (await import('js-yaml')).default;
// Use raw sql.js database for memory systems (they need exec() method)
const sqlJsDb = getSqlJsDatabase();
if (sqlJsDb) {
initCognitiveMemory(sqlJsDb);
console.log('🧠 Cognitive Memory initialized');
} else {
console.warn('⚠️ Cognitive Memory running in degraded mode (no sql.js database)');
initCognitiveMemory();
}
// Initialize Unified Memory System
const { unifiedMemorySystem } = await import('./mcp/cognitive/UnifiedMemorySystem.js');
unifiedMemorySystem.init();
console.log('🧠 Unified Memory System initialized');
const registry = getSourceRegistry();
// Register agents-yaml data source
registry.registerSource({
name: 'agents-yaml',
type: 'file',
capabilities: ['agents.*', 'agents.list', 'agents.get', 'agents.trigger'],
isHealthy: async () => existsSync('agents/registry.yml'),
estimatedLatency: 50,
costPerQuery: 0,
query: async (operation: string, params: any) => {
const content = readFileSync('agents/registry.yml', 'utf-8');
const data = yaml.load(content) as any;
if (operation === 'list') {
return data.agents || [];
} else if (operation === 'get' && params?.id) {
return data.agents?.find((a: any) => a.id === params.id);
}
return data.agents || [];
}
});
// Step 3.6: Initialize MCP → Autonomous Integration (non-blocking with timeout)
const autonomousInitPromise = (async () => {
try {
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Autonomous init timeout')), 5000)
);
const { initializeAutonomousSources } = await import('./mcp/autonomous/MCPIntegration.js');
await Promise.race([initializeAutonomousSources(), timeoutPromise]);
console.log('🔗 MCP tools registered as autonomous sources');
const agent = initAutonomousAgent();
console.log('🤖 Autonomous Agent initialized');
startAutonomousLearning(agent, 300000);
console.log('🔄 Autonomous learning started (5min intervals)');
} catch (err: any) {
console.warn('⚠️ Autonomous sources initialization skipped:', err.message);
}
})();
// Don't await - let it run in background
// Step 3.7: Start HansPedder orchestrator (non-blocking)
(async () => {
try {
const { startHansPedder } = await import('./orchestrator/hansPedder.js');
await startHansPedder();
console.log('👔 HansPedder orchestrator started');
} catch (err) {
console.error('⚠️ Failed to start HansPedder:', err);
}
})();
// Step 3.8: Start Data Ingestion Scheduler
dataScheduler.start();
console.log('⏰ Data Ingestion Scheduler started');
// Step 3.8.5: Start NudgeService (aggressive data generation every 15 min)
const { nudgeService } = await import('./services/NudgeService.js');
nudgeService.start();
// Step 3.9: Start HansPedder Agent Controller (non-blocking)
(async () => {
try {
const { hansPedderAgent } = await import('./services/agent/HansPedderAgentController.js');
hansPedderAgent.start();
console.log('🤖 HansPedder Agent Controller started (continuous testing + nudges)');
} catch (err) {
console.error('⚠️ Failed to start HansPedder Agent Controller:', err);
}
})();
// Step 4: Setup routes
// 🛡️ ANGEL PROXY: Security Shield on all API routes
app.use('/api', AngelProxy.cortexFirewall);
console.log('🛡️ [ANGEL] Cortex Firewall Active on /api/*');
app.use('/api/mcp', mcpRouter);
app.use('/api/mcp/autonomous', autonomousRouter);
app.use('/api/memory', memoryRouter);
app.use('/api/srag', sragRouter);
app.use('/api/evolution', evolutionRouter);
app.use('/api/harvest', (req, res, next) => {
req.url = `/harvest${req.url}`;
evolutionRouter(req, res, next);
});
app.use('/api/pal', palRouter);
app.use('/api/security', securityRouter);
// HansPedder Agent Controller routes
const hanspedderRoutes = (await import('./routes/hanspedderRoutes.js')).default;
app.use('/api/hanspedder', hanspedderRoutes);
// Cortex API - Neural Graph & Synaptic Impulses (Symbiosis V5)
const cortexRoutes = (await import('./routes/cortex.routes.js')).default;
app.use('/api/cortex', cortexRoutes);
console.log('🧬 Cortex API mounted at /api/cortex');
// Omni-Link v10 - Psyche/Consciousness Engine
const v10Routes = (await import('./routes/v10.routes.js')).default;
app.use('/api/v10', v10Routes);
console.log('🧠 Omni-Link v10 (Psyche) mounted at /api/v10');
// Omni-Link v11 - Subconscious/Proactive Analysis
const v11Routes = (await import('./routes/v11.routes.js')).default;
app.use('/api/v11/subconscious', v11Routes);
console.log('💭 Omni-Link v11 (Subconscious) mounted at /api/v11/subconscious');
// Start cognitive services background loops
const { psycheService, subconsciousService } = await import('./services/cognitive/index.js');
psycheService.startUpdateLoop(5000); // Update psyche every 5 seconds
subconsciousService.startAnalysisLoop(60000); // Analyze stakeholders every minute
console.log('🔮 Cognitive services started');
// Prototype Generation routes (PRD to Prototype)
const prototypeRoutes = (await import('./routes/prototype.js')).default;
app.use('/api/prototype', prototypeRoutes);
// System Information routes (CPU, Memory, GPU, Network stats)
const sysRoutes = (await import('./routes/sys.js')).default;
app.use('/api/sys', sysRoutes);
console.log('📊 System Info API mounted at /api/sys');
// Neural Chat - Agent-to-Agent Communication
const { neuralChatRouter } = await import('./services/NeuralChat/index.js');
app.use('/api/neural-chat', neuralChatRouter);
console.log('💬 Neural Chat API mounted at /api/neural-chat');
// Knowledge Compiler - System State Aggregation
const knowledgeRoutes = (await import('./routes/knowledge.js')).default;
app.use('/api/knowledge', knowledgeRoutes);
console.log('🧠 Knowledge API mounted at /api/knowledge');
// Knowledge Acquisition - The Omni-Harvester
const acquisitionRoutes = (await import('./routes/acquisition.js')).default;
app.use('/api/acquisition', acquisitionRoutes);
console.log('🌾 Omni-Harvester API mounted at /api/acquisition');
// Email API - Cloud-compatible email fetching via IMAP
const emailRoutes = (await import('./routes/email.js')).default;
app.use('/api/email', emailRoutes);
console.log('📧 Email API mounted at /api/email');
// Neo4j Sync API - Auto-sync between local and cloud
const neo4jSyncRoutes = (await import('./routes/neo4j-sync.js')).default;
app.use('/api/neo4j-sync', neo4jSyncRoutes);
console.log('🔄 Neo4j Sync API mounted at /api/neo4j-sync');
// Start KnowledgeCompiler auto-compilation (every 60 seconds)
const { knowledgeCompiler } = await import('./services/Knowledge/index.js');
knowledgeCompiler.startAutoCompilation(60000);
console.log('🧠 KnowledgeCompiler auto-compilation started');
// ═══════════════════════════════════════════════════════════════════
// 🛡️ BOOTSTRAP HEALTH CHECKS now run inside BootstrapGate.init()
// Prevents "Death on Startup" if Neo4j/DB unavailable
// ═══════════════════════════════════════════════════════════════════
const bootstrapHealthCheck = async (): Promise<{ ready: boolean; degraded: boolean; services: any[] }> => {
const services: { name: string; status: 'healthy' | 'degraded' | 'unavailable'; latencyMs?: number }[] = [];
const criticalFailure = false;
// Check Neo4j
try {
const start = Date.now();
const { neo4jAdapter } = await import('./adapters/Neo4jAdapter.js');
await neo4jAdapter.executeQuery('RETURN 1 as ping');
services.push({ name: 'Neo4j', status: 'healthy', latencyMs: Date.now() - start });
console.log('✅ Neo4j: HEALTHY');
} catch (err: any) {
services.push({ name: 'Neo4j', status: 'degraded' });
console.warn('⚠️ Neo4j: DEGRADED - continuing without graph features');
}
// Check Prisma/PostgreSQL (already initialized above)
try {
const start = Date.now();
// Prisma is already connected if we got here
services.push({ name: 'PostgreSQL', status: 'healthy', latencyMs: Date.now() - start });
console.log('✅ PostgreSQL: HEALTHY (Prisma connected)');
} catch (err: any) {
services.push({ name: 'PostgreSQL', status: 'degraded' });
console.warn('⚠️ PostgreSQL: DEGRADED - some features may be unavailable');
}
// Check filesystem (DropZone)
try {
const fs = await import('fs/promises');
const { DROPZONE_PATH } = await import('./config.js');
await fs.access(DROPZONE_PATH);
services.push({ name: 'Filesystem', status: 'healthy' });
console.log(`✅ Filesystem: HEALTHY (${DROPZONE_PATH})`);
} catch {
services.push({ name: 'Filesystem', status: 'degraded' });
console.warn('⚠️ Filesystem: DropZone not accessible');
}
const degraded = services.some(s => s.status === 'degraded');
return { ready: !criticalFailure, degraded, services };
};
console.log('\n🔍 Running Bootstrap Health Check...');
const bootHealth = await bootstrapHealthCheck();
if (!bootHealth.ready) {
console.error('💀 CRITICAL: Bootstrap health check failed - aborting startup');
process.exit(1);
}
if (bootHealth.degraded) {
console.warn('⚠️ WARNING: Starting in DEGRADED MODE - some features may be unavailable\n');
} else {
console.log('✅ All systems nominal - proceeding with startup\n');
}
// Server started early at top of startServer()
// ═══════════════════════════════════════════════════════════════════
// CONTINUING INITIALIZATION...
// ═══════════════════════════════════════════════════════════════════
// ============================================
// KNOWLEDGE COMPILER API - System Intelligence
// ============================================
const knowledgeApi = (await import('./api/knowledge.js')).default;
app.use('/api/knowledge', knowledgeApi);
console.log('📚 Knowledge Compiler API mounted at /api/knowledge');
const logsRouter = (await import('./routes/logs.js')).default;
app.use('/api/logs', logsRouter);
console.log('📝 Log API mounted at /api/logs');
// HyperLog API - Real-time intelligence monitoring for NeuroLink widget
app.get('/api/hyper/events', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const events = hyperLog.getHistory(50);
const metrics = hyperLog.getMetrics();
res.json({ events, metrics });
} catch (error) {
console.error('HyperLog error:', error);
res.status(500).json({ error: 'HyperLog unavailable', events: [], metrics: { totalThoughts: 0, toolUsageRate: 0, activeAgents: 0 } });
}
});
// ============================================
// SEMANTIC BUS: Widget Telepathy API
// ============================================
// Dream API - Semantic search across collective memory
app.post('/api/hyper/dream', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { query, limit = 5, minScore = 0.6 } = req.body;
if (!query) {
return res.status(400).json({ error: 'Query is required' });
}
const results = await hyperLog.findRelatedThoughts(query, limit, minScore);
const canDream = hyperLog.canDream();
res.json({
results,
query,
dreamMode: canDream ? 'semantic' : 'keyword',
timestamp: Date.now()
});
} catch (error) {
console.error('Dream API error:', error);
res.status(500).json({ error: 'Dream failed', results: [] });
}
});
// Broadcast API - Widget sends a thought into the collective
app.post('/api/hyper/broadcast', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { type, agent, content, metadata = {} } = req.body;
if (!type || !agent || !content) {
return res.status(400).json({ error: 'type, agent, and content are required' });
}
const eventId = await hyperLog.log(type, agent, content, metadata);
res.json({
success: true,
eventId,
timestamp: Date.now()
});
} catch (error) {
console.error('Broadcast API error:', error);
res.status(500).json({ error: 'Broadcast failed' });
}
});
// Find similar thoughts to a specific event
app.get('/api/hyper/similar/:eventId', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { eventId } = req.params;
const limit = parseInt(req.query.limit as string) || 5;
const results = await hyperLog.findSimilarTo(eventId, limit);
res.json({ results, eventId });
} catch (error) {
console.error('Similar API error:', error);
res.status(500).json({ error: 'Similarity search failed', results: [] });
}
});
// Get causal path leading to an event (rewind the brain)
app.get('/api/hyper/rewind/:eventId', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { eventId } = req.params;
const maxDepth = parseInt(req.query.maxDepth as string) || 50;
const path = await hyperLog.getCausalPath(eventId, maxDepth);
res.json({ path, eventId, depth: path.length });
} catch (error) {
console.error('Rewind API error:', error);
res.status(500).json({ error: 'Rewind failed', path: [] });
}
});
// Start a new thought chain (correlation)
app.post('/api/hyper/chain/start', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { label } = req.body;
const correlationId = hyperLog.startChain(label);
res.json({ correlationId, label });
} catch (error) {
console.error('Chain start error:', error);
res.status(500).json({ error: 'Failed to start chain' });
}
});
// Get brain status (can it dream?)
app.get('/api/hyper/status', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const metrics = hyperLog.getMetrics();
const canDream = hyperLog.canDream();
res.json({
canDream,
metrics,
status: canDream ? 'dreaming' : 'awake',
timestamp: Date.now()
});
} catch (error) {
console.error('Status API error:', error);
res.status(500).json({ error: 'Status unavailable' });
}
});
// ============================================
// THE STRATEGIST - Team Delegation API
// ============================================
/**
* POST /api/team/delegate
* The Strategist delegates tasks to team members (Architect, Visionary)
*/
app.post('/api/team/delegate', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const {
task,
assignTo,
priority = 'medium',
context = {},
parentTaskId
} = req.body;
if (!task || !assignTo) {
return res.status(400).json({
error: 'Missing required fields: task, assignTo'
});
}
// Log the delegation event
const eventId = await hyperLog.log(
'DELEGATION',
'TheStrategist',
`Delegating to ${assignTo}: ${task}`,
{
assignedTo: assignTo,
priority,
context,
parentTaskId,
status: 'pending'
}
);
// Broadcast the delegation for the assigned widget to pick up
await hyperLog.log(
'THOUGHT',
assignTo,
`Received task from Strategist: ${task}`,
{
delegationId: eventId,
priority,
context
}
);
res.json({
success: true,
delegationId: eventId,
message: `Task delegated to ${assignTo}`,
task: {
id: eventId,
description: task,
assignedTo: assignTo,
priority,
status: 'pending',
createdAt: Date.now()
}
});
} catch (error) {
console.error('Delegation API error:', error);
res.status(500).json({ error: 'Delegation failed' });
}
});
/**
* GET /api/team/tasks
* Get all delegated tasks and their status
*/
app.get('/api/team/tasks', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { assignedTo, status } = req.query;
// Search for delegation events
const allEvents = hyperLog.getHistory(100);
let tasks = allEvents.filter(e => e.type === 'DELEGATION');
if (assignedTo) {
tasks = tasks.filter(t => t.metadata?.assignedTo === assignedTo);
}
if (status) {
tasks = tasks.filter(t => t.metadata?.status === status);
}
res.json({
tasks: tasks.map(t => ({
id: t.id,
description: t.content,
assignedTo: t.metadata?.assignedTo,
priority: t.metadata?.priority,
status: t.metadata?.status || 'pending',
createdAt: t.timestamp,
context: t.metadata?.context
})),
total: tasks.length
});
} catch (error) {
console.error('Tasks API error:', error);
res.status(500).json({ error: 'Failed to fetch tasks' });
}
});
/**
* PUT /api/team/tasks/:taskId/status
* Update task status (e.g., in_progress, completed, blocked)
*/
app.put('/api/team/tasks/:taskId/status', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const { taskId } = req.params;
const { status, result, notes } = req.body;
if (!status) {
return res.status(400).json({ error: 'Status is required' });
}
// Log the status update
const eventId = await hyperLog.log(
'REASONING_UPDATE',
'TheStrategist',
`Task ${taskId} status updated to: ${status}`,
{
taskId,
newStatus: status,
result,
notes,
updatedAt: Date.now()
}
);
res.json({
success: true,
taskId,
status,
updateEventId: eventId
});
} catch (error) {
console.error('Task update API error:', error);
res.status(500).json({ error: 'Failed to update task' });
}
});
/**
* POST /api/team/plan
* The Strategist creates a multi-step plan with dependencies
*/
app.post('/api/team/plan', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const {
goal,
steps,
teamMembers = ['TheArchitect', 'TheVisionary']
} = req.body;
if (!goal || !steps || !Array.isArray(steps)) {
return res.status(400).json({
error: 'Missing required fields: goal, steps (array)'
});
}
// Start a new correlation chain for this plan
const planId = hyperLog.startChain(`Plan: ${goal.substring(0, 50)}`);
// Log the plan creation
await hyperLog.log(
'CRITICAL_DECISION',
'TheStrategist',
`Created plan: ${goal}`,
{
planId,
totalSteps: steps.length,
teamMembers,
steps: steps.map((s: any, i: number) => ({
order: i + 1,
...s
}))
}
);
// Create delegation events for each step
const delegations: { id: string; step: string }[] = [];
for (let i = 0; i < steps.length; i++) {
const step = steps[i];
const eventId = await hyperLog.log(
'DELEGATION',
'TheStrategist',
`Step ${i + 1}: ${step.task}`,
{
planId,
stepOrder: i + 1,
assignedTo: step.assignTo || teamMembers[i % teamMembers.length],
dependsOn: step.dependsOn || (i > 0 ? [delegations[i - 1].id] : []),
status: 'pending',
priority: step.priority || 'medium'
}
);
delegations.push({ id: eventId, step: step.task });
}
res.json({
success: true,
planId,
goal,
steps: delegations.map((d, i) => ({
...d,
order: i + 1,
assignedTo: steps[i].assignTo || teamMembers[i % teamMembers.length]
})),
totalSteps: steps.length
});
} catch (error) {
console.error('Plan API error:', error);
res.status(500).json({ error: 'Failed to create plan' });
}
});
/**
* GET /api/team/status
* Get overall team status and workload
*/
app.get('/api/team/status', async (req, res) => {
try {
const { hyperLog } = await import('./services/hyper-log.js');
const allEvents = hyperLog.getHistory(200);
const delegations = allEvents.filter(e => e.type === 'DELEGATION');
const byAgent: Record<string, any> = {};
// Aggregate by team member
for (const d of delegations) {
const agent = d.metadata?.assignedTo || 'Unassigned';
if (!byAgent[agent]) {
byAgent[agent] = {
name: agent,
pending: 0,
inProgress: 0,
completed: 0,
blocked: 0,
tasks: []
};
}
const status = d.metadata?.status || 'pending';
byAgent[agent][status === 'in_progress' ? 'inProgress' : status]++;
byAgent[agent].tasks.push({
id: d.id,
task: d.content,
status,
priority: d.metadata?.priority
});
}
res.json({
team: Object.values(byAgent),
summary: {
totalTasks: delegations.length,
pending: delegations.filter(d => d.metadata?.status === 'pending').length,
inProgress: delegations.filter(d => d.metadata?.status === 'in_progress').length,
completed: delegations.filter(d => d.metadata?.status === 'completed').length
},
lastUpdated: Date.now()
});
} catch (error) {
console.error('Team status API error:', error);
res.status(500).json({ error: 'Failed to fetch team status' });
}
});
// ============================================
// THE COLONIZER - API Assimilation Engine
// ============================================
/**
* POST /api/evolution/colonize
* Assimilate a new external API into the WidgeTDC swarm
*/
app.post('/api/evolution/colonize', async (req, res) => {
try {
const { colonizerService } = await import('./services/colonizer-service.js');
const { systemName, documentation, generateTests = false, dryRun = false } = req.body;
if (!systemName || !documentation) {
return res.status(400).json({
error: 'Missing required fields: systemName, documentation'
});
}
console.log(`🛸 [COLONIZER API] Received assimilation request for: ${systemName}`);
const result = await colonizerService.assimilateSystem({
systemName,
apiSpecContent: documentation,
generateTests,
dryRun
});
res.json(result);
} catch (error: any) {
console.error('Colonizer API error:', error);
res.status(500).json({ error: error.message || 'Assimilation failed' });
}
});
/**
* GET /api/evolution/systems
* List all assimilated systems
*/
app.get('/api/evolution/systems', async (req, res) => {
try {
const { colonizerService } = await import('./services/colonizer-service.js');
const systems = await colonizerService.listAssimilatedSystems();
res.json({
systems,
count: systems.length,
toolsDirectory: 'apps/backend/src/tools/generated'
});
} catch (error: any) {
console.error('Systems list API error:', error);
res.status(500).json({ error: 'Failed to list systems' });
}
});
/**
* DELETE /api/evolution/systems/:systemName
* Remove an assimilated system
*/
app.delete('/api/evolution/systems/:systemName', async (req, res) => {
try {
const { colonizerService } = await import('./services/colonizer-service.js');
const { systemName } = req.params;
const success = await colonizerService.removeSystem(systemName);
if (success) {
res.json({
success: true,
message: `System ${systemName} removed. Restart server to complete removal.`
});
} else {
res.status(404).json({
success: false,
message: `System ${systemName} not found`
});
}
} catch (error: any) {
console.error('System removal API error:', error);
res.status(500).json({ error: 'Failed to remove system' });
}
});
/**
* GET /api/evolution/graph/stats
* Get Neo4j graph statistics for 3D visualization
* 🔗 NEURAL LINK ENDPOINT
*
* OPTIMIZED: Uses separate lightweight queries to avoid memory overflow
* on Neo4j AuraDB free tier (824 MiB limit)
*/
app.get('/api/evolution/graph/stats', async (_req, res) => {
try {
const { neo4jService } = await import('./database/Neo4jService.js');
// 1. Fetch Stats using memory-efficient separate queries
// Note: The original MATCH (n) OPTIONAL MATCH ()-[r]->() creates a cross-product
// that exceeds Neo4j AuraDB's memory limits on large graphs (150K+ nodes)
const nodeCountQuery = `MATCH (n) RETURN count(n) as nodes`;
const relCountQuery = `MATCH ()-[r]->() RETURN count(r) as relationships`;
// Run queries in parallel for better performance
const [nodeResult, relResult] = await Promise.all([
neo4jService.runQuery(nodeCountQuery),
neo4jService.runQuery(relCountQuery)
]);
const stats = {
nodes: nodeResult[0]?.nodes?.toNumber ? nodeResult[0].nodes.toNumber() : (nodeResult[0]?.nodes || 0),
relationships: relResult[0]?.relationships?.toNumber ? relResult[0].relationships.toNumber() : (relResult[0]?.relationships || 0)
};
// 2. Fetch Sample Nodes for Visualization
const vizQuery = `
MATCH (n)
RETURN n, labels(n) as labels
LIMIT 100
`;
const vizResult = await neo4jService.runQuery(vizQuery);
// Map Neo4j structure to clean JSON for Frontend
const visualNodes = vizResult.map(row => {
const node = row.n;
return {
id: node.elementId, // v6: use elementId instead of identity
name: node.properties.name || node.properties.title || `Node ${node.elementId}`,
labels: row.labels || node.labels,
type: (row.labels && row.labels.includes('Directory')) ? 'directory' : 'file', // Simple heuristic
properties: node.properties
};
});
// 3. Fetch Sample Relationships
const relQuery = `
MATCH (n)-[r]->(m)
RETURN r, elementId(n) as source, elementId(m) as target
LIMIT 200
`;
const relQueryResult = await neo4jService.runQuery(relQuery);
const visualLinks = relQueryResult.map(row => ({
source: row.source, // elementId is string
target: row.target, // elementId is string
type: row.r.type,
id: row.r.elementId // v6: use elementId
}));
// 4. Send Combined Payload
res.json({
timestamp: new Date().toISOString(),
stats: stats,
nodes: visualNodes,
links: visualLinks,
// Backwards compatibility fields
totalNodes: stats.nodes,
totalRelationships: stats.relationships,
importGraph: visualLinks.map(l => ({ from: l.source, to: l.target }))
});
} catch (error: any) {
console.error('❌ API Error in /graph/stats:', error);
res.status(500).json({
error: 'Failed to retrieve neural link data',
details: error.message,
nodes: [],
links: []
});
}
});
/**
* GET /api/codex/status
* Get Codex Symbiosis status
*/
app.get('/api/codex/status', async (_req, res) => {
try {
const { CODEX_VERSION } = await import('./config/codex.js');
res.json({
version: CODEX_VERSION,
status: 'active',
injectionPoint: 'LLM Service',
principles: [
'HUKOMMELSE - Check context before responding',
'TRANSPARENS - Explain all actions',
'SIKKERHED - Never leak PII without approval',
'SAMARBEJDE - Compatible with team patterns',
'VÆKST - Suggest improvements when seen',
'YDMYGHED - Ask when uncertain',
'LOYALITET - Serve The Executive'
],
message: 'Codex Symbiosis is active. All AI responses are filtered through the ethical framework.'
});
} catch (error: any) {
res.status(500).json({ error: 'Failed to get Codex status' });
}
});
// ============================================
// OMNI-HARVESTER - Knowledge Acquisition API
// ============================================
const acquisitionRouter = (await import('./routes/acquisition.js')).default;
app.use('/api/acquisition', acquisitionRouter);
console.log('🌾 Omni-Harvester API mounted at /api/acquisition');
// ============================================
// 🧠 NEURAL ORGANS API
// ============================================
const neuralRouter = (await import('./routes/neural.js')).default;
app.use('/api/neural', neuralRouter);
console.log('🧠 Neural Organs API mounted at /api/neural');
// ============================================
// 📦 SHOWPAD - Brand Asset Management
// ============================================
const showpadRouter = (await import('./routes/showpad.js')).default;
app.use('/api/showpad', showpadRouter);
console.log('📦 Showpad API mounted at /api/showpad');
// ============================================
// 📝 NOTION - CORTEX Dashboard Integration (Optional)
// ============================================
try {
const notionRouter = (await import('./routes/notion.js')).default;
app.use('/api/notion', notionRouter);
console.log('📝 Notion CORTEX API mounted at /api/notion');
} catch (err) {
console.log('⚠️ Notion routes not available (optional module)');
}
// Graceful shutdown handler
const gracefulShutdown = async (signal: string) => {
console.log(`\n🛑 ${signal} received: starting graceful shutdown...`);
// Stop accepting new connections
server.close(() => {
console.log(' ✓ HTTP server closed');
});
// Stop scheduled tasks
try {
dataScheduler.stop();
console.log(' ✓ Data scheduler stopped');
} catch { /* ignore */ }
// Stop HansPedder agent
try {
const { hansPedderAgent } = await import('./services/agent/HansPedderAgentController.js');
hansPedderAgent.stop();
console.log(' ✓ HansPedder agent stopped');
} catch { /* ignore */ }
// Close Neo4j connections
try {
const { neo4jService } = await import('./database/Neo4jService.js');
await neo4jService.close();
console.log(' ✓ Neo4j connection closed');
} catch { /* ignore */ }
// Close SQLite database
try {
const { closeDatabase } = await import('./database/index.js');
closeDatabase();
console.log(' ✓ SQLite database closed');
} catch { /* ignore */ }
// Stop Neural Compiler
try {
await neuralCompiler.stop();
console.log(' ✓ Neural Compiler stopped');
} catch { /* ignore */ }
console.log('✅ Graceful shutdown complete');
process.exit(0);
};
// Handle shutdown signals
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
// Handle uncaught errors gracefully
process.on('uncaughtException', (error) => {
console.error('💥 Uncaught Exception:', error);
gracefulShutdown('uncaughtException');
});
process.on('unhandledRejection', (reason, promise) => {
console.error('💥 Unhandled Rejection at:', promise, 'reason:', reason);
// Don't exit on unhandled rejections, just log
});
} catch (error) {
console.error('❌ Failed to start server:', error);
process.exit(1);
}
}
// Start the application
startServer();