Files
waggle-os/scripts/deep-clean-and-recompile.mjs
Oleg Maslov 0c3e2ead3b
Some checks failed
Installer Smoke / installer-smoke (push) Has been cancelled
moving
2026-09-02 10:10:29 +02:00

157 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Deep clean KG + recompile wiki — only keep entities with real relations.
*/
import path from 'node:path';
import os from 'node:os';
import {
MindDB, FrameStore, KnowledgeGraph, SessionStore,
HybridSearch, createEmbeddingProvider,
} from '@waggle/core';
import { WikiCompiler, CompilationState } from '@waggle/wiki-compiler';
const dataDir = process.env.WAGGLE_DATA_DIR?.replace('~', os.homedir()) ?? path.join(os.homedir(), '.waggle');
const db = new MindDB(path.join(dataDir, 'personal.mind'));
const frameStore = new FrameStore(db);
const kg = new KnowledgeGraph(db);
const sessions = new SessionStore(db);
const embedder = await createEmbeddingProvider({ provider: 'mock' });
const search = new HybridSearch(db, embedder);
const raw = db.getDatabase();
// ── Step 1: Aggressive KG cleanup ─────────────────────────────────
console.log('\n🔥 Deep KG cleanup — keeping only entities with relations or known-good names...');
// Known-good entities to always keep
const KEEP_NAMES = new Set([
'marko markovic', 'waggle os', 'kvark', 'egzakta group', 'lm tek',
'react', 'typescript', 'tauri', 'sqlite', 'fastify', 'clerk', 'stripe',
'mcp protocol', 'hive mind', 'memory harvest', 'eu ai act', 'tier strategy',
'data sovereignty', 'wiki compiler', 'memory mcp',
'adam ramecz', 'aleksandar radojicic', 'alfred friedacher', 'ana petrovi',
'christian fuhrmann', 'briant gerlach', 'alan ford',
'claude', 'claude code', 'anthropic', 'chatgpt', 'openai', 'gemini', 'google',
'microsoft', 'ollama', 'vite', 'tailwind', 'playwright',
'node.js', 'nodejs', 'bun', 'rust', 'python',
'aws', 'azure', 'docker', 'kubernetes',
]);
const allEntities = kg.getEntities(10000);
let retired = 0;
let kept = 0;
const cleanTx = raw.transaction(() => {
for (const e of allEntities) {
const lower = e.name.toLowerCase().trim();
// Always keep known-good
if (KEEP_NAMES.has(lower)) {
kept++;
continue;
}
// Keep entities with actual relations
const outRels = kg.getRelationsFrom(e.id);
const inRels = kg.getRelationsTo(e.id);
if (outRels.length > 0 || inRels.length > 0) {
kept++;
continue;
}
// Keep real people (>2 words, reasonable name pattern)
if (e.entity_type === 'person') {
const words = e.name.split(/\s+/);
if (words.length >= 2 && words.length <= 4 && words.every(w => /^[A-Z][a-z]+$/.test(w))) {
kept++;
continue;
}
}
// Retire everything else
kg.retireEntity(e.id);
retired++;
}
});
cleanTx();
console.log(` Retired: ${retired}`);
console.log(` Kept: ${kept}`);
console.log(` Active entities: ${kg.getEntityCount()}`);
// ── Step 2: Wipe old wiki pages ───────────────────────────────────
console.log('\n🗑 Wiping old wiki pages...');
try {
raw.prepare('DELETE FROM wiki_pages').run();
raw.prepare('DELETE FROM wiki_watermark').run();
console.log(' ✅ Wiki state cleared');
} catch { console.log(' ⏭️ No wiki tables to clear'); }
// ── Step 3: Recompile ─────────────────────────────────────────────
console.log('\n📖 Recompiling wiki with clean data...');
const state = new CompilationState(db);
const compiler = new WikiCompiler(kg, frameStore, search, state, {
synthesize: async (prompt) => {
const frameMatch = prompt.match(/## Source Frames \((\d+) total\)/);
const frameCount = frameMatch ? frameMatch[1] : '?';
const entityMatch = prompt.match(/about "([^"]+)"/) || prompt.match(/about the concept "([^"]+)"/);
const name = entityMatch ? entityMatch[1] : 'this topic';
// Better echo synthesis — parse the prompt for actual frame content
const frameLines = prompt.match(/\[Frame #\d+.*?\]: .+/g) || [];
const uniqueFacts = frameLines.slice(0, 8).map(line => {
const match = line.match(/\[Frame (#\d+).*?\]: (.+)/);
if (match) return `- ${match[2].slice(0, 200)} *(${match[1]})*`;
return null;
}).filter(Boolean);
return [
`## Summary`,
`Synthesized from ${frameCount} source frames about ${name}.`,
'',
...(uniqueFacts.length > 0 ? ['## Key Facts', ...uniqueFacts, ''] : []),
`> *Compiled with echo synthesizer. Connect LLM for deeper synthesis.*`,
].join('\n');
},
});
const concepts = ['Waggle OS', 'KVARK', 'Memory Harvest', 'Wiki Compiler', 'EU AI Act', 'Tier Strategy', 'Data Sovereignty'];
const result = await compiler.compile({ incremental: false, concepts });
console.log(`\n📊 Results:`);
console.log(` Entity pages: ${result.entityPages.length}${result.entityPages.join(', ')}`);
console.log(` Concept pages: ${result.conceptPages.length}${result.conceptPages.join(', ')}`);
console.log(` Synthesis pages: ${result.synthesisPages.length}${result.synthesisPages.join(', ')}`);
console.log(` Total pages: ${result.pagesCreated}`);
console.log(` Duration: ${result.durationMs}ms`);
// ── Step 4: Health ────────────────────────────────────────────────
const health = compiler.compileHealth();
console.log(`\n🏥 Health: ${health.dataQualityScore}/100`);
console.log(` Frames: ${health.totalFrames}, Entities: ${health.totalEntities}, Pages: ${health.totalPages}`);
console.log(` Issues: ${health.issues.length}`);
const highIssues = health.issues.filter(i => i.severity === 'high');
if (highIssues.length > 0) {
console.log(`\n High severity:`);
for (const i of highIssues.slice(0, 5)) {
console.log(`${i.description}`);
}
}
// List all pages
console.log('\n📄 All compiled pages:');
const allPages = state.getAllPages();
for (const p of allPages) {
console.log(` ${p.pageType.padEnd(10)} ${p.name.padEnd(30)} (${p.sourceCount} sources)`);
}
console.log(`\n✅ Deep clean + recompile complete!\n`);
db.close();