diff options
Diffstat (limited to 'modules/core/module-neural-vfs.js')
| -rw-r--r-- | modules/core/module-neural-vfs.js | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/modules/core/module-neural-vfs.js b/modules/core/module-neural-vfs.js index 32fb0eb..1019299 100644 --- a/modules/core/module-neural-vfs.js +++ b/modules/core/module-neural-vfs.js @@ -33,7 +33,7 @@ class NeuralVFSModule { this._loadAliases(); // Deep Indexing toggle this._deepIndexEnabled = localStorage.getItem('webx11_nvfs_deep') === 'true'; - this._deepModel = localStorage.getItem('webx11_nvfs_deep_model') || 'ministral-3:3b-cloud'; + this._deepModel = localStorage.getItem('webx11_nvfs_deep_model') || 'gemma4:31b-cloud'; this._deepIndexing = false; this._deepQueue = []; this._deepProcessed = 0; @@ -80,6 +80,7 @@ class NeuralVFSModule { this.commands['nvfs-sync'] = async (args) => this.nvfsSync(args); this.commands['nvfs-save'] = async (args) => this.nvfsSave(); this.commands['nvfs-cancel'] = (args) => this.cancelIndex(); + this.commands['nvfs-index-graph'] = () => this.indexGraphFacts(); } // ── Core Index Builder (async, chunked) ── @@ -1044,6 +1045,61 @@ Concepts:`; } } } + + // v4.5.89: Semantic bridge — mirror graph facts into VFS for unified search + indexGraphFacts() { + const mg = this.terminal.moduleManager.modules['MemoryGraphModule']; + if (!mg) return this.terminal.print('❌ Memory Graph module not loaded', 'error'); + const fs = this.terminal.fs; + if (!fs) return this.terminal.print('❌ VFS not available', 'error'); + + const factNodes = Object.values(mg._nodes).filter(function(n) { + return n.type === 'concept' || n.type === 'fact' || n.type === 'entity' || n.type === 'task'; + }); + + if (factNodes.length === 0) { + return this.terminal.print('No graph fact nodes to index. Use memgraph-learn first.', 'info'); + } + + if (!fs.readDir('/_graph_facts')) fs.mkdir('_graph_facts'); + + // v4.5.89b fix: Clean stale files for deleted nodes (P2 from review) + const validKeys = new Set(factNodes.map(function(n) { return n.id.replace(/[^a-zA-Z0-9_-]/g, '_') + '.txt'; })); + try { + const existing = fs.readDir('/_graph_facts') || []; + for (const f of existing) { + if (!validKeys.has(f)) fs.deleteFile('/_graph_facts/' + f); + } + } catch (_) {} + + let indexed = 0; + for (const node of factNodes) { + let content = node.label + '\n'; + if (node.metadata) { + if (node.metadata.full) content += node.metadata.full + '\n'; + if (node.metadata.result) content += 'Result: ' + node.metadata.result + '\n'; + } + content += 'Type: ' + node.type + '\n'; + content += 'Namespace: ' + (node.namespace || 'global') + '\n'; + if (node.source_session) content += 'Session: ' + node.source_session + '\n'; + const safeName = node.id.replace(/[^a-zA-Z0-9_-]/g, '_'); + fs.writeFile('/_graph_facts/' + safeName + '.txt', content); + indexed++; + } + + this.terminal.print('🔗 Indexed ' + indexed + ' graph facts into /_graph_facts/', 'success'); + this.terminal.print(' Run nvfs-index to include them in semantic search', 'info'); + } + + // v4.5.89b: Index a single fact — O(1) instead of O(n) re-index (P2 from review) + indexSingleFact(factKey, entity, fact) { + const fs = this.terminal.fs; + if (!fs) return; + if (!fs.readDir('/_graph_facts')) fs.mkdir('_graph_facts'); + const safeName = factKey.replace(/[^a-zA-Z0-9_-]/g, '_'); + const content = entity + '\n' + fact + '\nType: fact\nNamespace: global\n'; + fs.writeFile('/_graph_facts/' + safeName + '.txt', content); + } } // Required for module system |