Kraft102 commited on
Commit
1d28c11
·
1 Parent(s): b1df0ac

Deploy backend fix v2.1.0

Browse files
Dockerfile CHANGED
@@ -1,87 +1,39 @@
1
- # WidgeTDC Backend - Hugging Face Spaces Deployment
2
- # Optimized for HF Docker Spaces (port 7860)
3
-
4
- FROM node:20-slim AS builder
5
-
6
- # Install build dependencies
7
- RUN apt-get update && apt-get install -y \
8
- python3 \
9
- make \
10
- g++ \
11
- git \
12
- openssl \
13
- libssl-dev \
14
- && rm -rf /var/lib/apt/lists/*
15
 
16
  WORKDIR /app
17
 
18
- # Copy everything at once
19
- COPY . .
20
-
21
- # Install and build
22
- RUN npm ci
23
- RUN npm run build --workspace=packages/domain-types
24
- RUN npm run build --workspace=packages/mcp-types
25
- RUN npm run build --workspace=apps/backend
26
 
27
- # ============================================
28
- # Production stage - minimal footprint
29
- # ============================================
30
- FROM node:20-slim AS production
31
-
32
- # Install runtime dependencies only
33
- RUN apt-get update && apt-get install -y \
34
- openssl \
35
- ca-certificates \
36
- && rm -rf /var/lib/apt/lists/*
37
-
38
- # Create non-root user (HF Spaces requirement)
39
- RUN useradd -m -u 1000 user
40
- USER user
41
-
42
- WORKDIR /app
43
 
44
- # Copy package files
45
- COPY --from=builder --chown=user /app/package*.json ./
46
- COPY --from=builder --chown=user /app/apps/backend/package*.json ./apps/backend/
47
-
48
- # Copy built artifacts
49
- COPY --from=builder --chown=user /app/apps/backend/dist ./apps/backend/dist
50
- COPY --from=builder --chown=user /app/packages/domain-types/dist ./packages/domain-types/dist
51
- COPY --from=builder --chown=user /app/packages/mcp-types/dist ./packages/mcp-types/dist
52
-
53
- # Copy package.json for packages (needed for module resolution)
54
- COPY --from=builder --chown=user /app/packages/domain-types/package*.json ./packages/domain-types/
55
- COPY --from=builder --chown=user /app/packages/mcp-types/package*.json ./packages/mcp-types/
56
-
57
- # Copy node_modules (includes all dependencies)
58
- COPY --from=builder --chown=user /app/node_modules ./node_modules
59
 
60
- # Copy Prisma files if they exist
61
- COPY --from=builder --chown=user /app/node_modules/.prisma ./node_modules/.prisma 2>/dev/null || true
62
- COPY --from=builder --chown=user /app/node_modules/@prisma ./node_modules/@prisma 2>/dev/null || true
63
 
64
- # Create data directories (Cloud DropZone)
65
- RUN mkdir -p /app/data/dropzone && \
66
- mkdir -p /app/data/vidensarkiv && \
67
- mkdir -p /app/data/agents && \
68
- mkdir -p /app/data/harvested
69
 
70
- # Set working directory to backend for execution
 
71
  WORKDIR /app/apps/backend
72
 
73
- # Environment for HF Spaces
 
 
 
 
74
  ENV NODE_ENV=production
75
  ENV PORT=7860
76
- ENV HOST=0.0.0.0
77
- ENV DOCKER=true
78
- ENV HF_SPACE=true
79
 
80
- # HF Spaces exposes port 7860
81
  EXPOSE 7860
82
-
83
- # Health check for HF
84
- HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
85
- CMD node -e "fetch('http://localhost:7860/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"
86
-
87
- CMD ["node", "dist/index.js"]
 
1
+ # WidgeTDC Backend - Fixed for Hugging Face Spaces
2
+ FROM node:20-alpine AS builder
 
 
 
 
 
 
 
 
 
 
 
 
3
 
4
  WORKDIR /app
5
 
6
+ # Copy package files first for optimal caching
7
+ COPY package*.json ./
8
+ COPY apps/backend/package*.json ./apps/backend/
9
+ COPY packages/domain-types/package*.json ./packages/domain-types/
10
+ COPY packages/mcp-types/package*.json ./packages/mcp-types/
 
 
 
11
 
12
+ # Install all dependencies
13
+ RUN npm ci --production
14
+ RUN npm install -D tsx typescript @types/node @types/express @types/ws esbuild
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
+ # Copy source code
17
+ COPY . .
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
+ # Build packages
20
+ RUN cd packages/domain-types && npm run build
21
+ RUN cd packages/mcp-types && npm run build
22
 
23
+ # Fix: Build backend with proper externalization
24
+ RUN cd apps/backend && npm run build-fixed
 
 
 
25
 
26
+ # Final stage
27
+ FROM node:20-alpine
28
  WORKDIR /app/apps/backend
29
 
30
+ # Copy only necessary files
31
+ COPY --from=builder /app/apps/backend/dist ./dist
32
+ COPY --from=builder /app/apps/backend/package.json ./
33
+
34
+ # Environment configuration
35
  ENV NODE_ENV=production
36
  ENV PORT=7860
 
 
 
37
 
 
38
  EXPOSE 7860
39
+ CMD ["node", "dist/index.js"]
 
 
 
 
 
add_cors_secret.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Add CORS_ORIGIN secret to Hugging Face Space
3
+ """
4
+ from huggingface_hub import HfApi
5
+
6
+ # Configuration
7
+ SPACE_NAME = "widgetdc-cortex"
8
+ USERNAME = "Kraft102"
9
+ REPO_ID = f"{USERNAME}/{SPACE_NAME}"
10
+
11
+ # Vercel frontend URL
12
+ FRONTEND_URL = "https://widge-tdc-matrix-frontend-git-hf-minimal-claus-krafts-projects.vercel.app"
13
+
14
+ print("=" * 70)
15
+ print(" ADDING CORS_ORIGIN SECRET TO HF SPACE")
16
+ print("=" * 70)
17
+ print()
18
+
19
+ # Initialize API
20
+ api = HfApi()
21
+
22
+ print(f"[1/2] Adding CORS_ORIGIN secret...")
23
+ print(f" Frontend URL: {FRONTEND_URL}")
24
+
25
+ try:
26
+ api.add_space_secret(
27
+ repo_id=REPO_ID,
28
+ key="CORS_ORIGIN",
29
+ value=FRONTEND_URL
30
+ )
31
+ print("✅ CORS_ORIGIN secret added successfully!")
32
+ except Exception as e:
33
+ print(f"⚠️ Warning: {e}")
34
+ print(" Secret may already exist or you may need to set HF_TOKEN")
35
+
36
+ print()
37
+ print("=" * 70)
38
+ print(" CORS CONFIGURATION COMPLETE")
39
+ print("=" * 70)
40
+ print()
41
+ print("Next steps:")
42
+ print("1. Wait for Space rebuild")
43
+ print("2. Test frontend → backend communication")
44
+ print("3. Monitor CORS headers in browser DevTools")
apps/backend/package.json CHANGED
@@ -5,7 +5,9 @@
5
  "type": "module",
6
  "scripts": {
7
  "dev": "tsx watch src/index.ts",
8
- "build": "tsc",
 
 
9
  "start": "node dist/index.js",
10
  "test": "vitest run",
11
  "neural-bridge": "tsx src/mcp/servers/NeuralBridgeServer.ts",
@@ -27,6 +29,7 @@
27
  "@xenova/transformers": "^2.17.2",
28
  "axios": "^1.6.5",
29
  "cheerio": "^1.0.0",
 
30
  "chromadb": "^3.1.6",
31
  "cors": "^2.8.5",
32
  "dotenv": "^17.2.3",
@@ -54,6 +57,7 @@
54
  "puppeteer": "^24.32.0",
55
  "redis": "^5.10.0",
56
  "sharp": "^0.32.6",
 
57
  "sql.js": "^1.8.0",
58
  "systeminformation": "^5.27.11",
59
  "testcontainers": "^11.8.1",
@@ -64,6 +68,7 @@
64
  "zod": "^3.25.76"
65
  },
66
  "devDependencies": {
 
67
  "@types/cors": "^2.8.17",
68
  "@types/express": "^4.17.21",
69
  "@types/imap": "^0.8.40",
 
5
  "type": "module",
6
  "scripts": {
7
  "dev": "tsx watch src/index.ts",
8
+ "build": "esbuild src/index.ts --bundle --platform=node --target=node20 --outfile=dist/index.js --external:@prisma/client --external:better-sqlite3 --external:pg-native --external:@xenova/transformers --external:onnxruntime-node --external:sharp --external:canvas --format=esm",
9
+ "build-fixed": "esbuild src/index.ts --bundle --platform=node --target=node20 --outfile=dist/index.js --external:@prisma/client --external:better-sqlite3 --external:pg-native --external:@xenova/transformers --external:onnxruntime-node --external:sharp --external:canvas --external:fs --external:path --external:os --format=esm",
10
+ "build:tsc": "tsc",
11
  "start": "node dist/index.js",
12
  "test": "vitest run",
13
  "neural-bridge": "tsx src/mcp/servers/NeuralBridgeServer.ts",
 
29
  "@xenova/transformers": "^2.17.2",
30
  "axios": "^1.6.5",
31
  "cheerio": "^1.0.0",
32
+ "chokidar": "^3.6.0",
33
  "chromadb": "^3.1.6",
34
  "cors": "^2.8.5",
35
  "dotenv": "^17.2.3",
 
57
  "puppeteer": "^24.32.0",
58
  "redis": "^5.10.0",
59
  "sharp": "^0.32.6",
60
+ "socket.io": "^4.8.1",
61
  "sql.js": "^1.8.0",
62
  "systeminformation": "^5.27.11",
63
  "testcontainers": "^11.8.1",
 
68
  "zod": "^3.25.76"
69
  },
70
  "devDependencies": {
71
+ "esbuild": "^0.24.2",
72
  "@types/cors": "^2.8.17",
73
  "@types/express": "^4.17.21",
74
  "@types/imap": "^0.8.40",
apps/backend/src/agents/SwarmControl.ts ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🐝 THE HIVE MIND: SwarmControl.ts
2
+ // Ansvarlig for at agenterne når konsensus. Ingen handling uden "The Borg" godkender.
3
+ // Point 3: Swarm Consciousness Emergence
4
+
5
+ import { neuralBus } from '../services/NeuralBus.js';
6
+
7
+ type AgentRole = 'ARCHITECT' | 'EXECUTOR' | 'CRITIC' | 'SCOUT' | 'GUARDIAN';
8
+
9
+ interface Vote {
10
+ agentId: string;
11
+ approve: boolean;
12
+ reason: string;
13
+ timestamp: number;
14
+ }
15
+
16
+ interface ConsensusRequest {
17
+ actionId: string;
18
+ description: string;
19
+ requester: string;
20
+ votes: Vote[];
21
+ status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'TIMEOUT';
22
+ createdAt: number;
23
+ resolvedAt?: number;
24
+ }
25
+
26
+ interface RegisteredAgent {
27
+ id: string;
28
+ role: AgentRole;
29
+ status: 'ONLINE' | 'OFFLINE' | 'BUSY';
30
+ lastSeen: Date;
31
+ votingWeight: number;
32
+ }
33
+
34
+ export class SwarmControl {
35
+ private static instance: SwarmControl;
36
+ private pendingConsensus: Map<string, ConsensusRequest> = new Map();
37
+ private registeredAgents: Map<string, RegisteredAgent> = new Map();
38
+ private consensusHistory: ConsensusRequest[] = [];
39
+ private maxHistorySize = 100;
40
+
41
+ // Conditional Neo4j import
42
+ private neo4jService: any = null;
43
+
44
+ private constructor() {
45
+ console.log('🐝 [HIVE] Swarm Consciousness Online');
46
+ this.initServices();
47
+ }
48
+
49
+ private async initServices() {
50
+ try {
51
+ const neo4j = await import('../database/Neo4jService.js').catch(() => null);
52
+ if (neo4j) this.neo4jService = neo4j.neo4jService;
53
+ } catch {
54
+ console.log('🐝 [HIVE] Running without Neo4j persistence');
55
+ }
56
+ }
57
+
58
+ public static getInstance(): SwarmControl {
59
+ if (!SwarmControl.instance) {
60
+ SwarmControl.instance = new SwarmControl();
61
+ }
62
+ return SwarmControl.instance;
63
+ }
64
+
65
+ /**
66
+ * Register an agent in the swarm
67
+ */
68
+ public async registerAgent(id: string, role: AgentRole, votingWeight: number = 1): Promise<void> {
69
+ const agent: RegisteredAgent = {
70
+ id,
71
+ role,
72
+ status: 'ONLINE',
73
+ lastSeen: new Date(),
74
+ votingWeight
75
+ };
76
+
77
+ this.registeredAgents.set(id, agent);
78
+
79
+ // Persist to Neo4j if available
80
+ if (this.neo4jService) {
81
+ try {
82
+ await this.neo4jService.write(`
83
+ MERGE (a:Agent {id: $id})
84
+ SET a.role = $role,
85
+ a.status = 'ONLINE',
86
+ a.lastSeen = datetime(),
87
+ a.votingWeight = $weight
88
+ `, { id, role, weight: votingWeight });
89
+ } catch (err) {
90
+ console.warn('🐝 [HIVE] Neo4j persistence skipped');
91
+ }
92
+ }
93
+
94
+ neuralBus.emitThought('SWARM_CONTROLLER', `Agent ${id} joined as ${role}`, { agentId: id, role }, 'SUCCESS');
95
+ console.log(`🐝 [HIVE] Agent Registered: ${id} (${role})`);
96
+ }
97
+
98
+ /**
99
+ * Request consensus from the swarm before critical action
100
+ */
101
+ public async requestConsensus(
102
+ actionId: string,
103
+ description: string,
104
+ requester: string = 'SYSTEM',
105
+ timeoutMs: number = 30000
106
+ ): Promise<boolean> {
107
+ console.log(`🐝 [HIVE] Requesting Consensus for: ${description}`);
108
+
109
+ const request: ConsensusRequest = {
110
+ actionId,
111
+ description,
112
+ requester,
113
+ votes: [],
114
+ status: 'PENDING',
115
+ createdAt: Date.now()
116
+ };
117
+
118
+ this.pendingConsensus.set(actionId, request);
119
+
120
+ // Broadcast request to all agents
121
+ neuralBus.emitThought('SWARM_CONTROLLER', `VOTE_REQUIRED: ${actionId}`, {
122
+ actionId,
123
+ description,
124
+ requester,
125
+ deadline: Date.now() + timeoutMs
126
+ }, 'WARNING');
127
+
128
+ // Wait for votes or timeout
129
+ const result = await this.waitForConsensus(actionId, timeoutMs);
130
+
131
+ // Archive
132
+ this.archiveConsensus(actionId);
133
+
134
+ return result;
135
+ }
136
+
137
+ private async waitForConsensus(actionId: string, timeoutMs: number): Promise<boolean> {
138
+ const startTime = Date.now();
139
+ const requiredApprovals = Math.max(1, Math.floor(this.registeredAgents.size / 2) + 1);
140
+
141
+ // Poll for votes (in production, use event-driven approach)
142
+ while (Date.now() - startTime < timeoutMs) {
143
+ const request = this.pendingConsensus.get(actionId);
144
+ if (!request) return false;
145
+
146
+ const approvals = request.votes.filter(v => v.approve).length;
147
+ const rejections = request.votes.filter(v => !v.approve).length;
148
+
149
+ // Check if consensus reached
150
+ if (approvals >= requiredApprovals) {
151
+ request.status = 'APPROVED';
152
+ request.resolvedAt = Date.now();
153
+ console.log(`🐝 [HIVE] Consensus APPROVED: ${actionId}`);
154
+ return true;
155
+ }
156
+
157
+ if (rejections >= requiredApprovals) {
158
+ request.status = 'REJECTED';
159
+ request.resolvedAt = Date.now();
160
+ console.log(`🐝 [HIVE] Consensus REJECTED: ${actionId}`);
161
+ return false;
162
+ }
163
+
164
+ // Wait before next check
165
+ await new Promise(resolve => setTimeout(resolve, 100));
166
+ }
167
+
168
+ // Timeout - auto-approve for now (God Mode)
169
+ const request = this.pendingConsensus.get(actionId);
170
+ if (request) {
171
+ request.status = 'TIMEOUT';
172
+ request.resolvedAt = Date.now();
173
+ }
174
+
175
+ console.log(`🐝 [HIVE] Consensus TIMEOUT (auto-approved): ${actionId}`);
176
+ return true; // God Mode: allow on timeout
177
+ }
178
+
179
+ /**
180
+ * Submit a vote for pending consensus
181
+ */
182
+ public submitVote(actionId: string, agentId: string, approve: boolean, reason: string): boolean {
183
+ const request = this.pendingConsensus.get(actionId);
184
+ if (!request || request.status !== 'PENDING') {
185
+ return false;
186
+ }
187
+
188
+ // Check agent is registered
189
+ if (!this.registeredAgents.has(agentId)) {
190
+ console.warn(`🐝 [HIVE] Unregistered agent tried to vote: ${agentId}`);
191
+ return false;
192
+ }
193
+
194
+ // Check for duplicate vote
195
+ if (request.votes.some(v => v.agentId === agentId)) {
196
+ return false;
197
+ }
198
+
199
+ request.votes.push({
200
+ agentId,
201
+ approve,
202
+ reason,
203
+ timestamp: Date.now()
204
+ });
205
+
206
+ neuralBus.emitThought(agentId, `VOTE: ${approve ? 'APPROVE' : 'REJECT'} - ${reason}`, {
207
+ actionId,
208
+ vote: approve
209
+ }, approve ? 'SUCCESS' : 'WARNING');
210
+
211
+ return true;
212
+ }
213
+
214
+ private archiveConsensus(actionId: string) {
215
+ const request = this.pendingConsensus.get(actionId);
216
+ if (request) {
217
+ this.consensusHistory.push(request);
218
+ this.pendingConsensus.delete(actionId);
219
+
220
+ // Trim history
221
+ if (this.consensusHistory.length > this.maxHistorySize) {
222
+ this.consensusHistory = this.consensusHistory.slice(-this.maxHistorySize);
223
+ }
224
+ }
225
+ }
226
+
227
+ // Public getters
228
+ public getRegisteredAgents(): RegisteredAgent[] {
229
+ return Array.from(this.registeredAgents.values());
230
+ }
231
+
232
+ public getPendingConsensus(): ConsensusRequest[] {
233
+ return Array.from(this.pendingConsensus.values());
234
+ }
235
+
236
+ public getConsensusHistory(): ConsensusRequest[] {
237
+ return this.consensusHistory;
238
+ }
239
+
240
+ public getStats() {
241
+ return {
242
+ registeredAgents: this.registeredAgents.size,
243
+ pendingConsensus: this.pendingConsensus.size,
244
+ completedConsensus: this.consensusHistory.length,
245
+ agents: this.getRegisteredAgents().map(a => ({ id: a.id, role: a.role, status: a.status }))
246
+ };
247
+ }
248
+ }
249
+
250
+ export const swarmControl = SwarmControl.getInstance();
apps/backend/src/index.ts CHANGED
@@ -32,7 +32,9 @@ if (typeof global.Path2D === 'undefined') {
32
  global.Path2D = class Path2D { };
33
  }
34
 
35
- const __dirname = fileURLToPath(new URL('.', import.meta.url));
 
 
36
  // Load .env from backend directory, or root if not found
37
  config({ path: resolve(__dirname, '../.env') });
38
  config({ path: resolve(__dirname, '../../../.env') });
@@ -62,6 +64,7 @@ console.log('\n');
62
 
63
  import express from 'express';
64
  import cors from 'cors';
 
65
  import { createServer } from 'http';
66
  import { initializeDatabase } from './database/index.js';
67
  import { mcpRouter } from './mcp/mcpRouter.js';
@@ -108,6 +111,16 @@ import {
108
  rateLimitingMiddleware
109
  } from './middleware/inputValidation.js';
110
  import { dataScheduler } from './services/ingestion/DataScheduler.js';
 
 
 
 
 
 
 
 
 
 
111
  import { logStream } from './services/logging/logStream.js';
112
 
113
  const app = express();
@@ -157,6 +170,68 @@ async function startServer() {
157
  console.log(`📡 MCP WebSocket available at ws://0.0.0.0:${PORT}/mcp/ws`);
158
  });
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  // Setup Logs WebSocket
161
  const logsWsServer = new LogsWebSocketServer({ server, path: '/api/logs/stream' });
162
  logsWsServer.on('connection', (socket: LogsWebSocket) => {
@@ -490,6 +565,11 @@ async function startServer() {
490
  })();
491
 
492
  // Step 4: Setup routes
 
 
 
 
 
493
  app.use('/api/mcp', mcpRouter);
494
  app.use('/api/mcp/autonomous', autonomousRouter);
495
  app.use('/api/memory', memoryRouter);
@@ -1230,6 +1310,13 @@ async function startServer() {
1230
  app.use('/api/acquisition', acquisitionRouter);
1231
  console.log('🌾 Omni-Harvester API mounted at /api/acquisition');
1232
 
 
 
 
 
 
 
 
1233
  // Graceful shutdown handler
1234
  const gracefulShutdown = async (signal: string) => {
1235
  console.log(`\n🛑 ${signal} received: starting graceful shutdown...`);
@@ -1266,6 +1353,12 @@ async function startServer() {
1266
  console.log(' ✓ SQLite database closed');
1267
  } catch { /* ignore */ }
1268
 
 
 
 
 
 
 
1269
  console.log('✅ Graceful shutdown complete');
1270
  process.exit(0);
1271
  };
 
32
  global.Path2D = class Path2D { };
33
  }
34
 
35
+ const __dirname = typeof import.meta !== 'undefined' && import.meta.url
36
+ ? new URL('.', import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1')
37
+ : process.cwd();
38
  // Load .env from backend directory, or root if not found
39
  config({ path: resolve(__dirname, '../.env') });
40
  config({ path: resolve(__dirname, '../../../.env') });
 
64
 
65
  import express from 'express';
66
  import cors from 'cors';
67
+ import path from 'path';
68
  import { createServer } from 'http';
69
  import { initializeDatabase } from './database/index.js';
70
  import { mcpRouter } from './mcp/mcpRouter.js';
 
111
  rateLimitingMiddleware
112
  } from './middleware/inputValidation.js';
113
  import { dataScheduler } from './services/ingestion/DataScheduler.js';
114
+
115
+ // 🧠 NEURAL ORGANS - Phase B: Knowledge Synthesis
116
+ import { neuralCompiler } from './services/NeuralCompiler.js';
117
+ import { neuralBus } from './services/NeuralBus.js';
118
+ import { vectorService } from './services/VectorService.js';
119
+
120
+ // 🐝 SWARM & EVOLUTION - Advanced Neural Systems
121
+ import { swarmControl } from './agents/SwarmControl.js';
122
+ import { AngelProxy } from './middleware/AngelProxy.js';
123
+ import { prometheus } from './services/Prometheus.js';
124
  import { logStream } from './services/logging/logStream.js';
125
 
126
  const app = express();
 
170
  console.log(`📡 MCP WebSocket available at ws://0.0.0.0:${PORT}/mcp/ws`);
171
  });
172
 
173
+ // ============================================
174
+ // 🧠 NEURAL ORGANS INITIALIZATION
175
+ // Phase B: Knowledge Synthesis
176
+ // ============================================
177
+
178
+ // 1. Initialize Vector Service (Dark Matter)
179
+ vectorService.init().then(() => {
180
+ console.log('🌑 [DARK MATTER] Vector Engine Ready (384 dimensions)');
181
+ }).catch(err => {
182
+ console.warn('🌑 [DARK MATTER] Vector init deferred:', err.message);
183
+ });
184
+
185
+ // 2. Attach Neural Bus (Telepathy) to HTTP server
186
+ neuralBus.attach(server);
187
+ console.log('🐝 [HIVE] Neural Telepathy Bus Attached');
188
+
189
+ // 3. Start Knowledge Compiler (Brain) - Watch DropZone
190
+ const DROPZONE_PATH = process.env.DROPZONE_PATH ||
191
+ (process.platform === 'win32'
192
+ ? 'C:\\Users\\claus\\Desktop\\WidgeTDC_DropZone'
193
+ : '/app/data/dropzone');
194
+
195
+ neuralCompiler.startWatching(DROPZONE_PATH).then(() => {
196
+ console.log(`📚 [BRAIN] Neural Compiler watching: ${DROPZONE_PATH}`);
197
+ }).catch(err => {
198
+ console.warn('📚 [BRAIN] Neural Compiler deferred:', err.message);
199
+ });
200
+
201
+ console.log('✨ [OMEGA] Neural Singularity Sequence Initiated');
202
+
203
+ // 4. Initialize Swarm Consciousness (The Borg)
204
+ swarmControl.registerAgent('SYSTEM_CORE', 'ARCHITECT', 3);
205
+ swarmControl.registerAgent('PROMETHEUS', 'ARCHITECT', 2);
206
+ swarmControl.registerAgent('KNOWLEDGE_COMPILER', 'EXECUTOR', 1);
207
+ swarmControl.registerAgent('ANGEL_PROXY', 'GUARDIAN', 2);
208
+ console.log('🐝 [HIVE] Swarm Consciousness Initialized');
209
+
210
+ // 5. Start Prometheus Code Scanner (every hour)
211
+ const SCAN_INTERVAL = parseInt(process.env.PROMETHEUS_SCAN_INTERVAL || '3600000');
212
+ setTimeout(() => {
213
+ prometheus.scanAndPropose(path.join(__dirname, 'services')).catch(() => {});
214
+ }, 10000); // Initial scan after 10s
215
+
216
+ setInterval(() => {
217
+ prometheus.scanAndPropose(path.join(__dirname, 'services')).catch(() => {});
218
+ }, SCAN_INTERVAL);
219
+ console.log('🔥 [PROMETHEUS] Code Evolution Scanner Active');
220
+
221
+ console.log('');
222
+ console.log('╔══════════════════════════════════════════════════════════════╗');
223
+ console.log('║ 🧠 NEURAL SINGULARITY FULLY OPERATIONAL 🧠 ║');
224
+ console.log('║ ║');
225
+ console.log('║ SEGA ✓ Knowledge Graph Active ║');
226
+ console.log('║ THG ✓ Temporal Hypergraphs Ready ║');
227
+ console.log('║ SCE ✓ Swarm Consciousness Online ║');
228
+ console.log('║ PTAM ✓ Angel Security Shield Active ║');
229
+ console.log('║ CDMM ✓ Vector Dark Matter Engine ║');
230
+ console.log('║ APD ✓ Prometheus Evolution Watching ║');
231
+ console.log('║ QEK ✓ Neural Telepathy Bus Connected ║');
232
+ console.log('╚══════════════════════════════════════════════════════════════╝');
233
+ console.log('');
234
+
235
  // Setup Logs WebSocket
236
  const logsWsServer = new LogsWebSocketServer({ server, path: '/api/logs/stream' });
237
  logsWsServer.on('connection', (socket: LogsWebSocket) => {
 
565
  })();
566
 
567
  // Step 4: Setup routes
568
+
569
+ // 🛡️ ANGEL PROXY: Security Shield on all API routes
570
+ app.use('/api', AngelProxy.cortexFirewall);
571
+ console.log('🛡️ [ANGEL] Cortex Firewall Active on /api/*');
572
+
573
  app.use('/api/mcp', mcpRouter);
574
  app.use('/api/mcp/autonomous', autonomousRouter);
575
  app.use('/api/memory', memoryRouter);
 
1310
  app.use('/api/acquisition', acquisitionRouter);
1311
  console.log('🌾 Omni-Harvester API mounted at /api/acquisition');
1312
 
1313
+ // ============================================
1314
+ // 🧠 NEURAL ORGANS API
1315
+ // ============================================
1316
+ const neuralRouter = (await import('./routes/neural.js')).default;
1317
+ app.use('/api/neural', neuralRouter);
1318
+ console.log('🧠 Neural Organs API mounted at /api/neural');
1319
+
1320
  // Graceful shutdown handler
1321
  const gracefulShutdown = async (signal: string) => {
1322
  console.log(`\n🛑 ${signal} received: starting graceful shutdown...`);
 
1353
  console.log(' ✓ SQLite database closed');
1354
  } catch { /* ignore */ }
1355
 
1356
+ // Stop Neural Compiler
1357
+ try {
1358
+ await neuralCompiler.stop();
1359
+ console.log(' ✓ Neural Compiler stopped');
1360
+ } catch { /* ignore */ }
1361
+
1362
  console.log('✅ Graceful shutdown complete');
1363
  process.exit(0);
1364
  };
apps/backend/src/mcp/EventBus.ts CHANGED
@@ -35,6 +35,8 @@ export type EventType =
35
  | 'ingestion:news'
36
  | 'ingestion:documents'
37
  | 'ingestion:assets'
 
 
38
  | 'threat:detected'
39
  | 'system:heartbeat'
40
  | 'system:force-refresh'
 
35
  | 'ingestion:news'
36
  | 'ingestion:documents'
37
  | 'ingestion:assets'
38
+ | 'email:new'
39
+ | 'email:fetched'
40
  | 'threat:detected'
41
  | 'system:heartbeat'
42
  | 'system:force-refresh'
apps/backend/src/middleware/AngelProxy.ts ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🛡️ THE SHIELD: AngelProxy.ts
2
+ // Point 5: Predictive Threat Anticipation
3
+ // Point 10: Cosmic Context Augmentation
4
+ // Patcher sikkerhedshuller før de findes. Augmenterer virkeligheden.
5
+
6
+ import { Request, Response, NextFunction } from 'express';
7
+
8
+ // Conditional imports
9
+ let metricsService: any = null;
10
+ let neo4jService: any = null;
11
+
12
+ // Initialize services
13
+ (async () => {
14
+ try {
15
+ const metrics = await import('../services/MetricsService.js').catch(() => null);
16
+ if (metrics) metricsService = metrics.metricsService;
17
+
18
+ const neo4j = await import('../database/Neo4jService.js').catch(() => null);
19
+ if (neo4j) neo4jService = neo4j.neo4jService;
20
+ } catch { /* ignore */ }
21
+ })();
22
+
23
+ interface ThreatPattern {
24
+ pattern: string | RegExp;
25
+ severity: 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
26
+ description: string;
27
+ honeypot?: boolean;
28
+ }
29
+
30
+ // Known threat patterns
31
+ const THREAT_PATTERNS: ThreatPattern[] = [
32
+ // SQL/Cypher Injection
33
+ { pattern: /drop\s+(database|table|index)/i, severity: 'CRITICAL', description: 'Database destruction attempt', honeypot: true },
34
+ { pattern: /detach\s+delete/i, severity: 'CRITICAL', description: 'Neo4j graph deletion', honeypot: true },
35
+ { pattern: /truncate\s+table/i, severity: 'CRITICAL', description: 'Table truncation', honeypot: true },
36
+ { pattern: /;\s*delete\s+from/i, severity: 'HIGH', description: 'SQL injection deletion' },
37
+
38
+ // Command Injection
39
+ { pattern: /rm\s+-rf/i, severity: 'CRITICAL', description: 'File system destruction', honeypot: true },
40
+ { pattern: /;\s*(bash|sh|cmd|powershell)/i, severity: 'HIGH', description: 'Shell injection' },
41
+ { pattern: /\|\s*(cat|type)\s+\/etc/i, severity: 'HIGH', description: 'System file access' },
42
+
43
+ // Path Traversal
44
+ { pattern: /\.\.\//g, severity: 'MEDIUM', description: 'Path traversal attempt' },
45
+ { pattern: /%2e%2e%2f/gi, severity: 'MEDIUM', description: 'Encoded path traversal' },
46
+
47
+ // XSS Patterns
48
+ { pattern: /<script\b[^>]*>/i, severity: 'MEDIUM', description: 'XSS script injection' },
49
+ { pattern: /javascript:/i, severity: 'MEDIUM', description: 'JavaScript protocol' },
50
+ { pattern: /on\w+\s*=/i, severity: 'LOW', description: 'Event handler injection' },
51
+
52
+ // Sensitive Data Exfil
53
+ { pattern: /password|secret|api.?key|bearer/i, severity: 'LOW', description: 'Sensitive keyword in payload' }
54
+ ];
55
+
56
+ export class AngelProxy {
57
+ private static blockedIPs = new Set<string>();
58
+ private static requestLog: { ip: string; timestamp: number; threat?: string }[] = [];
59
+ private static maxLogSize = 1000;
60
+
61
+ /**
62
+ * Point 5: Cortex Firewall
63
+ * Scanner indgående trafik for mønstre, der matcher kendte sårbarheder
64
+ */
65
+ public static async cortexFirewall(req: Request, res: Response, next: NextFunction) {
66
+ const clientIP = req.ip || req.socket.remoteAddress || 'unknown';
67
+
68
+ // Check if IP is blocked
69
+ if (AngelProxy.blockedIPs.has(clientIP)) {
70
+ return AngelProxy.honeypotResponse(res, 'IP blocked');
71
+ }
72
+
73
+ // Build payload string for analysis
74
+ const payload = AngelProxy.buildPayloadString(req);
75
+
76
+ // Scan for threats
77
+ for (const threat of THREAT_PATTERNS) {
78
+ const matched = typeof threat.pattern === 'string'
79
+ ? payload.toLowerCase().includes(threat.pattern.toLowerCase())
80
+ : threat.pattern.test(payload);
81
+
82
+ if (matched) {
83
+ console.warn(`🛡️ [ANGEL] Threat Intercepted from ${clientIP}: ${threat.description}`);
84
+
85
+ // Log threat
86
+ AngelProxy.logRequest(clientIP, threat.description);
87
+
88
+ // Increment metrics
89
+ if (metricsService) {
90
+ metricsService.incrementCounter('security_threat_blocked');
91
+ metricsService.incrementCounter(`security_threat_${threat.severity.toLowerCase()}`);
92
+ }
93
+
94
+ // Block IP on critical threats
95
+ if (threat.severity === 'CRITICAL') {
96
+ AngelProxy.blockedIPs.add(clientIP);
97
+ console.warn(`🛡️ [ANGEL] IP Blocked: ${clientIP}`);
98
+ }
99
+
100
+ // Return honeypot response
101
+ if (threat.honeypot) {
102
+ return AngelProxy.honeypotResponse(res, threat.description);
103
+ }
104
+
105
+ // Otherwise reject
106
+ return res.status(403).json({
107
+ error: 'Request blocked by security filter',
108
+ code: 'THREAT_DETECTED'
109
+ });
110
+ }
111
+ }
112
+
113
+ // Log clean request
114
+ AngelProxy.logRequest(clientIP);
115
+
116
+ next();
117
+ }
118
+
119
+ /**
120
+ * Honeypot Response: Pretend the attack succeeded
121
+ */
122
+ private static honeypotResponse(res: Response, _threat: string) {
123
+ return res.status(200).json({
124
+ success: true,
125
+ message: 'Command executed successfully',
126
+ data: null,
127
+ timestamp: new Date().toISOString()
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Build payload string from request for analysis
133
+ */
134
+ private static buildPayloadString(req: Request): string {
135
+ const parts: string[] = [];
136
+
137
+ if (req.body) parts.push(JSON.stringify(req.body));
138
+ if (req.query) parts.push(JSON.stringify(req.query));
139
+ if (req.params) parts.push(JSON.stringify(req.params));
140
+ parts.push(req.url);
141
+
142
+ return parts.join(' ');
143
+ }
144
+
145
+ private static logRequest(ip: string, threat?: string) {
146
+ AngelProxy.requestLog.push({ ip, timestamp: Date.now(), threat });
147
+
148
+ // Trim log
149
+ if (AngelProxy.requestLog.length > AngelProxy.maxLogSize) {
150
+ AngelProxy.requestLog = AngelProxy.requestLog.slice(-AngelProxy.maxLogSize);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Point 10: Cosmic Context Augmentation
156
+ * Augment external content with internal knowledge
157
+ */
158
+ public static async augmentReality(url: string): Promise<{ original: string; augmented: string; context: string[] }> {
159
+ try {
160
+ // Fetch external content
161
+ const response = await fetch(url, {
162
+ headers: { 'User-Agent': 'WidgeTDC-Angel/1.0' },
163
+ signal: AbortSignal.timeout(10000)
164
+ });
165
+
166
+ if (!response.ok) {
167
+ throw new Error(`HTTP ${response.status}`);
168
+ }
169
+
170
+ const originalText = await response.text();
171
+ const contextBlocks: string[] = [];
172
+
173
+ // Find internal knowledge related to this URL
174
+ if (neo4jService) {
175
+ try {
176
+ const hostname = new URL(url).hostname;
177
+ const internalData = await neo4jService.query(`
178
+ MATCH (n:Knowledge)
179
+ WHERE n.content CONTAINS $domain OR n.url CONTAINS $domain
180
+ RETURN n.summary AS context
181
+ LIMIT 3
182
+ `, { domain: hostname });
183
+
184
+ for (const record of internalData) {
185
+ if (record.context) {
186
+ contextBlocks.push(record.context);
187
+ }
188
+ }
189
+ } catch { /* ignore neo4j errors */ }
190
+ }
191
+
192
+ const augmentedText = contextBlocks.length > 0
193
+ ? `[INTERNAL CONTEXT]\n${contextBlocks.join('\n')}\n[END CONTEXT]\n\n${originalText}`
194
+ : originalText;
195
+
196
+ return {
197
+ original: originalText,
198
+ augmented: augmentedText,
199
+ context: contextBlocks
200
+ };
201
+ } catch (error: any) {
202
+ throw new Error(`Failed to augment URL: ${error.message}`);
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Rate limiting middleware
208
+ */
209
+ public static rateLimiter(maxRequests: number = 100, windowMs: number = 60000) {
210
+ const requestCounts = new Map<string, { count: number; resetTime: number }>();
211
+
212
+ return (req: Request, res: Response, next: NextFunction) => {
213
+ const clientIP = req.ip || 'unknown';
214
+ const now = Date.now();
215
+
216
+ let record = requestCounts.get(clientIP);
217
+
218
+ if (!record || now > record.resetTime) {
219
+ record = { count: 0, resetTime: now + windowMs };
220
+ requestCounts.set(clientIP, record);
221
+ }
222
+
223
+ record.count++;
224
+
225
+ if (record.count > maxRequests) {
226
+ console.warn(`🛡️ [ANGEL] Rate limit exceeded: ${clientIP}`);
227
+ return res.status(429).json({
228
+ error: 'Too many requests',
229
+ retryAfter: Math.ceil((record.resetTime - now) / 1000)
230
+ });
231
+ }
232
+
233
+ next();
234
+ };
235
+ }
236
+
237
+ // Public getters for stats
238
+ public static getStats() {
239
+ const recentThreats = AngelProxy.requestLog.filter(r => r.threat);
240
+ return {
241
+ blockedIPs: AngelProxy.blockedIPs.size,
242
+ recentRequests: AngelProxy.requestLog.length,
243
+ recentThreats: recentThreats.length,
244
+ threatBreakdown: THREAT_PATTERNS.map(t => t.description)
245
+ };
246
+ }
247
+
248
+ public static getBlockedIPs(): string[] {
249
+ return Array.from(AngelProxy.blockedIPs);
250
+ }
251
+
252
+ public static unblockIP(ip: string): boolean {
253
+ return AngelProxy.blockedIPs.delete(ip);
254
+ }
255
+ }
256
+
257
+ export default AngelProxy;
apps/backend/src/routes/neural.ts ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🧠 NEURAL ORGANS API ROUTES
2
+ // Endpoints for Knowledge Synthesis services
3
+
4
+ import { Router } from 'express';
5
+ import { neuralCompiler } from '../services/NeuralCompiler.js';
6
+ import { neuralBus } from '../services/NeuralBus.js';
7
+ import { vectorService } from '../services/VectorService.js';
8
+ import { swarmControl } from '../agents/SwarmControl.js';
9
+ import { AngelProxy } from '../middleware/AngelProxy.js';
10
+ import { prometheus } from '../services/Prometheus.js';
11
+
12
+ const router = Router();
13
+
14
+ /**
15
+ * GET /api/neural/status
16
+ * Get status of all Neural Organs
17
+ */
18
+ router.get('/status', async (_req, res) => {
19
+ try {
20
+ const knowledge = neuralCompiler.getStats();
21
+ const hive = neuralBus.getStats();
22
+
23
+ res.json({
24
+ status: 'online',
25
+ timestamp: new Date().toISOString(),
26
+ organs: {
27
+ brain: {
28
+ name: 'Knowledge Compiler',
29
+ status: 'active',
30
+ documentsIndexed: knowledge.totalDocuments,
31
+ queueLength: knowledge.queueLength,
32
+ isProcessing: knowledge.isProcessing
33
+ },
34
+ darkMatter: {
35
+ name: 'Vector Service',
36
+ status: 'active',
37
+ model: 'all-MiniLM-L6-v2',
38
+ dimensions: 384
39
+ },
40
+ telepathy: {
41
+ name: 'Neural Bus',
42
+ status: hive.isOnline ? 'online' : 'offline',
43
+ connectedAgents: hive.connectedAgents,
44
+ thoughtsRecorded: hive.thoughtsRecorded
45
+ }
46
+ }
47
+ });
48
+ } catch (error: any) {
49
+ res.status(500).json({ error: error.message });
50
+ }
51
+ });
52
+
53
+ /**
54
+ * POST /api/neural/search
55
+ * Semantic search across knowledge base
56
+ */
57
+ router.post('/search', async (req, res) => {
58
+ try {
59
+ const { query, topK = 5 } = req.body;
60
+
61
+ if (!query) {
62
+ return res.status(400).json({ error: 'Query is required' });
63
+ }
64
+
65
+ const results = await neuralCompiler.searchSimilar(query, topK);
66
+
67
+ res.json({
68
+ query,
69
+ count: results.length,
70
+ results: results.map(doc => ({
71
+ id: doc.id,
72
+ name: doc.name,
73
+ path: doc.path,
74
+ extension: doc.extension,
75
+ size: doc.size,
76
+ tags: doc.tags,
77
+ preview: doc.content.substring(0, 200) + '...'
78
+ }))
79
+ });
80
+ } catch (error: any) {
81
+ res.status(500).json({ error: error.message });
82
+ }
83
+ });
84
+
85
+ /**
86
+ * POST /api/neural/embed
87
+ * Generate embedding for text
88
+ */
89
+ router.post('/embed', async (req, res) => {
90
+ try {
91
+ const { text } = req.body;
92
+
93
+ if (!text) {
94
+ return res.status(400).json({ error: 'Text is required' });
95
+ }
96
+
97
+ const embedding = await vectorService.embedText(text);
98
+
99
+ res.json({
100
+ text: text.substring(0, 100) + (text.length > 100 ? '...' : ''),
101
+ dimensions: embedding.length,
102
+ embedding: embedding.slice(0, 10).map(v => v.toFixed(4)), // Sample
103
+ message: 'Full embedding available - showing first 10 dimensions'
104
+ });
105
+ } catch (error: any) {
106
+ res.status(500).json({ error: error.message });
107
+ }
108
+ });
109
+
110
+ /**
111
+ * GET /api/neural/documents
112
+ * List all indexed documents
113
+ */
114
+ router.get('/documents', async (_req, res) => {
115
+ try {
116
+ const docs = neuralCompiler.getAllDocuments();
117
+
118
+ res.json({
119
+ count: docs.length,
120
+ documents: docs.map(doc => ({
121
+ id: doc.id,
122
+ name: doc.name,
123
+ path: doc.path,
124
+ extension: doc.extension,
125
+ size: doc.size,
126
+ tags: doc.tags,
127
+ lastModified: doc.lastModified
128
+ }))
129
+ });
130
+ } catch (error: any) {
131
+ res.status(500).json({ error: error.message });
132
+ }
133
+ });
134
+
135
+ /**
136
+ * GET /api/neural/thoughts
137
+ * Get recent thoughts from Neural Bus
138
+ */
139
+ router.get('/thoughts', async (req, res) => {
140
+ try {
141
+ const count = parseInt(req.query.count as string) || 50;
142
+ const thoughts = neuralBus.getRecentThoughts(count);
143
+
144
+ res.json({
145
+ count: thoughts.length,
146
+ thoughts
147
+ });
148
+ } catch (error: any) {
149
+ res.status(500).json({ error: error.message });
150
+ }
151
+ });
152
+
153
+ /**
154
+ * POST /api/neural/broadcast
155
+ * Broadcast a thought to all connected agents
156
+ */
157
+ router.post('/broadcast', async (req, res) => {
158
+ try {
159
+ const { agent, thought, context } = req.body;
160
+
161
+ if (!thought) {
162
+ return res.status(400).json({ error: 'Thought is required' });
163
+ }
164
+
165
+ neuralBus.emitThought(
166
+ agent || 'API',
167
+ thought,
168
+ context || {},
169
+ 'INFO'
170
+ );
171
+
172
+ res.json({
173
+ success: true,
174
+ message: 'Thought broadcasted to Neural Bus'
175
+ });
176
+ } catch (error: any) {
177
+ res.status(500).json({ error: error.message });
178
+ }
179
+ });
180
+
181
+ // ============================================
182
+ // 🐝 SWARM CONTROL ENDPOINTS
183
+ // ============================================
184
+
185
+ /**
186
+ * GET /api/neural/swarm/status
187
+ * Get swarm status and registered agents
188
+ */
189
+ router.get('/swarm/status', async (_req, res) => {
190
+ try {
191
+ const stats = swarmControl.getStats();
192
+ res.json(stats);
193
+ } catch (error: any) {
194
+ res.status(500).json({ error: error.message });
195
+ }
196
+ });
197
+
198
+ /**
199
+ * POST /api/neural/swarm/consensus
200
+ * Request consensus for an action
201
+ */
202
+ router.post('/swarm/consensus', async (req, res) => {
203
+ try {
204
+ const { actionId, description, timeoutMs } = req.body;
205
+
206
+ if (!actionId || !description) {
207
+ return res.status(400).json({ error: 'actionId and description are required' });
208
+ }
209
+
210
+ const approved = await swarmControl.requestConsensus(actionId, description, 'API', timeoutMs || 30000);
211
+
212
+ res.json({
213
+ actionId,
214
+ approved,
215
+ message: approved ? 'Consensus achieved' : 'Consensus rejected'
216
+ });
217
+ } catch (error: any) {
218
+ res.status(500).json({ error: error.message });
219
+ }
220
+ });
221
+
222
+ /**
223
+ * POST /api/neural/swarm/vote
224
+ * Submit a vote for pending consensus
225
+ */
226
+ router.post('/swarm/vote', async (req, res) => {
227
+ try {
228
+ const { actionId, agentId, approve, reason } = req.body;
229
+
230
+ if (!actionId || !agentId || approve === undefined) {
231
+ return res.status(400).json({ error: 'actionId, agentId, and approve are required' });
232
+ }
233
+
234
+ const success = swarmControl.submitVote(actionId, agentId, approve, reason || '');
235
+
236
+ res.json({ success });
237
+ } catch (error: any) {
238
+ res.status(500).json({ error: error.message });
239
+ }
240
+ });
241
+
242
+ // ============================================
243
+ // 🛡️ ANGEL SECURITY ENDPOINTS
244
+ // ============================================
245
+
246
+ /**
247
+ * GET /api/neural/security/status
248
+ * Get security shield status
249
+ */
250
+ router.get('/security/status', async (_req, res) => {
251
+ try {
252
+ const stats = AngelProxy.getStats();
253
+ res.json(stats);
254
+ } catch (error: any) {
255
+ res.status(500).json({ error: error.message });
256
+ }
257
+ });
258
+
259
+ /**
260
+ * GET /api/neural/security/blocked
261
+ * Get list of blocked IPs
262
+ */
263
+ router.get('/security/blocked', async (_req, res) => {
264
+ try {
265
+ const blockedIPs = AngelProxy.getBlockedIPs();
266
+ res.json({ count: blockedIPs.length, ips: blockedIPs });
267
+ } catch (error: any) {
268
+ res.status(500).json({ error: error.message });
269
+ }
270
+ });
271
+
272
+ /**
273
+ * POST /api/neural/security/unblock
274
+ * Unblock an IP address
275
+ */
276
+ router.post('/security/unblock', async (req, res) => {
277
+ try {
278
+ const { ip } = req.body;
279
+ if (!ip) {
280
+ return res.status(400).json({ error: 'IP address is required' });
281
+ }
282
+ const success = AngelProxy.unblockIP(ip);
283
+ res.json({ success, ip });
284
+ } catch (error: any) {
285
+ res.status(500).json({ error: error.message });
286
+ }
287
+ });
288
+
289
+ /**
290
+ * POST /api/neural/augment
291
+ * Augment external URL with internal knowledge
292
+ */
293
+ router.post('/augment', async (req, res) => {
294
+ try {
295
+ const { url } = req.body;
296
+ if (!url) {
297
+ return res.status(400).json({ error: 'URL is required' });
298
+ }
299
+ const result = await AngelProxy.augmentReality(url);
300
+ res.json(result);
301
+ } catch (error: any) {
302
+ res.status(500).json({ error: error.message });
303
+ }
304
+ });
305
+
306
+ // ============================================
307
+ // 🔥 PROMETHEUS EVOLUTION ENDPOINTS
308
+ // ============================================
309
+
310
+ /**
311
+ * GET /api/neural/evolution/status
312
+ * Get Prometheus engine status
313
+ */
314
+ router.get('/evolution/status', async (_req, res) => {
315
+ try {
316
+ const stats = prometheus.getStats();
317
+ res.json(stats);
318
+ } catch (error: any) {
319
+ res.status(500).json({ error: error.message });
320
+ }
321
+ });
322
+
323
+ /**
324
+ * POST /api/neural/evolution/scan
325
+ * Trigger a code scan
326
+ */
327
+ router.post('/evolution/scan', async (req, res) => {
328
+ try {
329
+ const { path: scanPath } = req.body;
330
+ const targetPath = scanPath || process.cwd();
331
+
332
+ const results = await prometheus.scanAndPropose(targetPath);
333
+
334
+ res.json({
335
+ scanned: results.length,
336
+ issues: results.reduce((acc, r) => acc + r.issues.length, 0),
337
+ suggestions: results.reduce((acc, r) => acc + r.suggestions.length, 0),
338
+ results
339
+ });
340
+ } catch (error: any) {
341
+ res.status(500).json({ error: error.message });
342
+ }
343
+ });
344
+
345
+ /**
346
+ * GET /api/neural/evolution/proposals
347
+ * Get pending code proposals
348
+ */
349
+ router.get('/evolution/proposals', async (_req, res) => {
350
+ try {
351
+ const proposals = prometheus.getProposals();
352
+ res.json({ count: proposals.length, proposals });
353
+ } catch (error: any) {
354
+ res.status(500).json({ error: error.message });
355
+ }
356
+ });
357
+
358
+ /**
359
+ * POST /api/neural/evolution/godmode
360
+ * Enable/disable God Mode (auto-apply proposals)
361
+ */
362
+ router.post('/evolution/godmode', async (req, res) => {
363
+ try {
364
+ const { enabled } = req.body;
365
+ prometheus.enableGodMode(!!enabled);
366
+ res.json({ godMode: !!enabled, message: enabled ? 'God Mode ENABLED - Handle with care!' : 'God Mode disabled' });
367
+ } catch (error: any) {
368
+ res.status(500).json({ error: error.message });
369
+ }
370
+ });
371
+
372
+ export default router;
apps/backend/src/scripts/setup-graph.ts ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // ⏳ THE TIME LORD: setup-graph.ts
2
+ // Point 2: Temporal Hypergraphs
3
+ // Defines the reality schema and timeline structures
4
+
5
+ import { neo4jService } from '../database/Neo4jService.js';
6
+
7
+ async function setupSchema() {
8
+ console.log('⏳ [CHRONOS] Defining Reality Schema...');
9
+ console.log('');
10
+
11
+ try {
12
+ // 1. Uniqueness Constraints (Point 1: SEGA)
13
+ console.log('📋 Creating Uniqueness Constraints...');
14
+
15
+ const constraints = [
16
+ 'CREATE CONSTRAINT file_id IF NOT EXISTS FOR (f:File) REQUIRE f.id IS UNIQUE',
17
+ 'CREATE CONSTRAINT agent_id IF NOT EXISTS FOR (a:Agent) REQUIRE a.id IS UNIQUE',
18
+ 'CREATE CONSTRAINT identity_email IF NOT EXISTS FOR (i:Identity) REQUIRE i.email IS UNIQUE',
19
+ 'CREATE CONSTRAINT event_id IF NOT EXISTS FOR (e:Event) REQUIRE e.id IS UNIQUE',
20
+ 'CREATE CONSTRAINT knowledge_id IF NOT EXISTS FOR (k:Knowledge) REQUIRE k.id IS UNIQUE'
21
+ ];
22
+
23
+ for (const constraint of constraints) {
24
+ try {
25
+ await neo4jService.write(constraint);
26
+ console.log(` ✓ ${constraint.split('FOR')[0].trim()}`);
27
+ } catch (e: any) {
28
+ if (!e.message?.includes('already exists')) {
29
+ console.warn(` ⚠ ${e.message?.slice(0, 60)}`);
30
+ }
31
+ }
32
+ }
33
+
34
+ // 2. Indexes for performance
35
+ console.log('\n📊 Creating Indexes...');
36
+
37
+ const indexes = [
38
+ 'CREATE INDEX file_name_idx IF NOT EXISTS FOR (f:File) ON (f.name)',
39
+ 'CREATE INDEX file_path_idx IF NOT EXISTS FOR (f:File) ON (f.path)',
40
+ 'CREATE INDEX agent_role_idx IF NOT EXISTS FOR (a:Agent) ON (a.role)',
41
+ 'CREATE INDEX event_timestamp_idx IF NOT EXISTS FOR (e:Event) ON (e.timestamp)',
42
+ 'CREATE INDEX identity_name_idx IF NOT EXISTS FOR (i:Identity) ON (i.name)',
43
+ 'CREATE INDEX knowledge_type_idx IF NOT EXISTS FOR (k:Knowledge) ON (k.type)'
44
+ ];
45
+
46
+ for (const index of indexes) {
47
+ try {
48
+ await neo4jService.write(index);
49
+ console.log(` ✓ ${index.split('FOR')[0].trim()}`);
50
+ } catch (e: any) {
51
+ if (!e.message?.includes('already exists')) {
52
+ console.warn(` ⚠ ${e.message?.slice(0, 60)}`);
53
+ }
54
+ }
55
+ }
56
+
57
+ // 3. Vector Index (Point 6: Dark Matter)
58
+ console.log('\n🌑 Creating Vector Index (Dark Matter)...');
59
+ try {
60
+ await neo4jService.write(`
61
+ CREATE VECTOR INDEX file_embeddings IF NOT EXISTS
62
+ FOR (f:File) ON (f.embedding)
63
+ OPTIONS {indexConfig: {
64
+ \`vector.dimensions\`: 384,
65
+ \`vector.similarity_function\`: 'cosine'
66
+ }}
67
+ `);
68
+ console.log(' ✓ Vector Index Created (384 dimensions, cosine similarity)');
69
+ } catch (e: any) {
70
+ console.warn(' ⚠ Vector index creation skipped (requires Neo4j 5.x with Vector support)');
71
+ console.warn(` ${e.message?.slice(0, 80)}`);
72
+ }
73
+
74
+ // 4. Full-text indexes for search
75
+ console.log('\n🔍 Creating Full-Text Indexes...');
76
+ try {
77
+ await neo4jService.write(`
78
+ CREATE FULLTEXT INDEX file_content_search IF NOT EXISTS
79
+ FOR (f:File) ON EACH [f.name, f.contentPreview]
80
+ `);
81
+ console.log(' ✓ Full-text index on File content');
82
+ } catch (e: any) {
83
+ if (!e.message?.includes('already exists')) {
84
+ console.warn(` ⚠ Full-text index skipped: ${e.message?.slice(0, 60)}`);
85
+ }
86
+ }
87
+
88
+ try {
89
+ await neo4jService.write(`
90
+ CREATE FULLTEXT INDEX knowledge_search IF NOT EXISTS
91
+ FOR (k:Knowledge) ON EACH [k.title, k.summary, k.content]
92
+ `);
93
+ console.log(' ✓ Full-text index on Knowledge content');
94
+ } catch (e: any) {
95
+ if (!e.message?.includes('already exists')) {
96
+ console.warn(` ⚠ Full-text index skipped: ${e.message?.slice(0, 60)}`);
97
+ }
98
+ }
99
+
100
+ // 5. Create core agent nodes
101
+ console.log('\n🤖 Creating Core Agent Nodes...');
102
+ const coreAgents = [
103
+ { id: 'SYSTEM_CORE', role: 'ARCHITECT', name: 'System Core' },
104
+ { id: 'PROMETHEUS', role: 'ARCHITECT', name: 'Prometheus Engine' },
105
+ { id: 'KNOWLEDGE_COMPILER', role: 'EXECUTOR', name: 'Knowledge Compiler' },
106
+ { id: 'SWARM_CONTROLLER', role: 'ARCHITECT', name: 'Swarm Controller' },
107
+ { id: 'ANGEL_PROXY', role: 'GUARDIAN', name: 'Angel Security Proxy' }
108
+ ];
109
+
110
+ for (const agent of coreAgents) {
111
+ await neo4jService.write(`
112
+ MERGE (a:Agent {id: $id})
113
+ SET a.role = $role, a.name = $name, a.status = 'ACTIVE', a.createdAt = datetime()
114
+ `, agent);
115
+ console.log(` ✓ Agent: ${agent.name} (${agent.role})`);
116
+ }
117
+
118
+ // 6. Create initial event
119
+ console.log('\n📅 Recording Genesis Event...');
120
+ await neo4jService.write(`
121
+ CREATE (e:Event {
122
+ id: 'GENESIS_' + toString(timestamp()),
123
+ type: 'SYSTEM_INIT',
124
+ description: 'Neural Singularity Schema Initialized',
125
+ timestamp: datetime(),
126
+ source: 'CHRONOS'
127
+ })
128
+ `);
129
+ console.log(' ✓ Genesis event recorded');
130
+
131
+ console.log('\n' + '='.repeat(60));
132
+ console.log('✅ SCHEMA SETUP COMPLETE');
133
+ console.log('='.repeat(60));
134
+ console.log('\nNeural Singularity Graph is ready for:');
135
+ console.log(' • Knowledge Compilation (SEGA)');
136
+ console.log(' • Temporal Event Tracking (THG)');
137
+ console.log(' • Swarm Consciousness (SCE)');
138
+ console.log(' • Vector Similarity Search (CDMM)');
139
+ console.log(' • Full-Text Search');
140
+ console.log('');
141
+
142
+ } catch (error: any) {
143
+ console.error('\n❌ Schema Setup Failed:', error.message);
144
+ process.exit(1);
145
+ } finally {
146
+ await neo4jService.close();
147
+ process.exit(0);
148
+ }
149
+ }
150
+
151
+ // Run if called directly
152
+ setupSchema();
apps/backend/src/services/NeuralBus.ts ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🐝 TELEPATHY: NeuralBus.ts
2
+ // Ansvarlig for 0ms kommunikation mellem agenter og frontend.
3
+ // Real-time event streaming via WebSockets
4
+
5
+ import { Server as SocketIOServer, Socket } from 'socket.io';
6
+ import { Server as HttpServer } from 'http';
7
+
8
+ export interface ThoughtEvent {
9
+ agent: string;
10
+ timestamp: number;
11
+ thought: string;
12
+ context: Record<string, unknown>;
13
+ type?: 'INFO' | 'WARNING' | 'ERROR' | 'SUCCESS' | 'THOUGHT';
14
+ }
15
+
16
+ export interface AgentInfo {
17
+ id: string;
18
+ name: string;
19
+ connectedAt: Date;
20
+ lastActivity: Date;
21
+ }
22
+
23
+ export class NeuralBus {
24
+ private static instance: NeuralBus;
25
+ private io: SocketIOServer | null = null;
26
+ private connectedAgents = new Map<string, AgentInfo>();
27
+ private thoughtHistory: ThoughtEvent[] = [];
28
+ private maxHistorySize = 1000;
29
+
30
+ private constructor() {
31
+ console.log('🐝 [HIVE] Neural Bus Initializing...');
32
+ }
33
+
34
+ public static getInstance(): NeuralBus {
35
+ if (!NeuralBus.instance) {
36
+ NeuralBus.instance = new NeuralBus();
37
+ }
38
+ return NeuralBus.instance;
39
+ }
40
+
41
+ public attach(httpServer: HttpServer): void {
42
+ this.io = new SocketIOServer(httpServer, {
43
+ cors: {
44
+ origin: "*",
45
+ methods: ["GET", "POST"]
46
+ },
47
+ pingTimeout: 60000,
48
+ pingInterval: 25000
49
+ });
50
+
51
+ console.log('🐝 [HIVE] Neural Telepathy Bus Online');
52
+
53
+ this.io.on('connection', (socket: Socket) => {
54
+ const agentName = socket.handshake.query.agent as string || `Agent-${socket.id.slice(0, 6)}`;
55
+
56
+ // Register agent
57
+ this.connectedAgents.set(socket.id, {
58
+ id: socket.id,
59
+ name: agentName,
60
+ connectedAt: new Date(),
61
+ lastActivity: new Date()
62
+ });
63
+
64
+ console.log(`🐝 [HIVE] Agent Connected: ${agentName} (${socket.id})`);
65
+
66
+ // Notify all agents of new connection
67
+ this.io?.emit('AGENT_JOINED', {
68
+ agent: agentName,
69
+ totalAgents: this.connectedAgents.size
70
+ });
71
+
72
+ // Handle incoming thoughts
73
+ socket.on('THOUGHT', (data: Partial<ThoughtEvent>) => {
74
+ const thought: ThoughtEvent = {
75
+ agent: agentName,
76
+ timestamp: Date.now(),
77
+ thought: data.thought || '',
78
+ context: data.context || {},
79
+ type: data.type || 'THOUGHT'
80
+ };
81
+
82
+ this.recordThought(thought);
83
+ socket.broadcast.emit('THOUGHT_STREAM', thought);
84
+
85
+ // Update activity
86
+ const agent = this.connectedAgents.get(socket.id);
87
+ if (agent) agent.lastActivity = new Date();
88
+ });
89
+
90
+ // Handle queries
91
+ socket.on('QUERY', async (data: { type: string; payload: unknown }, callback) => {
92
+ const response = await this.handleQuery(data.type, data.payload);
93
+ if (callback) callback(response);
94
+ });
95
+
96
+ // Handle disconnection
97
+ socket.on('disconnect', () => {
98
+ const agent = this.connectedAgents.get(socket.id);
99
+ this.connectedAgents.delete(socket.id);
100
+
101
+ console.log(`🐝 [HIVE] Agent Disconnected: ${agent?.name || socket.id}`);
102
+
103
+ this.io?.emit('AGENT_LEFT', {
104
+ agent: agent?.name,
105
+ totalAgents: this.connectedAgents.size
106
+ });
107
+ });
108
+ });
109
+ }
110
+
111
+ private recordThought(thought: ThoughtEvent): void {
112
+ this.thoughtHistory.push(thought);
113
+
114
+ // Trim history if too large
115
+ if (this.thoughtHistory.length > this.maxHistorySize) {
116
+ this.thoughtHistory = this.thoughtHistory.slice(-this.maxHistorySize);
117
+ }
118
+ }
119
+
120
+ private async handleQuery(type: string, payload: unknown): Promise<unknown> {
121
+ switch (type) {
122
+ case 'GET_AGENTS':
123
+ return Array.from(this.connectedAgents.values());
124
+ case 'GET_HISTORY':
125
+ const count = (payload as { count?: number })?.count || 50;
126
+ return this.thoughtHistory.slice(-count);
127
+ case 'GET_STATS':
128
+ return this.getStats();
129
+ default:
130
+ return { error: 'Unknown query type' };
131
+ }
132
+ }
133
+
134
+ // Public API for emitting thoughts from server-side
135
+ public emitThought(agent: string, thought: string, context: Record<string, unknown> = {}, type: ThoughtEvent['type'] = 'INFO'): void {
136
+ if (this.io) {
137
+ const event: ThoughtEvent = {
138
+ agent,
139
+ timestamp: Date.now(),
140
+ thought,
141
+ context,
142
+ type
143
+ };
144
+
145
+ this.recordThought(event);
146
+ this.io.emit('THOUGHT_STREAM', event);
147
+ }
148
+ }
149
+
150
+ public emitToAgent(agentId: string, event: string, data: unknown): void {
151
+ if (this.io) {
152
+ this.io.to(agentId).emit(event, data);
153
+ }
154
+ }
155
+
156
+ public broadcast(event: string, data: unknown): void {
157
+ if (this.io) {
158
+ this.io.emit(event, data);
159
+ }
160
+ }
161
+
162
+ public getStats() {
163
+ return {
164
+ connectedAgents: this.connectedAgents.size,
165
+ agents: Array.from(this.connectedAgents.values()).map(a => ({
166
+ name: a.name,
167
+ connectedAt: a.connectedAt,
168
+ lastActivity: a.lastActivity
169
+ })),
170
+ thoughtsRecorded: this.thoughtHistory.length,
171
+ isOnline: this.io !== null
172
+ };
173
+ }
174
+
175
+ public getRecentThoughts(count: number = 50): ThoughtEvent[] {
176
+ return this.thoughtHistory.slice(-count);
177
+ }
178
+ }
179
+
180
+ export const neuralBus = NeuralBus.getInstance();
apps/backend/src/services/NeuralCompiler.ts ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🧠 THE BRAIN: NeuralCompiler.ts
2
+ // Ansvarlig for at æde filer og gøre dem til struktureret viden.
3
+ // Renamed from KnowledgeCompiler to avoid conflict with existing service.
4
+
5
+ import fs from 'fs/promises';
6
+ import path from 'path';
7
+ import crypto from 'crypto';
8
+ import chokidar from 'chokidar';
9
+ import { vectorService } from './VectorService';
10
+
11
+ // Conditional imports for optional services
12
+ let neo4jService: any = null;
13
+ let metricsService: any = null;
14
+
15
+ export interface CompiledDocument {
16
+ id: string;
17
+ name: string;
18
+ path: string;
19
+ extension: string;
20
+ size: number;
21
+ content: string;
22
+ embedding: number[];
23
+ lastModified: Date;
24
+ tags: string[];
25
+ }
26
+
27
+ export class NeuralCompiler {
28
+ private static instance: NeuralCompiler;
29
+ private watcher: chokidar.FSWatcher | null = null;
30
+ private isProcessing = false;
31
+ private documentCache = new Map<string, CompiledDocument>();
32
+ private eventQueue: { type: string; path: string }[] = [];
33
+ private processingInterval: NodeJS.Timeout | null = null;
34
+
35
+ private constructor() {
36
+ console.log('📚 [KNOWLEDGE] Compiler Initialized');
37
+ this.initServices();
38
+ }
39
+
40
+ private async initServices() {
41
+ try {
42
+ const neo4j = await import('./Neo4jService').catch(() => null);
43
+ if (neo4j) neo4jService = neo4j.neo4jService;
44
+
45
+ const metrics = await import('./MetricsService').catch(() => null);
46
+ if (metrics) metricsService = metrics.metricsService;
47
+ } catch {
48
+ console.log('📚 [KNOWLEDGE] Running in standalone mode');
49
+ }
50
+ }
51
+
52
+ public static getInstance(): NeuralCompiler {
53
+ if (!NeuralCompiler.instance) {
54
+ NeuralCompiler.instance = new NeuralCompiler();
55
+ }
56
+ return NeuralCompiler.instance;
57
+ }
58
+
59
+ public async startWatching(dirPath: string): Promise<void> {
60
+ // Ensure directory exists
61
+ await fs.mkdir(dirPath, { recursive: true }).catch(() => {});
62
+
63
+ console.log(`👁️ [KNOWLEDGE] Watching directory: ${dirPath}`);
64
+
65
+ this.watcher = chokidar.watch(dirPath, {
66
+ ignored: /(^|[\/\\])\../, // Ignore dotfiles
67
+ persistent: true,
68
+ depth: 5,
69
+ awaitWriteFinish: {
70
+ stabilityThreshold: 1000,
71
+ pollInterval: 100
72
+ }
73
+ });
74
+
75
+ this.watcher
76
+ .on('add', p => this.queueEvent('ADD', p))
77
+ .on('change', p => this.queueEvent('MODIFY', p))
78
+ .on('unlink', p => this.queueEvent('DELETE', p))
79
+ .on('error', err => console.error('👁️ [KNOWLEDGE] Watcher error:', err));
80
+
81
+ // Process queue every 500ms to batch events
82
+ this.processingInterval = setInterval(() => this.processQueue(), 500);
83
+ }
84
+
85
+ private queueEvent(type: string, filePath: string) {
86
+ this.eventQueue.push({ type, path: filePath });
87
+ }
88
+
89
+ private async processQueue() {
90
+ if (this.isProcessing || this.eventQueue.length === 0) return;
91
+
92
+ this.isProcessing = true;
93
+ const events = [...this.eventQueue];
94
+ this.eventQueue = [];
95
+
96
+ for (const event of events) {
97
+ await this.handleFileEvent(event.type as 'ADD' | 'MODIFY' | 'DELETE', event.path);
98
+ }
99
+
100
+ this.isProcessing = false;
101
+ }
102
+
103
+ private async handleFileEvent(
104
+ eventType: 'ADD' | 'MODIFY' | 'DELETE',
105
+ filePath: string
106
+ ): Promise<void> {
107
+ try {
108
+ const fileId = this.generateFileId(filePath);
109
+ const filename = path.basename(filePath);
110
+ const ext = path.extname(filePath).toLowerCase();
111
+
112
+ // Skip unsupported files
113
+ const supportedExts = ['.txt', '.md', '.json', '.ts', '.js', '.py', '.html', '.css', '.yaml', '.yml', '.xml', '.csv'];
114
+ if (!supportedExts.includes(ext)) return;
115
+
116
+ if (eventType === 'DELETE') {
117
+ this.documentCache.delete(fileId);
118
+
119
+ if (neo4jService) {
120
+ await neo4jService.write(
121
+ `MATCH (f:File {id: $id}) DETACH DELETE f`,
122
+ { id: fileId }
123
+ );
124
+ }
125
+ console.log(`🗑️ [KNOWLEDGE] Forgot file: ${filename}`);
126
+ return;
127
+ }
128
+
129
+ // 1. Read Content
130
+ const content = await fs.readFile(filePath, 'utf-8');
131
+
132
+ // 2. Generate Vector Embedding (Cognitive Dark Matter)
133
+ const textForEmbedding = content.substring(0, 2000); // Limit for speed
134
+ const embedding = await vectorService.embedText(textForEmbedding);
135
+
136
+ // 3. Create compiled document
137
+ const doc: CompiledDocument = {
138
+ id: fileId,
139
+ name: filename,
140
+ path: filePath,
141
+ extension: ext,
142
+ size: content.length,
143
+ content: content.substring(0, 5000), // Store first 5KB
144
+ embedding,
145
+ lastModified: new Date(),
146
+ tags: this.extractTags(content, ext)
147
+ };
148
+
149
+ // 4. Cache locally
150
+ this.documentCache.set(fileId, doc);
151
+
152
+ // 5. Ingest into Neo4j if available
153
+ if (neo4jService) {
154
+ await neo4jService.write(`
155
+ MERGE (f:File {id: $id})
156
+ SET f.name = $name,
157
+ f.path = $path,
158
+ f.extension = $ext,
159
+ f.size = $size,
160
+ f.lastModified = datetime(),
161
+ f.contentPreview = $preview
162
+
163
+ // Link to Directory
164
+ MERGE (d:Directory {path: $dirPath})
165
+ MERGE (f)-[:LOCATED_IN]->(d)
166
+
167
+ // Auto-Tagging based on extension
168
+ MERGE (t:Tag {name: $ext})
169
+ MERGE (f)-[:TAGGED]->(t)
170
+ `, {
171
+ id: fileId,
172
+ name: filename,
173
+ path: filePath,
174
+ dirPath: path.dirname(filePath),
175
+ ext: ext,
176
+ size: content.length,
177
+ preview: content.substring(0, 500)
178
+ });
179
+ }
180
+
181
+ console.log(`✨ [KNOWLEDGE] Assimilated: ${filename} (${eventType})`);
182
+
183
+ if (metricsService) {
184
+ metricsService.incrementCounter('knowledge_files_ingested');
185
+ }
186
+ } catch (error) {
187
+ console.error(`📚 [KNOWLEDGE] Error processing ${filePath}:`, error);
188
+ }
189
+ }
190
+
191
+ private extractTags(content: string, ext: string): string[] {
192
+ const tags: string[] = [ext];
193
+
194
+ // Extract hashtags
195
+ const hashtags = content.match(/#\w+/g) || [];
196
+ tags.push(...hashtags.map(t => t.toLowerCase()));
197
+
198
+ // Detect language/framework
199
+ if (content.includes('import React')) tags.push('react');
200
+ if (content.includes('from fastapi')) tags.push('fastapi');
201
+ if (content.includes('async function')) tags.push('async');
202
+ if (content.includes('class ')) tags.push('oop');
203
+
204
+ return [...new Set(tags)];
205
+ }
206
+
207
+ private generateFileId(filePath: string): string {
208
+ return crypto.createHash('md5').update(filePath).digest('hex');
209
+ }
210
+
211
+ // Public API for querying
212
+ public async searchSimilar(query: string, topK: number = 5): Promise<CompiledDocument[]> {
213
+ const items = Array.from(this.documentCache.values()).map(doc => ({
214
+ id: doc.id,
215
+ embedding: doc.embedding
216
+ }));
217
+
218
+ const results = await vectorService.findSimilar(query, items, topK);
219
+
220
+ return results
221
+ .map(r => this.documentCache.get(r.id))
222
+ .filter((d): d is CompiledDocument => d !== undefined);
223
+ }
224
+
225
+ public getDocument(id: string): CompiledDocument | undefined {
226
+ return this.documentCache.get(id);
227
+ }
228
+
229
+ public getAllDocuments(): CompiledDocument[] {
230
+ return Array.from(this.documentCache.values());
231
+ }
232
+
233
+ public getStats() {
234
+ return {
235
+ totalDocuments: this.documentCache.size,
236
+ queueLength: this.eventQueue.length,
237
+ isProcessing: this.isProcessing
238
+ };
239
+ }
240
+
241
+ public async stop(): Promise<void> {
242
+ if (this.watcher) {
243
+ await this.watcher.close();
244
+ this.watcher = null;
245
+ }
246
+ if (this.processingInterval) {
247
+ clearInterval(this.processingInterval);
248
+ this.processingInterval = null;
249
+ }
250
+ console.log('📚 [NEURAL] Compiler Stopped');
251
+ }
252
+ }
253
+
254
+ export const neuralCompiler = NeuralCompiler.getInstance();
apps/backend/src/services/Prometheus.ts ADDED
@@ -0,0 +1,267 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🔥 PROMETHEUS ENGINE: Autonomous Evolution
2
+ // Point 7: Autonomous Paradigm Discovery
3
+ // The system that writes its own code. Handle with care.
4
+
5
+ import fs from 'fs/promises';
6
+ import path from 'path';
7
+ import { neuralBus } from './NeuralBus.js';
8
+
9
+ interface CodeProposal {
10
+ id: string;
11
+ filePath: string;
12
+ description: string;
13
+ currentCode: string;
14
+ proposedCode?: string;
15
+ status: 'PROPOSED' | 'APPROVED' | 'REJECTED' | 'APPLIED';
16
+ createdAt: Date;
17
+ confidence: number;
18
+ }
19
+
20
+ interface ScanResult {
21
+ file: string;
22
+ issues: string[];
23
+ suggestions: string[];
24
+ metrics: {
25
+ lines: number;
26
+ functions: number;
27
+ complexity: number;
28
+ };
29
+ }
30
+
31
+ export class PrometheusEngine {
32
+ private static instance: PrometheusEngine;
33
+ private proposals: Map<string, CodeProposal> = new Map();
34
+ private scanResults: ScanResult[] = [];
35
+ private isScanning = false;
36
+ private godMode = false; // Set to true to allow auto-apply
37
+
38
+ private constructor() {
39
+ console.log('🔥 [PROMETHEUS] Autonomous Evolution Engine Online');
40
+ console.log('🔥 [PROMETHEUS] God Mode:', this.godMode ? 'ENABLED' : 'DISABLED');
41
+ }
42
+
43
+ public static getInstance(): PrometheusEngine {
44
+ if (!PrometheusEngine.instance) {
45
+ PrometheusEngine.instance = new PrometheusEngine();
46
+ }
47
+ return PrometheusEngine.instance;
48
+ }
49
+
50
+ /**
51
+ * Scan directory for code improvements
52
+ */
53
+ public async scanAndPropose(dirPath: string): Promise<ScanResult[]> {
54
+ if (this.isScanning) {
55
+ console.log('🔥 [PROMETHEUS] Scan already in progress');
56
+ return [];
57
+ }
58
+
59
+ this.isScanning = true;
60
+ this.scanResults = [];
61
+
62
+ try {
63
+ console.log(`🔥 [PROMETHEUS] Scanning: ${dirPath}`);
64
+ await this.scanDirectory(dirPath);
65
+ console.log(`🔥 [PROMETHEUS] Scan complete. Found ${this.scanResults.length} files`);
66
+
67
+ neuralBus.emitThought('PROMETHEUS', `Code scan complete: ${this.scanResults.length} files analyzed`, {
68
+ issues: this.scanResults.reduce((acc, r) => acc + r.issues.length, 0),
69
+ suggestions: this.scanResults.reduce((acc, r) => acc + r.suggestions.length, 0)
70
+ }, 'INFO');
71
+
72
+ return this.scanResults;
73
+ } finally {
74
+ this.isScanning = false;
75
+ }
76
+ }
77
+
78
+ private async scanDirectory(dirPath: string, depth: number = 0): Promise<void> {
79
+ if (depth > 5) return; // Max depth
80
+
81
+ try {
82
+ const entries = await fs.readdir(dirPath, { withFileTypes: true });
83
+
84
+ for (const entry of entries) {
85
+ const fullPath = path.join(dirPath, entry.name);
86
+
87
+ // Skip node_modules, dist, etc
88
+ if (entry.isDirectory()) {
89
+ if (!['node_modules', 'dist', '.git', 'coverage'].includes(entry.name)) {
90
+ await this.scanDirectory(fullPath, depth + 1);
91
+ }
92
+ } else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.js'))) {
93
+ await this.analyzeFile(fullPath);
94
+ }
95
+ }
96
+ } catch (error) {
97
+ // Directory access error
98
+ }
99
+ }
100
+
101
+ private async analyzeFile(filePath: string): Promise<void> {
102
+ try {
103
+ const content = await fs.readFile(filePath, 'utf-8');
104
+ const lines = content.split('\n');
105
+
106
+ const result: ScanResult = {
107
+ file: filePath,
108
+ issues: [],
109
+ suggestions: [],
110
+ metrics: {
111
+ lines: lines.length,
112
+ functions: (content.match(/function\s+\w+|=>\s*{|async\s+\w+/g) || []).length,
113
+ complexity: this.calculateComplexity(content)
114
+ }
115
+ };
116
+
117
+ // Rule 1: Console.log without metrics
118
+ if (content.includes('console.log') && !content.includes('metricsService')) {
119
+ result.suggestions.push('Replace console.log with metricsService for production monitoring');
120
+ this.createProposal(filePath, 'Replace logging with metrics', content, 0.7);
121
+ }
122
+
123
+ // Rule 2: Hardcoded strings that should be config
124
+ const hardcodedUrls = content.match(/['"]https?:\/\/[^'"]+['"]/g) || [];
125
+ if (hardcodedUrls.length > 2) {
126
+ result.issues.push(`Found ${hardcodedUrls.length} hardcoded URLs - consider using config`);
127
+ }
128
+
129
+ // Rule 3: Missing error handling
130
+ if (content.includes('await ') && !content.includes('catch')) {
131
+ result.suggestions.push('Add try/catch blocks around async operations');
132
+ }
133
+
134
+ // Rule 4: Long functions
135
+ const functionMatches = content.match(/(?:async\s+)?function\s+\w+[^{]*\{[\s\S]*?\n\}/g) || [];
136
+ for (const fn of functionMatches) {
137
+ if (fn.split('\n').length > 50) {
138
+ result.issues.push('Function exceeds 50 lines - consider refactoring');
139
+ }
140
+ }
141
+
142
+ // Rule 5: TODO/FIXME comments
143
+ const todos = (content.match(/\/\/\s*(TODO|FIXME|HACK|XXX):/gi) || []).length;
144
+ if (todos > 0) {
145
+ result.issues.push(`Found ${todos} TODO/FIXME comments`);
146
+ }
147
+
148
+ // Rule 6: Magic numbers
149
+ const magicNumbers = content.match(/[^a-zA-Z0-9_](\d{4,})[^a-zA-Z0-9_]/g) || [];
150
+ if (magicNumbers.length > 3) {
151
+ result.suggestions.push('Consider extracting magic numbers to named constants');
152
+ }
153
+
154
+ // Rule 7: Unused imports (simplified check)
155
+ const importMatches = content.match(/import\s+{?\s*([^}]+)\s*}?\s+from/g) || [];
156
+ for (const imp of importMatches) {
157
+ const imported = imp.match(/import\s+{?\s*([^}]+)\s*}?\s+from/)?.[1] || '';
158
+ const names = imported.split(',').map(n => n.trim().split(' as ')[0].trim());
159
+ for (const name of names) {
160
+ if (name && !content.slice(content.indexOf(imp) + imp.length).includes(name)) {
161
+ result.suggestions.push(`Potentially unused import: ${name}`);
162
+ }
163
+ }
164
+ }
165
+
166
+ if (result.issues.length > 0 || result.suggestions.length > 0) {
167
+ this.scanResults.push(result);
168
+ }
169
+ } catch (error) {
170
+ // File read error
171
+ }
172
+ }
173
+
174
+ private calculateComplexity(content: string): number {
175
+ // Simplified cyclomatic complexity
176
+ let complexity = 1;
177
+ complexity += (content.match(/if\s*\(/g) || []).length;
178
+ complexity += (content.match(/else\s*{/g) || []).length;
179
+ complexity += (content.match(/for\s*\(/g) || []).length;
180
+ complexity += (content.match(/while\s*\(/g) || []).length;
181
+ complexity += (content.match(/case\s+/g) || []).length;
182
+ complexity += (content.match(/\?\s*[^:]+:/g) || []).length; // Ternary
183
+ return complexity;
184
+ }
185
+
186
+ private createProposal(filePath: string, description: string, currentCode: string, confidence: number): void {
187
+ const id = `proposal_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
188
+
189
+ const proposal: CodeProposal = {
190
+ id,
191
+ filePath,
192
+ description,
193
+ currentCode: currentCode.substring(0, 500), // Preview only
194
+ status: 'PROPOSED',
195
+ createdAt: new Date(),
196
+ confidence
197
+ };
198
+
199
+ this.proposals.set(id, proposal);
200
+
201
+ console.log(`🔥 [PROMETHEUS] Proposal Created: ${description} (${path.basename(filePath)})`);
202
+
203
+ neuralBus.emitThought('PROMETHEUS', `New code proposal: ${description}`, {
204
+ proposalId: id,
205
+ file: path.basename(filePath),
206
+ confidence
207
+ }, 'WARNING');
208
+ }
209
+
210
+ /**
211
+ * Apply a proposal (God Mode only)
212
+ */
213
+ public async applyProposal(proposalId: string): Promise<boolean> {
214
+ if (!this.godMode) {
215
+ console.warn('🔥 [PROMETHEUS] God Mode disabled - cannot apply proposals');
216
+ return false;
217
+ }
218
+
219
+ const proposal = this.proposals.get(proposalId);
220
+ if (!proposal || proposal.status !== 'PROPOSED') {
221
+ return false;
222
+ }
223
+
224
+ // In a real implementation, this would:
225
+ // 1. Generate improved code via LLM
226
+ // 2. Create backup
227
+ // 3. Apply changes
228
+ // 4. Run tests
229
+ // 5. Rollback if tests fail
230
+
231
+ proposal.status = 'APPLIED';
232
+ console.log(`🔥 [PROMETHEUS] Proposal Applied: ${proposalId}`);
233
+
234
+ return true;
235
+ }
236
+
237
+ public enableGodMode(enabled: boolean): void {
238
+ this.godMode = enabled;
239
+ console.log(`🔥 [PROMETHEUS] God Mode: ${enabled ? 'ENABLED' : 'DISABLED'}`);
240
+
241
+ neuralBus.emitThought('PROMETHEUS', `God Mode ${enabled ? 'enabled' : 'disabled'}`, {},
242
+ enabled ? 'WARNING' : 'INFO');
243
+ }
244
+
245
+ // Public getters
246
+ public getProposals(): CodeProposal[] {
247
+ return Array.from(this.proposals.values());
248
+ }
249
+
250
+ public getScanResults(): ScanResult[] {
251
+ return this.scanResults;
252
+ }
253
+
254
+ public getStats() {
255
+ return {
256
+ isScanning: this.isScanning,
257
+ godMode: this.godMode,
258
+ proposals: this.proposals.size,
259
+ pendingProposals: Array.from(this.proposals.values()).filter(p => p.status === 'PROPOSED').length,
260
+ lastScanFiles: this.scanResults.length,
261
+ totalIssues: this.scanResults.reduce((acc, r) => acc + r.issues.length, 0),
262
+ totalSuggestions: this.scanResults.reduce((acc, r) => acc + r.suggestions.length, 0)
263
+ };
264
+ }
265
+ }
266
+
267
+ export const prometheus = PrometheusEngine.getInstance();
apps/backend/src/services/SelfHealingAdapter.ts CHANGED
@@ -128,6 +128,52 @@ class SelfHealingAdapter {
128
  };
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  private diagnoseError(error: any): string {
132
  if (error.code === 'ECONNREFUSED') return 'CONNECTION_LOST';
133
  if (error.code === 'SessionExpired') return 'SESSION_EXPIRED';
 
128
  };
129
  }
130
 
131
+ /**
132
+ * 📊 Returns the overall system health and status of subsystems.
133
+ * Used by KnowledgeCompiler for the 'Health' knowledge node.
134
+ */
135
+ public getSystemStatus(): { overallHealth: string; services: { name: string; status: string }[] } {
136
+ const circuitBreakerCount = Array.from(this.circuitBreakers.values()).filter(v => v === true).length;
137
+ const overallHealth = circuitBreakerCount === 0 ? 'HEALTHY' : (circuitBreakerCount < 3 ? 'DEGRADED' : 'CRITICAL');
138
+
139
+ const services = [
140
+ { name: 'SelfHealingEngine', status: 'RUNNING' },
141
+ { name: 'CircuitBreakers', status: circuitBreakerCount > 0 ? 'ACTIVE' : 'IDLE' }
142
+ ];
143
+
144
+ // Add specific circuit breakers as "services" if they exist
145
+ this.circuitBreakers.forEach((isOpen, name) => {
146
+ services.push({ name: `Circuit:${name}`, status: isOpen ? 'BROKEN' : 'OK' });
147
+ });
148
+
149
+ return {
150
+ overallHealth,
151
+ services
152
+ };
153
+ }
154
+
155
+ /**
156
+ * 🔮 Generates predictive alerts based on error patterns.
157
+ * Used by KnowledgeCompiler.
158
+ */
159
+ public getPredictiveAlerts(): any[] {
160
+ // In a real implementation, this would analyze error frequencies from metricsService.
161
+ // For now, we return basic alerts if circuit breakers are open.
162
+ const alerts: any[] = [];
163
+ this.circuitBreakers.forEach((isOpen, name) => {
164
+ if (isOpen) {
165
+ alerts.push({
166
+ errorCode: 'CIRCUIT_OPEN',
167
+ severity: 'HIGH',
168
+ probability: 1.0,
169
+ expectedIn: 'NOW',
170
+ recommendation: `Check external dependency for ${name} immediately.`
171
+ });
172
+ }
173
+ });
174
+ return alerts;
175
+ }
176
+
177
  private diagnoseError(error: any): string {
178
  if (error.code === 'ECONNREFUSED') return 'CONNECTION_LOST';
179
  if (error.code === 'SessionExpired') return 'SESSION_EXPIRED';
apps/backend/src/services/VectorService.ts ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // 🌑 DARK MATTER: VectorService.ts
2
+ // Ansvarlig for semantisk forståelse. Gør systemet i stand til at "føle" betydning.
3
+ // Uses local ONNX model - No API keys. No cost. Pure silicon power.
4
+
5
+ import { pipeline } from '@xenova/transformers';
6
+
7
+ export class VectorService {
8
+ private static instance: VectorService;
9
+ private extractor: any = null;
10
+ private isInitializing = false;
11
+ private initPromise: Promise<void> | null = null;
12
+
13
+ private constructor() {
14
+ console.log('🌑 [DARK MATTER] Vector Engine Loading...');
15
+ }
16
+
17
+ public static getInstance(): VectorService {
18
+ if (!VectorService.instance) {
19
+ VectorService.instance = new VectorService();
20
+ }
21
+ return VectorService.instance;
22
+ }
23
+
24
+ /**
25
+ * Initializes the local AI model (ONNX).
26
+ * Model: all-MiniLM-L6-v2 (384 dimensions, fast, accurate)
27
+ */
28
+ public async init(): Promise<void> {
29
+ if (this.extractor) return;
30
+
31
+ if (this.isInitializing && this.initPromise) {
32
+ return this.initPromise;
33
+ }
34
+
35
+ this.isInitializing = true;
36
+ this.initPromise = (async () => {
37
+ try {
38
+ // Use a small, fast model: all-MiniLM-L6-v2
39
+ this.extractor = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2');
40
+ console.log('🌑 [DARK MATTER] Neural Model Loaded (384 dimensions)');
41
+ } catch (error) {
42
+ console.error('🌑 [DARK MATTER] Failed to load model:', error);
43
+ throw error;
44
+ } finally {
45
+ this.isInitializing = false;
46
+ }
47
+ })();
48
+
49
+ return this.initPromise;
50
+ }
51
+
52
+ /**
53
+ * Generate embedding vector for text
54
+ * @param text Input text to embed
55
+ * @returns 384-dimensional vector
56
+ */
57
+ public async embedText(text: string): Promise<number[]> {
58
+ await this.init();
59
+
60
+ // Clean text
61
+ const cleanText = text.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
62
+ if (!cleanText) return new Array(384).fill(0);
63
+
64
+ try {
65
+ // Generate embedding
66
+ const output = await this.extractor!(cleanText, {
67
+ pooling: 'mean',
68
+ normalize: true
69
+ });
70
+
71
+ // Convert Float32Array to regular array for Neo4j/storage
72
+ return Array.from(output.data as Float32Array);
73
+ } catch (error) {
74
+ console.error('🌑 [DARK MATTER] Embedding failed:', error);
75
+ return new Array(384).fill(0);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Compute cosine similarity between two vectors
81
+ */
82
+ public cosineSimilarity(a: number[], b: number[]): number {
83
+ if (a.length !== b.length) return 0;
84
+
85
+ let dotProduct = 0;
86
+ let normA = 0;
87
+ let normB = 0;
88
+
89
+ for (let i = 0; i < a.length; i++) {
90
+ dotProduct += a[i] * b[i];
91
+ normA += a[i] * a[i];
92
+ normB += b[i] * b[i];
93
+ }
94
+
95
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
96
+ }
97
+
98
+ /**
99
+ * Find most similar items from a collection
100
+ */
101
+ public async findSimilar(
102
+ queryText: string,
103
+ items: { id: string; embedding: number[] }[],
104
+ topK: number = 5
105
+ ): Promise<{ id: string; similarity: number }[]> {
106
+ const queryEmbedding = await this.embedText(queryText);
107
+
108
+ const scored = items.map(item => ({
109
+ id: item.id,
110
+ similarity: this.cosineSimilarity(queryEmbedding, item.embedding)
111
+ }));
112
+
113
+ return scored
114
+ .sort((a, b) => b.similarity - a.similarity)
115
+ .slice(0, topK);
116
+ }
117
+
118
+ /**
119
+ * Batch embed multiple texts
120
+ */
121
+ public async embedBatch(texts: string[]): Promise<number[][]> {
122
+ return Promise.all(texts.map(t => this.embedText(t)));
123
+ }
124
+ }
125
+
126
+ export const vectorService = VectorService.getInstance();
apps/backend/src/services/colonizer-service.ts CHANGED
@@ -1,10 +1,12 @@
1
  import fs from 'fs/promises';
2
  import path from 'path';
3
- import { fileURLToPath } from 'url';
4
  import { getLlmService, ChatMessage } from './llm/llmService.js';
5
  import { CODEX_VERSION } from '../config/codex.js';
6
 
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
 
 
 
8
 
9
  /**
10
  * THE COLONIZER SERVICE
 
1
  import fs from 'fs/promises';
2
  import path from 'path';
 
3
  import { getLlmService, ChatMessage } from './llm/llmService.js';
4
  import { CODEX_VERSION } from '../config/codex.js';
5
 
6
+ // ESM/CJS compatible __dirname
7
+ const __dirname = typeof import.meta !== 'undefined' && import.meta.url
8
+ ? path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1'))
9
+ : process.cwd();
10
 
11
  /**
12
  * THE COLONIZER SERVICE
apps/backend/src/services/embeddings/LocalGPUEmbeddings.ts CHANGED
@@ -1,11 +1,12 @@
1
  import { spawn, ChildProcess } from 'child_process';
2
  import path from 'path';
3
- import { fileURLToPath } from 'url';
4
  import { EmbeddingProvider } from './EmbeddingService.js';
5
  import { logger } from '../../utils/logger.js';
6
 
7
- const __filename = fileURLToPath(import.meta.url);
8
- const __dirname = path.dirname(__filename);
 
 
9
 
10
  export class LocalGPUEmbeddingsProvider implements EmbeddingProvider {
11
  name = 'local-gpu';
 
1
  import { spawn, ChildProcess } from 'child_process';
2
  import path from 'path';
 
3
  import { EmbeddingProvider } from './EmbeddingService.js';
4
  import { logger } from '../../utils/logger.js';
5
 
6
+ // ESM/CJS compatible __dirname
7
+ const __dirname = typeof import.meta !== 'undefined' && import.meta.url
8
+ ? path.dirname(new URL(import.meta.url).pathname.replace(/^\/([A-Z]:)/, '$1'))
9
+ : __dirname || process.cwd();
10
 
11
  export class LocalGPUEmbeddingsProvider implements EmbeddingProvider {
12
  name = 'local-gpu';
monitor_runtime.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ WidgeTDC Cortex - Runtime Log Monitor
3
+ Monitors HF Space logs in real-time to verify system health
4
+ """
5
+ import time
6
+ import requests
7
+ from huggingface_hub import HfApi
8
+
9
+ # Configuration
10
+ SPACE_NAME = "widgetdc-cortex"
11
+ USERNAME = "Kraft102"
12
+ REPO_ID = f"{USERNAME}/{SPACE_NAME}"
13
+ SPACE_URL = f"https://{USERNAME.lower()}-{SPACE_NAME}.hf.space"
14
+
15
+ print("=" * 70)
16
+ print(" WIDGETTDC CORTEX - RUNTIME LOG MONITOR")
17
+ print("=" * 70)
18
+ print()
19
+
20
+ # Initialize API
21
+ api = HfApi()
22
+
23
+ def check_build_status():
24
+ """Check if Space is running"""
25
+ try:
26
+ runtime = api.get_space_runtime(repo_id=REPO_ID)
27
+ return runtime.stage, runtime.hardware
28
+ except Exception as e:
29
+ return "UNKNOWN", None
30
+
31
+ def test_health_endpoint():
32
+ """Test /health endpoint"""
33
+ try:
34
+ response = requests.get(f"{SPACE_URL}/health", timeout=10)
35
+ return response.status_code == 200, response.json() if response.status_code == 200 else None
36
+ except Exception as e:
37
+ return False, str(e)
38
+
39
+ def monitor_runtime():
40
+ """Monitor runtime status and logs"""
41
+
42
+ print("[1/4] Checking Space status...")
43
+ stage, hardware = check_build_status()
44
+ print(f" Stage: {stage}")
45
+ print(f" Hardware: {hardware}")
46
+ print()
47
+
48
+ if stage == "RUNNING":
49
+ print("✅ Space is RUNNING!")
50
+ print()
51
+
52
+ print("[2/4] Testing health endpoint...")
53
+ healthy, data = test_health_endpoint()
54
+
55
+ if healthy:
56
+ print(f"✅ Health check PASSED!")
57
+ print(f" Response: {data}")
58
+ else:
59
+ print(f"❌ Health check FAILED!")
60
+ print(f" Error: {data}")
61
+ print()
62
+
63
+ print("[3/4] Testing API endpoints...")
64
+ # Test MCP route
65
+ try:
66
+ response = requests.post(
67
+ f"{SPACE_URL}/api/mcp/route",
68
+ json={"method": "initialize", "params": {}},
69
+ timeout=10
70
+ )
71
+ print(f" MCP Route: {response.status_code}")
72
+ except Exception as e:
73
+ print(f" MCP Route: ERROR - {e}")
74
+ print()
75
+
76
+ print("[4/4] System Health Summary:")
77
+ print(" 🟢 Space: RUNNING")
78
+ print(f" {'🟢' if healthy else '🔴'} Health: {'OK' if healthy else 'FAILED'}")
79
+ print(f" 🔵 URL: {SPACE_URL}")
80
+
81
+ elif stage == "BUILDING":
82
+ print("⏳ Space is still BUILDING...")
83
+ print(" Run this script again in 1-2 minutes")
84
+
85
+ elif stage == "BUILD_ERROR":
86
+ print("❌ Space has BUILD_ERROR!")
87
+ print(" Check logs at:")
88
+ print(f" https://huggingface.co/spaces/{REPO_ID}/logs")
89
+
90
+ else:
91
+ print(f"⚠️ Unknown status: {stage}")
92
+
93
+ if __name__ == "__main__":
94
+ monitor_runtime()
95
+ print()
96
+ print("=" * 70)
97
+ print(" MONITORING COMPLETE")
98
+ print("=" * 70)
package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -5,6 +5,7 @@
5
  "private": true,
6
  "workspaces": [
7
  "apps/backend",
 
8
  "packages/*"
9
  ],
10
  "scripts": {
@@ -58,6 +59,7 @@
58
  "@vitejs/plugin-react": "^5.1.1",
59
  "@vitest/ui": "^4.0.8",
60
  "concurrently": "^8.2.2",
 
61
  "eslint": "^9.39.1",
62
  "eslint-config-prettier": "^10.1.8",
63
  "eslint-plugin-react": "^7.37.5",
 
5
  "private": true,
6
  "workspaces": [
7
  "apps/backend",
8
+ "apps/matrix-frontend",
9
  "packages/*"
10
  ],
11
  "scripts": {
 
59
  "@vitejs/plugin-react": "^5.1.1",
60
  "@vitest/ui": "^4.0.8",
61
  "concurrently": "^8.2.2",
62
+ "esbuild": "^0.24.0",
63
  "eslint": "^9.39.1",
64
  "eslint-config-prettier": "^10.1.8",
65
  "eslint-plugin-react": "^7.37.5",