ruvnet-kb-first 6.3.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +318 -533
- package/SKILL.md +222 -6
- package/kb-data/kb-embeddings.bin +0 -0
- package/kb-data/kb-entries.json +1 -0
- package/kb-data/kb-loader.js +238 -0
- package/kb-data/kb-metadata.json +71 -0
- package/package.json +3 -1
- package/scripts/kb-export-wasm.js +472 -0
- package/scripts/kb-ingest-template.js +548 -0
- package/scripts/kb-optimize.sql +250 -0
- package/scripts/kb-quality-audit.js +956 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WASM KB Loader - Auto-generated
|
|
3
|
+
*
|
|
4
|
+
* Loads the embedded knowledge base into RvLite WASM.
|
|
5
|
+
* Provides semantic search with ~5ms latency.
|
|
6
|
+
*
|
|
7
|
+
* Content Hash: 67818fd61d6327c3
|
|
8
|
+
* Generated: 2026-01-02T18:29:18.233Z
|
|
9
|
+
* Entries: 16,575
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
15
|
+
|
|
16
|
+
// Initialize WASM on first import
|
|
17
|
+
let wasmInitialized = false;
|
|
18
|
+
let RvLite, Embedder;
|
|
19
|
+
|
|
20
|
+
async function ensureWasmInit() {
|
|
21
|
+
if (!wasmInitialized) {
|
|
22
|
+
// Dynamic import to get the init function
|
|
23
|
+
const rvliteModule = await import('@ruvector/edge-full/rvlite');
|
|
24
|
+
|
|
25
|
+
// Get the wasm file path
|
|
26
|
+
const rvlitePath = path.dirname(fileURLToPath(import.meta.resolve('@ruvector/edge-full/rvlite')));
|
|
27
|
+
const wasmPath = path.join(rvlitePath, 'rvlite_bg.wasm');
|
|
28
|
+
|
|
29
|
+
// Read the wasm file and pass as buffer (Node.js compatible)
|
|
30
|
+
const wasmBuffer = fs.readFileSync(wasmPath);
|
|
31
|
+
|
|
32
|
+
// Initialize with the buffer
|
|
33
|
+
await rvliteModule.default(wasmBuffer);
|
|
34
|
+
|
|
35
|
+
// Get exports
|
|
36
|
+
RvLite = rvliteModule.RvLite;
|
|
37
|
+
Embedder = rvliteModule.Embedder;
|
|
38
|
+
|
|
39
|
+
wasmInitialized = true;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
44
|
+
|
|
45
|
+
// KB Version Info
|
|
46
|
+
export const KB_VERSION = {
|
|
47
|
+
hash: '67818fd61d6327c3',
|
|
48
|
+
exportedAt: '2026-01-02T18:29:18.233Z',
|
|
49
|
+
totalEntries: 16575,
|
|
50
|
+
embeddingDim: 384,
|
|
51
|
+
quantization: 'binary',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Singleton instance
|
|
55
|
+
let db = null;
|
|
56
|
+
let embedder = null;
|
|
57
|
+
let entries = null;
|
|
58
|
+
let isLoaded = false;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check if a newer KB version is available from PostgreSQL
|
|
62
|
+
*/
|
|
63
|
+
export async function checkForUpdates(pgConfig) {
|
|
64
|
+
try {
|
|
65
|
+
const pg = await import('pg');
|
|
66
|
+
const client = new pg.default.Client(pgConfig || {
|
|
67
|
+
host: 'localhost',
|
|
68
|
+
port: 5435,
|
|
69
|
+
database: 'postgres',
|
|
70
|
+
user: 'postgres',
|
|
71
|
+
password: 'guruKB2025',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await client.connect();
|
|
75
|
+
|
|
76
|
+
// Get current hash from PostgreSQL
|
|
77
|
+
const result = await client.query(`
|
|
78
|
+
SELECT MD5(STRING_AGG(id::text || ':' || title || ':' || category, '|' ORDER BY id))::text as hash
|
|
79
|
+
FROM ask_ruvnet.architecture_docs
|
|
80
|
+
WHERE embedding IS NOT NULL AND is_duplicate = false
|
|
81
|
+
`);
|
|
82
|
+
|
|
83
|
+
await client.end();
|
|
84
|
+
|
|
85
|
+
const currentHash = result.rows[0]?.hash?.substring(0, 16) || 'unknown';
|
|
86
|
+
const needsUpdate = currentHash !== KB_VERSION.hash;
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
embeddedHash: KB_VERSION.hash,
|
|
90
|
+
currentHash: currentHash,
|
|
91
|
+
needsUpdate: needsUpdate,
|
|
92
|
+
message: needsUpdate
|
|
93
|
+
? 'KB has been updated. Run: npm update ruvnet-kb-first'
|
|
94
|
+
: 'KB is up to date',
|
|
95
|
+
};
|
|
96
|
+
} catch (e) {
|
|
97
|
+
return {
|
|
98
|
+
embeddedHash: KB_VERSION.hash,
|
|
99
|
+
currentHash: 'unavailable',
|
|
100
|
+
needsUpdate: false,
|
|
101
|
+
message: 'Could not check for updates (PostgreSQL not available)',
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Load the embedded KB into RvLite WASM
|
|
108
|
+
*/
|
|
109
|
+
export async function loadKB() {
|
|
110
|
+
if (isLoaded) return { db, embedder, entries };
|
|
111
|
+
|
|
112
|
+
// Initialize WASM first
|
|
113
|
+
await ensureWasmInit();
|
|
114
|
+
|
|
115
|
+
console.log('Loading embedded KB...');
|
|
116
|
+
const startTime = Date.now();
|
|
117
|
+
|
|
118
|
+
// Load metadata
|
|
119
|
+
const metadataPath = path.join(__dirname, 'kb-metadata.json');
|
|
120
|
+
const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf-8'));
|
|
121
|
+
|
|
122
|
+
// Load entries
|
|
123
|
+
const entriesPath = path.join(__dirname, 'kb-entries.json');
|
|
124
|
+
entries = JSON.parse(fs.readFileSync(entriesPath, 'utf-8'));
|
|
125
|
+
|
|
126
|
+
// Load embeddings
|
|
127
|
+
const embeddingsPath = path.join(__dirname, 'kb-embeddings.bin');
|
|
128
|
+
const embeddingsBuffer = fs.readFileSync(embeddingsPath);
|
|
129
|
+
|
|
130
|
+
// Initialize RvLite with default config (384 dimensions, cosine)
|
|
131
|
+
db = RvLite.default();
|
|
132
|
+
|
|
133
|
+
// Initialize embedder for query embedding
|
|
134
|
+
embedder = new Embedder();
|
|
135
|
+
|
|
136
|
+
// Load vectors into RvLite
|
|
137
|
+
const bytesPerVector = metadata.quantization === 'binary'
|
|
138
|
+
? Math.ceil(metadata.embeddingDim / 8)
|
|
139
|
+
: metadata.embeddingDim * 4;
|
|
140
|
+
|
|
141
|
+
for (let i = 0; i < entries.length; i++) {
|
|
142
|
+
const entry = entries[i];
|
|
143
|
+
const offset = i * bytesPerVector;
|
|
144
|
+
|
|
145
|
+
// For binary quantization, we need to convert back to float32 for RvLite
|
|
146
|
+
// This is a lightweight operation since we're just expanding bits
|
|
147
|
+
let vector;
|
|
148
|
+
if (metadata.quantization === 'binary') {
|
|
149
|
+
const binaryBytes = embeddingsBuffer.slice(offset, offset + bytesPerVector);
|
|
150
|
+
vector = new Float32Array(metadata.embeddingDim);
|
|
151
|
+
for (let j = 0; j < metadata.embeddingDim; j++) {
|
|
152
|
+
const byteIdx = Math.floor(j / 8);
|
|
153
|
+
const bitIdx = 7 - (j % 8);
|
|
154
|
+
vector[j] = (binaryBytes[byteIdx] & (1 << bitIdx)) ? 1.0 : -1.0;
|
|
155
|
+
}
|
|
156
|
+
} else {
|
|
157
|
+
vector = new Float32Array(embeddingsBuffer.buffer, offset, metadata.embeddingDim);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Insert with metadata
|
|
161
|
+
db.insert_with_id(entry.id.toString(), vector, {
|
|
162
|
+
title: entry.title,
|
|
163
|
+
category: entry.category,
|
|
164
|
+
quality: entry.quality,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
isLoaded = true;
|
|
169
|
+
const loadTime = Date.now() - startTime;
|
|
170
|
+
console.log(`KB loaded: ${entries.length.toLocaleString()} entries in ${loadTime}ms`);
|
|
171
|
+
|
|
172
|
+
return { db, embedder, entries };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Semantic search using embedded KB
|
|
177
|
+
*/
|
|
178
|
+
export async function search(query, limit = 10, filter = null) {
|
|
179
|
+
await ensureWasmInit();
|
|
180
|
+
if (!isLoaded) await loadKB();
|
|
181
|
+
|
|
182
|
+
const startTime = Date.now();
|
|
183
|
+
|
|
184
|
+
// Generate query embedding
|
|
185
|
+
const queryVector = embedder.embed(query);
|
|
186
|
+
|
|
187
|
+
// Search
|
|
188
|
+
let results;
|
|
189
|
+
if (filter) {
|
|
190
|
+
results = db.search_with_filter(queryVector, limit, filter);
|
|
191
|
+
} else {
|
|
192
|
+
results = db.search(queryVector, limit);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Enrich results with entry data
|
|
196
|
+
const enrichedResults = results.map(r => {
|
|
197
|
+
const entry = entries.find(e => e.id.toString() === r.id.toString());
|
|
198
|
+
return {
|
|
199
|
+
id: r.id,
|
|
200
|
+
score: r.score,
|
|
201
|
+
distance: 1 - r.score, // Convert similarity score to distance
|
|
202
|
+
title: entry?.title || 'Unknown',
|
|
203
|
+
content: entry?.content || '',
|
|
204
|
+
category: entry?.category || 'general',
|
|
205
|
+
quality: entry?.quality || 0,
|
|
206
|
+
};
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const searchTime = Date.now() - startTime;
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
results: enrichedResults,
|
|
213
|
+
searchTimeMs: searchTime,
|
|
214
|
+
query: query,
|
|
215
|
+
totalEntries: entries.length,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Get KB statistics
|
|
221
|
+
*/
|
|
222
|
+
export function getStats() {
|
|
223
|
+
return {
|
|
224
|
+
version: KB_VERSION,
|
|
225
|
+
loaded: isLoaded,
|
|
226
|
+
entries: entries?.length || 0,
|
|
227
|
+
categories: KB_VERSION.totalEntries > 0 ? 15 : 0,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Export for CommonJS compatibility
|
|
232
|
+
export default {
|
|
233
|
+
loadKB,
|
|
234
|
+
search,
|
|
235
|
+
checkForUpdates,
|
|
236
|
+
getStats,
|
|
237
|
+
KB_VERSION,
|
|
238
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"schema": "ask_ruvnet",
|
|
4
|
+
"exportedAt": "2026-01-02T18:29:18.233Z",
|
|
5
|
+
"totalEntries": 16575,
|
|
6
|
+
"embeddingDim": 384,
|
|
7
|
+
"quantization": "binary",
|
|
8
|
+
"categories": [
|
|
9
|
+
{
|
|
10
|
+
"name": "general",
|
|
11
|
+
"count": 8502
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "agents",
|
|
15
|
+
"count": 4443
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "vector-db",
|
|
19
|
+
"count": 882
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"name": "swarms",
|
|
23
|
+
"count": 735
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "neural",
|
|
27
|
+
"count": 414
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "mcp",
|
|
31
|
+
"count": 259
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "deployment",
|
|
35
|
+
"count": 257
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "sparc",
|
|
39
|
+
"count": 236
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "github",
|
|
43
|
+
"count": 214
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "memory",
|
|
47
|
+
"count": 206
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"name": "performance",
|
|
51
|
+
"count": 184
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "security",
|
|
55
|
+
"count": 127
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "reinforcement-learning",
|
|
59
|
+
"count": 81
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "llm",
|
|
63
|
+
"count": 22
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "consensus",
|
|
67
|
+
"count": 13
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"contentHash": "67818fd61d6327c3"
|
|
71
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ruvnet-kb-first",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.0",
|
|
4
4
|
"description": "RuvNet KB-First Application Builder - Build intelligent applications on expert knowledge",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"url": "https://github.com/ruvnet/kb-first-builder/issues"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
+
"@ruvector/edge-full": "^0.1.0",
|
|
51
52
|
"agentic-flow": "^2.0.1-alpha.43",
|
|
52
53
|
"chalk": "^5.3.0",
|
|
53
54
|
"claude-flow": "^2.7.47",
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
"templates/",
|
|
82
83
|
"scripts/",
|
|
83
84
|
"install/",
|
|
85
|
+
"kb-data/",
|
|
84
86
|
"README.md",
|
|
85
87
|
"SKILL.md"
|
|
86
88
|
]
|