Kraft102's picture
Initial deployment - WidgeTDC Cortex Backend v2.1.0
529090e
import { Request, Response, Router } from 'express';
import { OmniHarvester } from './OmniHarvester.js';
import { knowledgeAcquisition } from '../KnowledgeAcquisitionService.js';
import path from 'path';
const router = Router();
const harvester = new OmniHarvester(path.resolve(process.cwd(), '../../')); // Scan project root
// --- HARVEST CONTROL STATE ---
let isHarvesting = false;
let currentHarvestId: string | null = null;
let harvestStats = {
projectFiles: 0,
intelFiles: 0,
startTime: 0
};
// 1. Harvest Status
router.get('/harvest/status', (req, res) => {
res.json({
isRunning: isHarvesting,
harvestId: currentHarvestId,
canAbort: isHarvesting,
duration: isHarvesting ? Date.now() - harvestStats.startTime : 0
});
});
// 2. Harvest Summary
router.get('/harvest/summary', async (req, res) => {
// In a real scenario, query Neo4j for accurate counts.
// For now, return tracking stats.
try {
const vectorStats = await knowledgeAcquisition.getVectorStats();
res.json({
project: {
totalFiles: harvestStats.projectFiles,
byStrategy: { 'code': harvestStats.projectFiles }
},
intel: {
totalFiles: vectorStats.totalRecords || harvestStats.intelFiles,
byStrategy: { 'web': vectorStats.totalRecords || 0 }
},
totalFiles: harvestStats.projectFiles + (vectorStats.totalRecords || 0)
});
} catch (err) {
res.json({
project: { totalFiles: 0, byStrategy: {} },
intel: { totalFiles: 0, byStrategy: {} },
totalFiles: 0
});
}
});
// 3. Start Harvest (Project)
router.post('/harvest', async (req, res) => {
if (isHarvesting) return res.status(409).json({ error: 'Harvest already in progress' });
isHarvesting = true;
currentHarvestId = `h-${Date.now()}`;
harvestStats.startTime = Date.now();
// Start async process
(async () => {
try {
// Use OmniHarvester to scan file system
const nodes = await harvester.scan();
// TODO: Actually ingest these nodes into KnowledgeAcquisition
harvestStats.projectFiles = nodes.length; // Simplified count
} catch (e) {
console.error("Harvest failed:", e);
} finally {
isHarvesting = false;
currentHarvestId = null;
}
})();
res.json({ message: 'Project harvest started', harvestId: currentHarvestId });
});
// 4. Start Harvest (Intel / Targets)
router.post('/harvest/intel', async (req, res) => {
if (isHarvesting) return res.status(409).json({ error: 'Harvest already in progress' });
isHarvesting = true;
currentHarvestId = `i-${Date.now()}`;
harvestStats.startTime = Date.now();
(async () => {
try {
const results = await knowledgeAcquisition.acquireFromTargets();
harvestStats.intelFiles += results.filter(r => r.success).length;
} catch (e) {
console.error("Intel harvest failed:", e);
} finally {
isHarvesting = false;
currentHarvestId = null;
}
})();
res.json({ message: 'Intel harvest started', harvestId: currentHarvestId });
});
// 5. Full Sweep
router.post('/harvest/all', async (req, res) => {
if (isHarvesting) return res.status(409).json({ error: 'Harvest already in progress' });
isHarvesting = true;
currentHarvestId = `f-${Date.now()}`;
(async () => {
try {
// 1. Project
const nodes = await harvester.scan();
harvestStats.projectFiles = nodes.length;
// 2. Intel
const results = await knowledgeAcquisition.acquireFromTargets();
harvestStats.intelFiles += results.filter(r => r.success).length;
} finally {
isHarvesting = false;
currentHarvestId = null;
}
})();
res.json({ message: 'Full sweep started', harvestId: currentHarvestId });
});
// 6. Abort / Nødstop
router.post('/harvest/abort', (req, res) => {
if (!isHarvesting) return res.status(400).json({ message: 'No active harvest to abort' });
// Logic to kill the async process would go here (requires AbortController implementation in services)
isHarvesting = false;
currentHarvestId = null;
res.json({ success: true, message: 'Harvest aborted immediately' });
});
router.get('/graph', async (req: Request, res: Response) => {
try {
// In a real implementation, this would query Neo4j.
// For the prototype, we scan the file system live and return a tree structure
// which the frontend can visualize as a graph.
const nodes = await harvester.scan();
// Flatten the tree for the 3D graph (simplified)
// This maps the recursive structure to a flat node/link list
const graphData = {
nodes: [] as any[],
links: [] as any[]
};
let idCounter = 0;
function processNode(node: any, parentId: number | null = null) {
const currentId = idCounter++;
const isDir = node.type === 'directory';
graphData.nodes.push({
id: currentId,
name: node.name,
type: node.type,
val: isDir ? 5 : 1, // Size for visualizer
color: isDir ? '#ff00ff' : '#00B5CB'
});
if (parentId !== null) {
graphData.links.push({
source: parentId,
target: currentId
});
}
if (node.children) {
node.children.forEach((child: any) => processNode(child, currentId));
}
}
// Only process first level depth for performance in this mocked version if it's huge
nodes.forEach(node => processNode(node, null));
res.json(graphData);
} catch (error: any) {
console.error("Evolution Graph Error:", error);
res.status(500).json({ error: error.message });
}
});
router.post('/evolve', async (req: Request, res: Response) => {
// Placeholder for self-modification endpoint
res.json({ message: "Evolution request received. Analysis started." });
});
export const evolutionRouter = router;