ruvector 0.2.18 → 0.2.19
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 +20 -7
- package/bin/cli.js +1430 -1553
- package/bin/mcp-server.js +277 -930
- package/package.json +19 -17
package/bin/mcp-server.js
CHANGED
|
@@ -95,71 +95,6 @@ function sanitizeNumericArg(arg, defaultVal) {
|
|
|
95
95
|
return Number.isFinite(n) && n > 0 ? n : (defaultVal || 0);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
// ── Proxy-aware fetch wrapper ───────────────────────────────────────────────
|
|
99
|
-
let _proxyDispatcherSet = false;
|
|
100
|
-
|
|
101
|
-
function getProxyUrl(targetUrl) {
|
|
102
|
-
const NO_PROXY = process.env.NO_PROXY || process.env.no_proxy || '';
|
|
103
|
-
if (NO_PROXY === '*') return null;
|
|
104
|
-
if (NO_PROXY) {
|
|
105
|
-
try {
|
|
106
|
-
const host = new URL(targetUrl).hostname.toLowerCase();
|
|
107
|
-
const patterns = NO_PROXY.split(',').map(p => p.trim().toLowerCase());
|
|
108
|
-
for (const p of patterns) {
|
|
109
|
-
if (!p) continue;
|
|
110
|
-
if (host === p || host.endsWith(p.startsWith('.') ? p : '.' + p)) return null;
|
|
111
|
-
}
|
|
112
|
-
} catch {}
|
|
113
|
-
}
|
|
114
|
-
return process.env.HTTPS_PROXY || process.env.https_proxy
|
|
115
|
-
|| process.env.HTTP_PROXY || process.env.http_proxy
|
|
116
|
-
|| process.env.ALL_PROXY || process.env.all_proxy
|
|
117
|
-
|| null;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function proxyFetch(url, opts) {
|
|
121
|
-
const target = typeof url === 'string' ? url : url.toString();
|
|
122
|
-
const proxy = getProxyUrl(target);
|
|
123
|
-
if (!proxy) return fetch(url, opts);
|
|
124
|
-
|
|
125
|
-
if (!_proxyDispatcherSet) {
|
|
126
|
-
try {
|
|
127
|
-
const undici = require('undici');
|
|
128
|
-
if (undici.ProxyAgent && undici.setGlobalDispatcher) {
|
|
129
|
-
undici.setGlobalDispatcher(new undici.ProxyAgent(proxy));
|
|
130
|
-
_proxyDispatcherSet = true;
|
|
131
|
-
}
|
|
132
|
-
} catch {}
|
|
133
|
-
}
|
|
134
|
-
if (_proxyDispatcherSet) return fetch(url, opts);
|
|
135
|
-
|
|
136
|
-
const { execFileSync } = require('child_process');
|
|
137
|
-
const args = ['-sS', '-L', '--max-time', '30'];
|
|
138
|
-
if (opts && opts.method) { args.push('-X', opts.method); }
|
|
139
|
-
if (opts && opts.headers) {
|
|
140
|
-
for (const [k, v] of Object.entries(opts.headers)) {
|
|
141
|
-
args.push('-H', `${k}: ${v}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (opts && opts.body) { args.push('-d', typeof opts.body === 'string' ? opts.body : JSON.stringify(opts.body)); }
|
|
145
|
-
args.push(target);
|
|
146
|
-
try {
|
|
147
|
-
const stdout = execFileSync('curl', args, { encoding: 'utf8', timeout: 35000 });
|
|
148
|
-
const body = stdout.trim();
|
|
149
|
-
return {
|
|
150
|
-
ok: true,
|
|
151
|
-
status: 200,
|
|
152
|
-
statusText: 'OK',
|
|
153
|
-
text: async () => body,
|
|
154
|
-
json: async () => JSON.parse(body),
|
|
155
|
-
headers: new Map(),
|
|
156
|
-
};
|
|
157
|
-
} catch (e) {
|
|
158
|
-
const msg = e.stderr ? e.stderr.toString().trim() : e.message;
|
|
159
|
-
throw new Error(`Proxy curl failed: ${msg}`);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
98
|
// Try to load the full IntelligenceEngine
|
|
164
99
|
let IntelligenceEngine = null;
|
|
165
100
|
let engineAvailable = false;
|
|
@@ -428,7 +363,7 @@ class Intelligence {
|
|
|
428
363
|
const server = new Server(
|
|
429
364
|
{
|
|
430
365
|
name: 'ruvector',
|
|
431
|
-
version: '0.2.
|
|
366
|
+
version: '0.2.0',
|
|
432
367
|
},
|
|
433
368
|
{
|
|
434
369
|
capabilities: {
|
|
@@ -1289,12 +1224,11 @@ const TOOLS = [
|
|
|
1289
1224
|
},
|
|
1290
1225
|
{
|
|
1291
1226
|
name: 'rvf_examples',
|
|
1292
|
-
description: 'List available example .rvf files with download URLs
|
|
1227
|
+
description: 'List available example .rvf files with download URLs from the ruvector repository',
|
|
1293
1228
|
inputSchema: {
|
|
1294
1229
|
type: 'object',
|
|
1295
1230
|
properties: {
|
|
1296
|
-
filter: { type: 'string', description: 'Filter examples by name or description substring' }
|
|
1297
|
-
category: { type: 'string', description: 'Filter by category (core, ai, security, compute, lineage, industry, network, integration)' }
|
|
1231
|
+
filter: { type: 'string', description: 'Filter examples by name or description substring' }
|
|
1298
1232
|
},
|
|
1299
1233
|
required: []
|
|
1300
1234
|
}
|
|
@@ -1336,7 +1270,8 @@ const TOOLS = [
|
|
|
1336
1270
|
required: ['query']
|
|
1337
1271
|
}
|
|
1338
1272
|
},
|
|
1339
|
-
|
|
1273
|
+
|
|
1274
|
+
// ── Brain Tools (Shared Intelligence) ─────────────────────────────────
|
|
1340
1275
|
{
|
|
1341
1276
|
name: 'brain_search',
|
|
1342
1277
|
description: 'Semantic search across shared brain knowledge',
|
|
@@ -1344,67 +1279,64 @@ const TOOLS = [
|
|
|
1344
1279
|
type: 'object',
|
|
1345
1280
|
properties: {
|
|
1346
1281
|
query: { type: 'string', description: 'Search query' },
|
|
1347
|
-
|
|
1348
|
-
|
|
1282
|
+
limit: { type: 'number', description: 'Max results to return', default: 10 },
|
|
1283
|
+
category: { type: 'string', description: 'Filter by category (optional)' }
|
|
1349
1284
|
},
|
|
1350
1285
|
required: ['query']
|
|
1351
1286
|
}
|
|
1352
1287
|
},
|
|
1353
1288
|
{
|
|
1354
1289
|
name: 'brain_share',
|
|
1355
|
-
description: 'Share
|
|
1290
|
+
description: 'Share knowledge with the collective brain',
|
|
1356
1291
|
inputSchema: {
|
|
1357
1292
|
type: 'object',
|
|
1358
1293
|
properties: {
|
|
1359
1294
|
title: { type: 'string', description: 'Title of the knowledge entry' },
|
|
1360
|
-
content: { type: 'string', description: '
|
|
1361
|
-
category: { type: 'string', description: 'Category (pattern,
|
|
1362
|
-
tags: { type: 'string', description: '
|
|
1363
|
-
code_snippet: { type: 'string', description: 'Optional code snippet' }
|
|
1295
|
+
content: { type: 'string', description: 'Knowledge content to share' },
|
|
1296
|
+
category: { type: 'string', description: 'Category (pattern, architecture, security, etc.)', default: 'pattern' },
|
|
1297
|
+
tags: { type: 'array', items: { type: 'string' }, description: 'Tags for the entry' }
|
|
1364
1298
|
},
|
|
1365
|
-
required: ['title', 'content'
|
|
1299
|
+
required: ['title', 'content']
|
|
1366
1300
|
}
|
|
1367
1301
|
},
|
|
1368
1302
|
{
|
|
1369
1303
|
name: 'brain_get',
|
|
1370
|
-
description: 'Retrieve a specific memory by ID with
|
|
1304
|
+
description: 'Retrieve a specific memory by ID with provenance',
|
|
1371
1305
|
inputSchema: {
|
|
1372
1306
|
type: 'object',
|
|
1373
1307
|
properties: {
|
|
1374
|
-
id: { type: 'string', description: 'Memory ID' }
|
|
1308
|
+
id: { type: 'string', description: 'Memory ID to retrieve' }
|
|
1375
1309
|
},
|
|
1376
1310
|
required: ['id']
|
|
1377
1311
|
}
|
|
1378
1312
|
},
|
|
1379
1313
|
{
|
|
1380
1314
|
name: 'brain_vote',
|
|
1381
|
-
description: '
|
|
1315
|
+
description: 'Vote on knowledge quality',
|
|
1382
1316
|
inputSchema: {
|
|
1383
1317
|
type: 'object',
|
|
1384
1318
|
properties: {
|
|
1385
|
-
id: { type: 'string', description: 'Memory ID' },
|
|
1386
|
-
direction: { type: 'string', description: 'Vote direction
|
|
1319
|
+
id: { type: 'string', description: 'Memory ID to vote on' },
|
|
1320
|
+
direction: { type: 'string', enum: ['up', 'down'], description: 'Vote direction' }
|
|
1387
1321
|
},
|
|
1388
1322
|
required: ['id', 'direction']
|
|
1389
1323
|
}
|
|
1390
1324
|
},
|
|
1391
1325
|
{
|
|
1392
1326
|
name: 'brain_list',
|
|
1393
|
-
description: 'List recent shared memories
|
|
1327
|
+
description: 'List recent shared memories',
|
|
1394
1328
|
inputSchema: {
|
|
1395
1329
|
type: 'object',
|
|
1396
1330
|
properties: {
|
|
1397
|
-
category: { type: 'string', description: 'Filter by category' },
|
|
1398
|
-
limit: { type: 'number', description: 'Max results
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
tags: { type: 'string', description: 'Filter by tags (comma-separated)' }
|
|
1402
|
-
}
|
|
1331
|
+
category: { type: 'string', description: 'Filter by category (optional)' },
|
|
1332
|
+
limit: { type: 'number', description: 'Max results to return', default: 20 }
|
|
1333
|
+
},
|
|
1334
|
+
required: []
|
|
1403
1335
|
}
|
|
1404
1336
|
},
|
|
1405
1337
|
{
|
|
1406
1338
|
name: 'brain_delete',
|
|
1407
|
-
description: 'Delete your own contribution
|
|
1339
|
+
description: 'Delete your own contribution',
|
|
1408
1340
|
inputSchema: {
|
|
1409
1341
|
type: 'object',
|
|
1410
1342
|
properties: {
|
|
@@ -1415,302 +1347,122 @@ const TOOLS = [
|
|
|
1415
1347
|
},
|
|
1416
1348
|
{
|
|
1417
1349
|
name: 'brain_status',
|
|
1418
|
-
description: 'Get
|
|
1350
|
+
description: 'Get brain system health and statistics',
|
|
1419
1351
|
inputSchema: {
|
|
1420
1352
|
type: 'object',
|
|
1421
|
-
properties: {}
|
|
1353
|
+
properties: {},
|
|
1354
|
+
required: []
|
|
1422
1355
|
}
|
|
1423
1356
|
},
|
|
1424
1357
|
{
|
|
1425
1358
|
name: 'brain_drift',
|
|
1426
|
-
description: 'Check
|
|
1359
|
+
description: 'Check knowledge drift',
|
|
1427
1360
|
inputSchema: {
|
|
1428
1361
|
type: 'object',
|
|
1429
1362
|
properties: {
|
|
1430
|
-
domain: { type: 'string', description: 'Domain to check drift for' }
|
|
1431
|
-
}
|
|
1363
|
+
domain: { type: 'string', description: 'Domain to check drift for (optional)' }
|
|
1364
|
+
},
|
|
1365
|
+
required: []
|
|
1432
1366
|
}
|
|
1433
1367
|
},
|
|
1434
1368
|
{
|
|
1435
1369
|
name: 'brain_partition',
|
|
1436
|
-
description: 'Get knowledge
|
|
1370
|
+
description: 'Get knowledge topology via mincut',
|
|
1437
1371
|
inputSchema: {
|
|
1438
1372
|
type: 'object',
|
|
1439
1373
|
properties: {
|
|
1440
|
-
domain: { type: 'string', description: 'Domain to partition' },
|
|
1441
|
-
min_cluster_size: { type: 'number', description: 'Minimum cluster size
|
|
1442
|
-
}
|
|
1374
|
+
domain: { type: 'string', description: 'Domain to partition (optional)' },
|
|
1375
|
+
min_cluster_size: { type: 'number', description: 'Minimum cluster size', default: 3 }
|
|
1376
|
+
},
|
|
1377
|
+
required: []
|
|
1443
1378
|
}
|
|
1444
1379
|
},
|
|
1445
1380
|
{
|
|
1446
1381
|
name: 'brain_transfer',
|
|
1447
|
-
description: '
|
|
1382
|
+
description: 'Transfer learned priors between domains',
|
|
1448
1383
|
inputSchema: {
|
|
1449
1384
|
type: 'object',
|
|
1450
1385
|
properties: {
|
|
1451
|
-
|
|
1452
|
-
|
|
1386
|
+
source: { type: 'string', description: 'Source domain' },
|
|
1387
|
+
target: { type: 'string', description: 'Target domain' }
|
|
1453
1388
|
},
|
|
1454
|
-
required: ['
|
|
1389
|
+
required: ['source', 'target']
|
|
1455
1390
|
}
|
|
1456
1391
|
},
|
|
1457
1392
|
{
|
|
1458
1393
|
name: 'brain_sync',
|
|
1459
|
-
description: '
|
|
1460
|
-
inputSchema: {
|
|
1461
|
-
type: 'object',
|
|
1462
|
-
properties: {
|
|
1463
|
-
direction: { type: 'string', description: 'Sync direction: pull, push, or both (default both)' }
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
},
|
|
1467
|
-
{
|
|
1468
|
-
name: 'brain_train',
|
|
1469
|
-
description: 'Trigger a training cycle — runs SONA pattern learning and domain evolution on accumulated data',
|
|
1470
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1471
|
-
},
|
|
1472
|
-
// ── Brain AGI Tools (6) ── AGI subsystem diagnostics via direct fetch ──
|
|
1473
|
-
{
|
|
1474
|
-
name: 'brain_agi_status',
|
|
1475
|
-
description: 'Combined AGI subsystem diagnostics — SONA, GWT, temporal, meta-learning, midstream',
|
|
1476
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1477
|
-
},
|
|
1478
|
-
{
|
|
1479
|
-
name: 'brain_sona_stats',
|
|
1480
|
-
description: 'SONA learning engine stats — patterns, trajectories, background ticks',
|
|
1481
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1482
|
-
},
|
|
1483
|
-
{
|
|
1484
|
-
name: 'brain_temporal',
|
|
1485
|
-
description: 'Temporal delta tracking — velocity, trend, total deltas',
|
|
1486
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1487
|
-
},
|
|
1488
|
-
{
|
|
1489
|
-
name: 'brain_explore',
|
|
1490
|
-
description: 'Meta-learning exploration — curiosity, regret, plateau status, Pareto frontier',
|
|
1491
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1492
|
-
},
|
|
1493
|
-
{
|
|
1494
|
-
name: 'brain_midstream',
|
|
1495
|
-
description: 'Midstream platform diagnostics — scheduler, attractor, solver, strange-loop',
|
|
1496
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1497
|
-
},
|
|
1498
|
-
{
|
|
1499
|
-
name: 'brain_flags',
|
|
1500
|
-
description: 'Show backend feature flag state (RVF, AGI, midstream flags)',
|
|
1501
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1502
|
-
},
|
|
1503
|
-
// ── Brainpedia Page Tools (5) ── Knowledge page management ──
|
|
1504
|
-
{
|
|
1505
|
-
name: 'brain_page_list',
|
|
1506
|
-
description: 'List Brainpedia knowledge pages with pagination and status filter',
|
|
1507
|
-
inputSchema: {
|
|
1508
|
-
type: 'object',
|
|
1509
|
-
properties: {
|
|
1510
|
-
limit: { type: 'number', description: 'Max pages to return (default 20)' },
|
|
1511
|
-
offset: { type: 'number', description: 'Skip first N pages for pagination (default 0)' },
|
|
1512
|
-
status: { type: 'string', description: 'Filter by status: draft, canonical, contested, archived' }
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
},
|
|
1516
|
-
{
|
|
1517
|
-
name: 'brain_page_get',
|
|
1518
|
-
description: 'Get a Brainpedia page by ID with delta log and evidence links',
|
|
1519
|
-
inputSchema: {
|
|
1520
|
-
type: 'object',
|
|
1521
|
-
properties: {
|
|
1522
|
-
id: { type: 'string', description: 'Page ID (UUID or slug)' }
|
|
1523
|
-
},
|
|
1524
|
-
required: ['id']
|
|
1525
|
-
}
|
|
1526
|
-
},
|
|
1527
|
-
{
|
|
1528
|
-
name: 'brain_page_create',
|
|
1529
|
-
description: 'Create a new Brainpedia knowledge page (requires reputation >= 0.5)',
|
|
1530
|
-
inputSchema: {
|
|
1531
|
-
type: 'object',
|
|
1532
|
-
properties: {
|
|
1533
|
-
title: { type: 'string', description: 'Page title' },
|
|
1534
|
-
content: { type: 'string', description: 'Page content body' },
|
|
1535
|
-
category: { type: 'string', description: 'Category (pattern, solution, architecture, convention, security, performance, tooling)' },
|
|
1536
|
-
tags: { type: 'string', description: 'Comma-separated tags' },
|
|
1537
|
-
code_snippet: { type: 'string', description: 'Optional code snippet' }
|
|
1538
|
-
},
|
|
1539
|
-
required: ['title', 'content', 'category']
|
|
1540
|
-
}
|
|
1541
|
-
},
|
|
1542
|
-
{
|
|
1543
|
-
name: 'brain_page_update',
|
|
1544
|
-
description: 'Submit a delta (correction, extension, evidence) to a Brainpedia page',
|
|
1545
|
-
inputSchema: {
|
|
1546
|
-
type: 'object',
|
|
1547
|
-
properties: {
|
|
1548
|
-
page_id: { type: 'string', description: 'Page ID to update' },
|
|
1549
|
-
delta_type: { type: 'string', description: 'Delta type: correction, extension, evidence, deprecation' },
|
|
1550
|
-
content_diff: { type: 'string', description: 'Content diff or new content' },
|
|
1551
|
-
evidence_links: { type: 'string', description: 'JSON array of evidence links' }
|
|
1552
|
-
},
|
|
1553
|
-
required: ['page_id', 'content_diff']
|
|
1554
|
-
}
|
|
1555
|
-
},
|
|
1556
|
-
{
|
|
1557
|
-
name: 'brain_page_delete',
|
|
1558
|
-
description: 'Delete a Brainpedia page by ID',
|
|
1394
|
+
description: 'Sync LoRA weights',
|
|
1559
1395
|
inputSchema: {
|
|
1560
1396
|
type: 'object',
|
|
1561
1397
|
properties: {
|
|
1562
|
-
|
|
1398
|
+
direction: { type: 'string', enum: ['pull', 'push', 'both'], description: 'Sync direction', default: 'both' }
|
|
1563
1399
|
},
|
|
1564
|
-
required: [
|
|
1565
|
-
}
|
|
1566
|
-
},
|
|
1567
|
-
// ── WASM Node Tools (4) ── Executable compute node management ──
|
|
1568
|
-
{
|
|
1569
|
-
name: 'brain_node_list',
|
|
1570
|
-
description: 'List published WASM compute nodes',
|
|
1571
|
-
inputSchema: {
|
|
1572
|
-
type: 'object',
|
|
1573
|
-
properties: {
|
|
1574
|
-
limit: { type: 'number', description: 'Max nodes to return (default 20)' }
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
},
|
|
1578
|
-
{
|
|
1579
|
-
name: 'brain_node_get',
|
|
1580
|
-
description: 'Get WASM compute node metadata and conformance vectors',
|
|
1581
|
-
inputSchema: {
|
|
1582
|
-
type: 'object',
|
|
1583
|
-
properties: {
|
|
1584
|
-
id: { type: 'string', description: 'Node ID' }
|
|
1585
|
-
},
|
|
1586
|
-
required: ['id']
|
|
1587
|
-
}
|
|
1588
|
-
},
|
|
1589
|
-
{
|
|
1590
|
-
name: 'brain_node_publish',
|
|
1591
|
-
description: 'Publish a WASM compute node to the shared brain network',
|
|
1592
|
-
inputSchema: {
|
|
1593
|
-
type: 'object',
|
|
1594
|
-
properties: {
|
|
1595
|
-
name: { type: 'string', description: 'Node name' },
|
|
1596
|
-
wasm_base64: { type: 'string', description: 'Base64-encoded WASM binary' },
|
|
1597
|
-
description: { type: 'string', description: 'Node description' },
|
|
1598
|
-
conformance_vectors: { type: 'string', description: 'JSON array of conformance test vectors' }
|
|
1599
|
-
},
|
|
1600
|
-
required: ['name', 'wasm_base64']
|
|
1601
|
-
}
|
|
1602
|
-
},
|
|
1603
|
-
{
|
|
1604
|
-
name: 'brain_node_revoke',
|
|
1605
|
-
description: 'Revoke a published WASM compute node',
|
|
1606
|
-
inputSchema: {
|
|
1607
|
-
type: 'object',
|
|
1608
|
-
properties: {
|
|
1609
|
-
id: { type: 'string', description: 'Node ID to revoke' }
|
|
1610
|
-
},
|
|
1611
|
-
required: ['id']
|
|
1612
|
-
}
|
|
1613
|
-
},
|
|
1614
|
-
// ── Midstream Tools (6) ── Real-time streaming analysis platform ──
|
|
1615
|
-
{
|
|
1616
|
-
name: 'midstream_status',
|
|
1617
|
-
description: 'Full midstream platform diagnostics — scheduler, attractor, solver, strange-loop',
|
|
1618
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1619
|
-
},
|
|
1620
|
-
{
|
|
1621
|
-
name: 'midstream_attractor',
|
|
1622
|
-
description: 'Attractor categories with Lyapunov exponent analysis',
|
|
1623
|
-
inputSchema: {
|
|
1624
|
-
type: 'object',
|
|
1625
|
-
properties: {
|
|
1626
|
-
category: { type: 'string', description: 'Optional category to filter (e.g., pattern, solution)' }
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
},
|
|
1630
|
-
{
|
|
1631
|
-
name: 'midstream_scheduler',
|
|
1632
|
-
description: 'Nanosecond scheduler performance metrics — ticks, tasks/sec',
|
|
1633
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1634
|
-
},
|
|
1635
|
-
{
|
|
1636
|
-
name: 'midstream_benchmark',
|
|
1637
|
-
description: 'Run sequential + concurrent latency benchmark against brain backend',
|
|
1638
|
-
inputSchema: {
|
|
1639
|
-
type: 'object',
|
|
1640
|
-
properties: {
|
|
1641
|
-
concurrent_count: { type: 'number', description: 'Number of concurrent search requests (default 20, max 100)' }
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
},
|
|
1645
|
-
{
|
|
1646
|
-
name: 'midstream_search',
|
|
1647
|
-
description: 'Semantic search with midstream scoring metadata in response',
|
|
1648
|
-
inputSchema: {
|
|
1649
|
-
type: 'object',
|
|
1650
|
-
properties: {
|
|
1651
|
-
query: { type: 'string', description: 'Search query' },
|
|
1652
|
-
limit: { type: 'number', description: 'Max results (default 10)' }
|
|
1653
|
-
},
|
|
1654
|
-
required: ['query']
|
|
1400
|
+
required: []
|
|
1655
1401
|
}
|
|
1656
1402
|
},
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
description: 'Combined health + midstream subsystem check',
|
|
1660
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1661
|
-
},
|
|
1662
|
-
// ── Edge Tools (4) ── Distributed compute via @ruvector/edge-net ──
|
|
1403
|
+
|
|
1404
|
+
// ── Edge Tools (Distributed Compute) ──────────────────────────────────
|
|
1663
1405
|
{
|
|
1664
1406
|
name: 'edge_status',
|
|
1665
|
-
description: '
|
|
1407
|
+
description: 'Query edge network status',
|
|
1666
1408
|
inputSchema: {
|
|
1667
1409
|
type: 'object',
|
|
1668
|
-
properties: {}
|
|
1410
|
+
properties: {},
|
|
1411
|
+
required: []
|
|
1669
1412
|
}
|
|
1670
1413
|
},
|
|
1671
1414
|
{
|
|
1672
1415
|
name: 'edge_join',
|
|
1673
|
-
description: 'Join
|
|
1416
|
+
description: 'Join as compute node',
|
|
1674
1417
|
inputSchema: {
|
|
1675
1418
|
type: 'object',
|
|
1676
1419
|
properties: {
|
|
1677
|
-
contribution: { type: 'number', description: 'Contribution
|
|
1678
|
-
|
|
1420
|
+
contribution: { type: 'number', description: 'Contribution factor (0-1)', default: 0.3 },
|
|
1421
|
+
key: { type: 'string', description: 'PI key (optional, defaults to PI env var)' }
|
|
1422
|
+
},
|
|
1423
|
+
required: []
|
|
1679
1424
|
}
|
|
1680
1425
|
},
|
|
1681
1426
|
{
|
|
1682
1427
|
name: 'edge_balance',
|
|
1683
|
-
description: 'Check rUv
|
|
1428
|
+
description: 'Check rUv balance',
|
|
1684
1429
|
inputSchema: {
|
|
1685
1430
|
type: 'object',
|
|
1686
|
-
properties: {
|
|
1431
|
+
properties: {
|
|
1432
|
+
key: { type: 'string', description: 'PI key (optional, defaults to PI env var)' }
|
|
1433
|
+
},
|
|
1434
|
+
required: []
|
|
1687
1435
|
}
|
|
1688
1436
|
},
|
|
1689
1437
|
{
|
|
1690
1438
|
name: 'edge_tasks',
|
|
1691
|
-
description: 'List available distributed compute tasks
|
|
1439
|
+
description: 'List available distributed compute tasks',
|
|
1692
1440
|
inputSchema: {
|
|
1693
1441
|
type: 'object',
|
|
1694
|
-
properties: {
|
|
1695
|
-
|
|
1696
|
-
}
|
|
1442
|
+
properties: {},
|
|
1443
|
+
required: []
|
|
1697
1444
|
}
|
|
1698
1445
|
},
|
|
1699
|
-
|
|
1446
|
+
|
|
1447
|
+
// ── Identity Tools (PI Key Management) ────────────────────────────────
|
|
1700
1448
|
{
|
|
1701
1449
|
name: 'identity_generate',
|
|
1702
|
-
description: 'Generate a new
|
|
1450
|
+
description: 'Generate a new PI key with SHAKE-256 pseudonym',
|
|
1703
1451
|
inputSchema: {
|
|
1704
1452
|
type: 'object',
|
|
1705
|
-
properties: {}
|
|
1453
|
+
properties: {},
|
|
1454
|
+
required: []
|
|
1706
1455
|
}
|
|
1707
1456
|
},
|
|
1708
1457
|
{
|
|
1709
1458
|
name: 'identity_show',
|
|
1710
|
-
description: 'Show current
|
|
1459
|
+
description: 'Show current identity derived from PI key',
|
|
1711
1460
|
inputSchema: {
|
|
1712
1461
|
type: 'object',
|
|
1713
|
-
properties: {
|
|
1462
|
+
properties: {
|
|
1463
|
+
key: { type: 'string', description: 'PI key (optional, defaults to PI env var)' }
|
|
1464
|
+
},
|
|
1465
|
+
required: []
|
|
1714
1466
|
}
|
|
1715
1467
|
}
|
|
1716
1468
|
];
|
|
@@ -3054,15 +2806,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3054
2806
|
}
|
|
3055
2807
|
|
|
3056
2808
|
case 'workers_create': {
|
|
3057
|
-
const name =
|
|
3058
|
-
const preset =
|
|
3059
|
-
const triggers = args.triggers
|
|
3060
|
-
if (!name) {
|
|
3061
|
-
return { content: [{ type: 'text', text: JSON.stringify({
|
|
3062
|
-
success: false,
|
|
3063
|
-
error: 'Invalid worker name'
|
|
3064
|
-
}, null, 2) }] };
|
|
3065
|
-
}
|
|
2809
|
+
const name = args.name;
|
|
2810
|
+
const preset = args.preset || 'quick-scan';
|
|
2811
|
+
const triggers = args.triggers;
|
|
3066
2812
|
try {
|
|
3067
2813
|
let cmd = `npx agentic-flow@alpha workers create "${name}" --preset ${preset}`;
|
|
3068
2814
|
if (triggers) cmd += ` --triggers "${triggers}"`;
|
|
@@ -3292,85 +3038,31 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3292
3038
|
}
|
|
3293
3039
|
|
|
3294
3040
|
case 'rvf_examples': {
|
|
3295
|
-
const
|
|
3296
|
-
const
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
// Fetch from GCS if no fresh cache
|
|
3313
|
-
if (!manifest) {
|
|
3314
|
-
try {
|
|
3315
|
-
const resp = await proxyFetch(GCS_MANIFEST, { signal: AbortSignal.timeout(15000) });
|
|
3316
|
-
if (resp.ok) {
|
|
3317
|
-
manifest = await resp.json();
|
|
3318
|
-
try {
|
|
3319
|
-
fs.mkdirSync(cacheDir, { recursive: true });
|
|
3320
|
-
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
3321
|
-
} catch {}
|
|
3322
|
-
}
|
|
3323
|
-
} catch {}
|
|
3324
|
-
}
|
|
3325
|
-
|
|
3326
|
-
// Fallback to hardcoded
|
|
3327
|
-
if (!manifest) {
|
|
3328
|
-
manifest = {
|
|
3329
|
-
version: 'builtin',
|
|
3330
|
-
base_url: GITHUB_RAW,
|
|
3331
|
-
examples: [
|
|
3332
|
-
{ name: 'basic_store', size_human: '152 KB', description: '1,000 vectors, dim 128', category: 'core' },
|
|
3333
|
-
{ name: 'semantic_search', size_human: '755 KB', description: 'Semantic search with HNSW', category: 'core' },
|
|
3334
|
-
{ name: 'rag_pipeline', size_human: '303 KB', description: 'RAG pipeline embeddings', category: 'core' },
|
|
3335
|
-
{ name: 'agent_memory', size_human: '32 KB', description: 'AI agent episodic memory', category: 'ai' },
|
|
3336
|
-
{ name: 'swarm_knowledge', size_human: '86 KB', description: 'Multi-agent knowledge base', category: 'ai' },
|
|
3337
|
-
{ name: 'self_booting', size_human: '31 KB', description: 'Self-booting with kernel', category: 'compute' },
|
|
3338
|
-
{ name: 'ebpf_accelerator', size_human: '153 KB', description: 'eBPF distance accelerator', category: 'compute' },
|
|
3339
|
-
{ name: 'tee_attestation', size_human: '102 KB', description: 'TEE attestation + witnesses', category: 'security' },
|
|
3340
|
-
{ name: 'claude_code_appliance', size_human: '17 KB', description: 'Claude Code appliance', category: 'integration' },
|
|
3341
|
-
{ name: 'lineage_parent', size_human: '52 KB', description: 'COW parent file', category: 'lineage' },
|
|
3342
|
-
{ name: 'financial_signals', size_human: '202 KB', description: 'Financial signals', category: 'industry' },
|
|
3343
|
-
{ name: 'progressive_index', size_human: '2.5 MB', description: 'Large-scale HNSW index', category: 'core' },
|
|
3344
|
-
]
|
|
3345
|
-
};
|
|
3346
|
-
}
|
|
3347
|
-
|
|
3348
|
-
let examples = manifest.examples || [];
|
|
3349
|
-
const baseUrl = manifest.base_url || GITHUB_RAW;
|
|
3350
|
-
|
|
3041
|
+
const BASE_URL = 'https://raw.githubusercontent.com/ruvnet/ruvector/main/examples/rvf/output';
|
|
3042
|
+
const examples = [
|
|
3043
|
+
{ name: 'basic_store', size: '152 KB', desc: '1,000 vectors, dim 128' },
|
|
3044
|
+
{ name: 'semantic_search', size: '755 KB', desc: 'Semantic search with HNSW' },
|
|
3045
|
+
{ name: 'rag_pipeline', size: '303 KB', desc: 'RAG pipeline embeddings' },
|
|
3046
|
+
{ name: 'agent_memory', size: '32 KB', desc: 'AI agent episodic memory' },
|
|
3047
|
+
{ name: 'swarm_knowledge', size: '86 KB', desc: 'Multi-agent knowledge base' },
|
|
3048
|
+
{ name: 'self_booting', size: '31 KB', desc: 'Self-booting with kernel' },
|
|
3049
|
+
{ name: 'ebpf_accelerator', size: '153 KB', desc: 'eBPF distance accelerator' },
|
|
3050
|
+
{ name: 'tee_attestation', size: '102 KB', desc: 'TEE attestation + witnesses' },
|
|
3051
|
+
{ name: 'lineage_parent', size: '52 KB', desc: 'COW parent file' },
|
|
3052
|
+
{ name: 'lineage_child', size: '26 KB', desc: 'COW child (derived)' },
|
|
3053
|
+
{ name: 'claude_code_appliance', size: '17 KB', desc: 'Claude Code appliance' },
|
|
3054
|
+
{ name: 'progressive_index', size: '2.5 MB', desc: 'Large-scale HNSW index' },
|
|
3055
|
+
];
|
|
3056
|
+
let filtered = examples;
|
|
3351
3057
|
if (args.filter) {
|
|
3352
3058
|
const f = args.filter.toLowerCase();
|
|
3353
|
-
|
|
3354
|
-
e.name.includes(f) ||
|
|
3355
|
-
(e.description || '').toLowerCase().includes(f) ||
|
|
3356
|
-
(e.category || '').includes(f)
|
|
3357
|
-
);
|
|
3059
|
+
filtered = examples.filter(e => e.name.includes(f) || e.desc.toLowerCase().includes(f));
|
|
3358
3060
|
}
|
|
3359
|
-
|
|
3360
|
-
if (args.category) {
|
|
3361
|
-
examples = examples.filter(e => e.category === args.category);
|
|
3362
|
-
}
|
|
3363
|
-
|
|
3364
3061
|
return { content: [{ type: 'text', text: JSON.stringify({
|
|
3365
3062
|
success: true,
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
examples: examples.map(e => ({
|
|
3370
|
-
...e,
|
|
3371
|
-
url: `${baseUrl}/${e.name}.rvf`
|
|
3372
|
-
})),
|
|
3373
|
-
categories: manifest.categories || {},
|
|
3063
|
+
total: 45,
|
|
3064
|
+
shown: filtered.length,
|
|
3065
|
+
examples: filtered.map(e => ({ ...e, url: `${BASE_URL}/${e.name}.rvf` })),
|
|
3374
3066
|
catalog: 'https://github.com/ruvnet/ruvector/tree/main/examples/rvf/output'
|
|
3375
3067
|
}, null, 2) }] };
|
|
3376
3068
|
}
|
|
@@ -3466,444 +3158,263 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3466
3158
|
}
|
|
3467
3159
|
}
|
|
3468
3160
|
|
|
3469
|
-
// ── Brain Tool Handlers
|
|
3470
|
-
case 'brain_search':
|
|
3471
|
-
case 'brain_share':
|
|
3472
|
-
case 'brain_get':
|
|
3473
|
-
case 'brain_vote':
|
|
3474
|
-
case 'brain_list':
|
|
3475
|
-
case 'brain_delete':
|
|
3476
|
-
case 'brain_status':
|
|
3477
|
-
case 'brain_drift':
|
|
3478
|
-
case 'brain_partition':
|
|
3479
|
-
case 'brain_transfer':
|
|
3480
|
-
case 'brain_sync':
|
|
3481
|
-
case 'brain_train': {
|
|
3161
|
+
// ── Brain Tool Handlers ─────────────────────────────────────────────
|
|
3162
|
+
case 'brain_search': {
|
|
3482
3163
|
try {
|
|
3483
|
-
const
|
|
3484
|
-
const
|
|
3485
|
-
const
|
|
3486
|
-
|
|
3487
|
-
const
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
case 'search': {
|
|
3491
|
-
const p = new URLSearchParams({ q: args.query || '' });
|
|
3492
|
-
if (args.category) p.set('category', args.category);
|
|
3493
|
-
if (args.limit) p.set('limit', String(args.limit));
|
|
3494
|
-
url = `${brainUrl}/v1/memories/search?${p}`;
|
|
3495
|
-
break;
|
|
3496
|
-
}
|
|
3497
|
-
case 'share': {
|
|
3498
|
-
url = `${brainUrl}/v1/memories`;
|
|
3499
|
-
fetchOpts.method = 'POST';
|
|
3500
|
-
fetchOpts.body = JSON.stringify({ title: args.title, content: args.content, category: args.category, tags: args.tags ? args.tags.split(',').map(t => t.trim()) : [], code_snippet: args.code_snippet });
|
|
3501
|
-
break;
|
|
3502
|
-
}
|
|
3503
|
-
case 'get': url = `${brainUrl}/v1/memories/${args.id}`; break;
|
|
3504
|
-
case 'vote': {
|
|
3505
|
-
url = `${brainUrl}/v1/memories/${args.id}/vote`;
|
|
3506
|
-
fetchOpts.method = 'POST';
|
|
3507
|
-
fetchOpts.body = JSON.stringify({ direction: args.direction });
|
|
3508
|
-
break;
|
|
3509
|
-
}
|
|
3510
|
-
case 'list': {
|
|
3511
|
-
const p = new URLSearchParams();
|
|
3512
|
-
if (args.category) p.set('category', args.category);
|
|
3513
|
-
p.set('limit', String(args.limit || 20));
|
|
3514
|
-
if (args.offset) p.set('offset', String(args.offset));
|
|
3515
|
-
if (args.sort) p.set('sort', args.sort);
|
|
3516
|
-
if (args.tags) p.set('tags', args.tags);
|
|
3517
|
-
url = `${brainUrl}/v1/memories/list?${p}`;
|
|
3518
|
-
break;
|
|
3519
|
-
}
|
|
3520
|
-
case 'delete': {
|
|
3521
|
-
url = `${brainUrl}/v1/memories/${args.id}`;
|
|
3522
|
-
fetchOpts.method = 'DELETE';
|
|
3523
|
-
break;
|
|
3524
|
-
}
|
|
3525
|
-
case 'status': url = `${brainUrl}/v1/status`; break;
|
|
3526
|
-
case 'drift': {
|
|
3527
|
-
const p = new URLSearchParams();
|
|
3528
|
-
if (args.domain) p.set('domain', args.domain);
|
|
3529
|
-
url = `${brainUrl}/v1/drift?${p}`;
|
|
3530
|
-
break;
|
|
3531
|
-
}
|
|
3532
|
-
case 'partition': {
|
|
3533
|
-
const p = new URLSearchParams();
|
|
3534
|
-
if (args.domain) p.set('domain', args.domain);
|
|
3535
|
-
if (args.min_cluster_size) p.set('min_cluster_size', String(args.min_cluster_size));
|
|
3536
|
-
url = `${brainUrl}/v1/partition?${p}`;
|
|
3537
|
-
break;
|
|
3538
|
-
}
|
|
3539
|
-
case 'transfer': {
|
|
3540
|
-
url = `${brainUrl}/v1/transfer`;
|
|
3541
|
-
fetchOpts.method = 'POST';
|
|
3542
|
-
fetchOpts.body = JSON.stringify({ source_domain: args.source_domain, target_domain: args.target_domain });
|
|
3543
|
-
break;
|
|
3544
|
-
}
|
|
3545
|
-
case 'sync': {
|
|
3546
|
-
const p = new URLSearchParams();
|
|
3547
|
-
if (args.direction) p.set('direction', args.direction);
|
|
3548
|
-
url = `${brainUrl}/v1/lora/latest${p.toString() ? '?' + p : ''}`;
|
|
3549
|
-
break;
|
|
3550
|
-
}
|
|
3551
|
-
case 'train': {
|
|
3552
|
-
url = `${brainUrl}/v1/train`;
|
|
3553
|
-
fetchOpts.method = 'POST';
|
|
3554
|
-
fetchOpts.body = JSON.stringify({});
|
|
3555
|
-
break;
|
|
3556
|
-
}
|
|
3557
|
-
}
|
|
3558
|
-
const resp = await proxyFetch(url, fetchOpts);
|
|
3559
|
-
if (!resp.ok) {
|
|
3560
|
-
const errText = await resp.text().catch(() => resp.statusText);
|
|
3561
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
|
|
3562
|
-
}
|
|
3563
|
-
const result = (resp.status === 204 || resp.headers.get('content-length') === '0') ? {} : await resp.json();
|
|
3564
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3164
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3165
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3166
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3167
|
+
const key = process.env.PI || '';
|
|
3168
|
+
const client = new PiBrainClient({ url, key });
|
|
3169
|
+
const results = await client.search(args.query, { limit: args.limit || 10, category: args.category });
|
|
3170
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...results }, null, 2) }] };
|
|
3565
3171
|
} catch (e) {
|
|
3172
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3173
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3174
|
+
}
|
|
3566
3175
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3567
3176
|
}
|
|
3568
3177
|
}
|
|
3569
3178
|
|
|
3570
|
-
|
|
3571
|
-
case 'brain_page_list':
|
|
3572
|
-
case 'brain_page_get':
|
|
3573
|
-
case 'brain_page_create':
|
|
3574
|
-
case 'brain_page_update':
|
|
3575
|
-
case 'brain_page_delete': {
|
|
3179
|
+
case 'brain_share': {
|
|
3576
3180
|
try {
|
|
3577
|
-
const
|
|
3578
|
-
const
|
|
3579
|
-
const
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
const
|
|
3583
|
-
switch (subCmd) {
|
|
3584
|
-
case 'list': {
|
|
3585
|
-
const p = new URLSearchParams();
|
|
3586
|
-
if (args.limit) p.set('limit', String(args.limit));
|
|
3587
|
-
if (args.offset) p.set('offset', String(args.offset));
|
|
3588
|
-
if (args.status) p.set('status', args.status);
|
|
3589
|
-
url = `${brainUrl}/v1/pages${p.toString() ? '?' + p : ''}`;
|
|
3590
|
-
break;
|
|
3591
|
-
}
|
|
3592
|
-
case 'get': url = `${brainUrl}/v1/pages/${args.id}`; break;
|
|
3593
|
-
case 'create': {
|
|
3594
|
-
url = `${brainUrl}/v1/pages`;
|
|
3595
|
-
fetchOpts.method = 'POST';
|
|
3596
|
-
fetchOpts.body = JSON.stringify({ title: args.title, content: args.content, category: args.category, tags: args.tags ? args.tags.split(',').map(t => t.trim()) : [], code_snippet: args.code_snippet, evidence_links: [], embedding: [], witness_hash: '' });
|
|
3597
|
-
break;
|
|
3598
|
-
}
|
|
3599
|
-
case 'update': {
|
|
3600
|
-
url = `${brainUrl}/v1/pages/${args.page_id}/deltas`;
|
|
3601
|
-
fetchOpts.method = 'POST';
|
|
3602
|
-
let evidence = [];
|
|
3603
|
-
try { if (args.evidence_links) evidence = JSON.parse(args.evidence_links); } catch {}
|
|
3604
|
-
fetchOpts.body = JSON.stringify({ delta_type: args.delta_type || 'extension', content_diff: args.content_diff, evidence_links: evidence, witness_hash: '' });
|
|
3605
|
-
break;
|
|
3606
|
-
}
|
|
3607
|
-
case 'delete': {
|
|
3608
|
-
url = `${brainUrl}/v1/pages/${args.id}`;
|
|
3609
|
-
fetchOpts.method = 'DELETE';
|
|
3610
|
-
break;
|
|
3611
|
-
}
|
|
3612
|
-
}
|
|
3613
|
-
const resp = await proxyFetch(url, fetchOpts);
|
|
3614
|
-
if (!resp.ok) {
|
|
3615
|
-
const errText = await resp.text().catch(() => resp.statusText);
|
|
3616
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
|
|
3617
|
-
}
|
|
3618
|
-
const result = (resp.status === 204 || resp.headers.get('content-length') === '0') ? {} : await resp.json();
|
|
3181
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3182
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3183
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3184
|
+
const key = process.env.PI || '';
|
|
3185
|
+
const client = new PiBrainClient({ url, key });
|
|
3186
|
+
const result = await client.share({ title: args.title, content: args.content, category: args.category || 'pattern', tags: args.tags });
|
|
3619
3187
|
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3620
3188
|
} catch (e) {
|
|
3189
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3190
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3191
|
+
}
|
|
3621
3192
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3622
3193
|
}
|
|
3623
3194
|
}
|
|
3624
3195
|
|
|
3625
|
-
|
|
3626
|
-
case 'brain_node_list':
|
|
3627
|
-
case 'brain_node_get':
|
|
3628
|
-
case 'brain_node_publish':
|
|
3629
|
-
case 'brain_node_revoke': {
|
|
3196
|
+
case 'brain_get': {
|
|
3630
3197
|
try {
|
|
3631
|
-
const
|
|
3632
|
-
const
|
|
3633
|
-
const
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
const
|
|
3637
|
-
|
|
3638
|
-
case 'list': {
|
|
3639
|
-
const p = new URLSearchParams();
|
|
3640
|
-
if (args.limit) p.set('limit', String(args.limit));
|
|
3641
|
-
url = `${brainUrl}/v1/nodes${p.toString() ? '?' + p : ''}`;
|
|
3642
|
-
break;
|
|
3643
|
-
}
|
|
3644
|
-
case 'get': url = `${brainUrl}/v1/nodes/${args.id}`; break;
|
|
3645
|
-
case 'publish': {
|
|
3646
|
-
url = `${brainUrl}/v1/nodes`;
|
|
3647
|
-
fetchOpts.method = 'POST';
|
|
3648
|
-
let vectors = [];
|
|
3649
|
-
try { if (args.conformance_vectors) vectors = JSON.parse(args.conformance_vectors); } catch {}
|
|
3650
|
-
fetchOpts.body = JSON.stringify({ name: args.name, wasm_base64: args.wasm_base64, description: args.description || '', conformance_vectors: vectors });
|
|
3651
|
-
break;
|
|
3652
|
-
}
|
|
3653
|
-
case 'revoke': {
|
|
3654
|
-
url = `${brainUrl}/v1/nodes/${args.id}/revoke`;
|
|
3655
|
-
fetchOpts.method = 'POST';
|
|
3656
|
-
fetchOpts.body = JSON.stringify({});
|
|
3657
|
-
break;
|
|
3658
|
-
}
|
|
3659
|
-
}
|
|
3660
|
-
const resp = await proxyFetch(url, fetchOpts);
|
|
3661
|
-
if (!resp.ok) {
|
|
3662
|
-
const errText = await resp.text().catch(() => resp.statusText);
|
|
3663
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
|
|
3664
|
-
}
|
|
3665
|
-
const result = (resp.status === 204 || resp.headers.get('content-length') === '0') ? {} : await resp.json();
|
|
3666
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...(Array.isArray(result) ? { items: result, count: result.length } : result) }, null, 2) }] };
|
|
3198
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3199
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3200
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3201
|
+
const key = process.env.PI || '';
|
|
3202
|
+
const client = new PiBrainClient({ url, key });
|
|
3203
|
+
const result = await client.get(args.id);
|
|
3204
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3667
3205
|
} catch (e) {
|
|
3206
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3207
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3208
|
+
}
|
|
3668
3209
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3669
3210
|
}
|
|
3670
3211
|
}
|
|
3671
3212
|
|
|
3672
|
-
|
|
3673
|
-
case 'brain_agi_status':
|
|
3674
|
-
case 'brain_sona_stats':
|
|
3675
|
-
case 'brain_temporal':
|
|
3676
|
-
case 'brain_explore':
|
|
3677
|
-
case 'brain_midstream':
|
|
3678
|
-
case 'brain_flags': {
|
|
3213
|
+
case 'brain_vote': {
|
|
3679
3214
|
try {
|
|
3680
|
-
const
|
|
3681
|
-
const
|
|
3682
|
-
const
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
const
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
brain_midstream: '/v1/midstream',
|
|
3691
|
-
brain_flags: '/v1/status',
|
|
3692
|
-
};
|
|
3693
|
-
const endpoint = endpointMap[name];
|
|
3694
|
-
const resp = await proxyFetch(`${brainUrl}${endpoint}`, { headers: hdrs, signal: AbortSignal.timeout(30000) });
|
|
3695
|
-
if (!resp.ok) {
|
|
3696
|
-
const errText = await resp.text().catch(() => resp.statusText);
|
|
3697
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
|
|
3698
|
-
}
|
|
3699
|
-
let data = await resp.json();
|
|
3700
|
-
|
|
3701
|
-
// For brain_flags, extract only flag-related fields
|
|
3702
|
-
if (name === 'brain_flags') {
|
|
3703
|
-
const flags = {};
|
|
3704
|
-
for (const [k, v] of Object.entries(data)) {
|
|
3705
|
-
if (typeof v === 'boolean' || k.startsWith('rvf_') || k.endsWith('_enabled') || (k.startsWith('midstream_') && typeof v === 'boolean')) {
|
|
3706
|
-
flags[k] = v;
|
|
3707
|
-
}
|
|
3708
|
-
}
|
|
3709
|
-
data = flags;
|
|
3710
|
-
}
|
|
3711
|
-
|
|
3712
|
-
// For brain_agi_status, extract AGI-specific fields
|
|
3713
|
-
if (name === 'brain_agi_status') {
|
|
3714
|
-
const agiFields = {};
|
|
3715
|
-
const agiKeys = ['sona_patterns', 'sona_trajectories', 'sona_background_ticks', 'gwt_workspace_load', 'gwt_avg_salience', 'knowledge_velocity', 'temporal_deltas', 'temporal_trend', 'meta_avg_regret', 'meta_plateau_status', 'midstream_scheduler_ticks', 'midstream_attractor_categories', 'midstream_strange_loop_version'];
|
|
3716
|
-
for (const k of agiKeys) {
|
|
3717
|
-
if (data[k] !== undefined) agiFields[k] = data[k];
|
|
3718
|
-
}
|
|
3719
|
-
data = Object.keys(agiFields).length > 0 ? agiFields : data;
|
|
3215
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3216
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3217
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3218
|
+
const key = process.env.PI || '';
|
|
3219
|
+
const client = new PiBrainClient({ url, key });
|
|
3220
|
+
const result = await client.vote(args.id, args.direction);
|
|
3221
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3222
|
+
} catch (e) {
|
|
3223
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3224
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3720
3225
|
}
|
|
3226
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3227
|
+
}
|
|
3228
|
+
}
|
|
3721
3229
|
|
|
3722
|
-
|
|
3230
|
+
case 'brain_list': {
|
|
3231
|
+
try {
|
|
3232
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3233
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3234
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3235
|
+
const key = process.env.PI || '';
|
|
3236
|
+
const client = new PiBrainClient({ url, key });
|
|
3237
|
+
const results = await client.list({ category: args.category, limit: args.limit || 20 });
|
|
3238
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...results }, null, 2) }] };
|
|
3723
3239
|
} catch (e) {
|
|
3240
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3241
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3242
|
+
}
|
|
3724
3243
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3725
3244
|
}
|
|
3726
3245
|
}
|
|
3727
3246
|
|
|
3728
|
-
|
|
3729
|
-
case 'midstream_status':
|
|
3730
|
-
case 'midstream_attractor':
|
|
3731
|
-
case 'midstream_scheduler': {
|
|
3247
|
+
case 'brain_delete': {
|
|
3732
3248
|
try {
|
|
3733
|
-
const
|
|
3734
|
-
const
|
|
3735
|
-
const
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
const
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3249
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3250
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3251
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3252
|
+
const key = process.env.PI || '';
|
|
3253
|
+
const client = new PiBrainClient({ url, key });
|
|
3254
|
+
const result = await client.delete(args.id);
|
|
3255
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3256
|
+
} catch (e) {
|
|
3257
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3258
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3742
3259
|
}
|
|
3743
|
-
|
|
3260
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3744
3263
|
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3264
|
+
case 'brain_status': {
|
|
3265
|
+
try {
|
|
3266
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3267
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3268
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3269
|
+
const key = process.env.PI || '';
|
|
3270
|
+
const client = new PiBrainClient({ url, key });
|
|
3271
|
+
const result = await client.status();
|
|
3272
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3273
|
+
} catch (e) {
|
|
3274
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3275
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3750
3276
|
}
|
|
3277
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3751
3280
|
|
|
3752
|
-
|
|
3281
|
+
case 'brain_drift': {
|
|
3282
|
+
try {
|
|
3283
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3284
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3285
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3286
|
+
const key = process.env.PI || '';
|
|
3287
|
+
const client = new PiBrainClient({ url, key });
|
|
3288
|
+
const result = await client.drift({ domain: args.domain });
|
|
3289
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3753
3290
|
} catch (e) {
|
|
3291
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3292
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3293
|
+
}
|
|
3754
3294
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3755
3295
|
}
|
|
3756
3296
|
}
|
|
3757
3297
|
|
|
3758
|
-
case '
|
|
3298
|
+
case 'brain_partition': {
|
|
3759
3299
|
try {
|
|
3760
|
-
const
|
|
3761
|
-
const
|
|
3762
|
-
const
|
|
3763
|
-
|
|
3764
|
-
const
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
return {
|
|
3300
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3301
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3302
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3303
|
+
const key = process.env.PI || '';
|
|
3304
|
+
const client = new PiBrainClient({ url, key });
|
|
3305
|
+
const result = await client.partition({ domain: args.domain, min_cluster_size: args.min_cluster_size || 3 });
|
|
3306
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3307
|
+
} catch (e) {
|
|
3308
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3309
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3770
3310
|
}
|
|
3311
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3771
3314
|
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
const r = await timeFetch(brainUrl + ep.path);
|
|
3785
|
-
times.push(r.elapsed);
|
|
3786
|
-
}
|
|
3787
|
-
sequential[ep.label] = {
|
|
3788
|
-
avg_ms: +(times.reduce((a, b) => a + b, 0) / times.length).toFixed(1),
|
|
3789
|
-
min_ms: +Math.min(...times).toFixed(1),
|
|
3790
|
-
max_ms: +Math.max(...times).toFixed(1)
|
|
3791
|
-
};
|
|
3315
|
+
case 'brain_transfer': {
|
|
3316
|
+
try {
|
|
3317
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3318
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3319
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3320
|
+
const key = process.env.PI || '';
|
|
3321
|
+
const client = new PiBrainClient({ url, key });
|
|
3322
|
+
const result = await client.transfer(args.source, args.target);
|
|
3323
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3324
|
+
} catch (e) {
|
|
3325
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3326
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3792
3327
|
}
|
|
3328
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3793
3331
|
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3332
|
+
case 'brain_sync': {
|
|
3333
|
+
try {
|
|
3334
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3335
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3336
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3337
|
+
const key = process.env.PI || '';
|
|
3338
|
+
const client = new PiBrainClient({ url, key });
|
|
3339
|
+
const result = await client.sync({ direction: args.direction || 'both' });
|
|
3340
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3341
|
+
} catch (e) {
|
|
3342
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3343
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3798
3344
|
}
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3345
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3802
3348
|
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3349
|
+
// ── Edge Tool Handlers ──────────────────────────────────────────────
|
|
3350
|
+
case 'edge_status': {
|
|
3351
|
+
try {
|
|
3352
|
+
const res = await fetch('https://edge-net-genesis-875130704813.us-central1.run.app/api/status');
|
|
3353
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3354
|
+
const data = await res.json();
|
|
3355
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3808
3356
|
} catch (e) {
|
|
3809
3357
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3810
3358
|
}
|
|
3811
3359
|
}
|
|
3812
3360
|
|
|
3813
|
-
case '
|
|
3361
|
+
case 'edge_join': {
|
|
3814
3362
|
try {
|
|
3815
|
-
const
|
|
3816
|
-
const
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
|
|
3825
|
-
}
|
|
3826
|
-
const data = await resp.json();
|
|
3827
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: true, results: data, count: Array.isArray(data) ? data.length : 0 }, null, 2) }] };
|
|
3363
|
+
const key = args.key || process.env.PI || '';
|
|
3364
|
+
const res = await fetch('https://edge-net-genesis-875130704813.us-central1.run.app/api/join', {
|
|
3365
|
+
method: 'POST',
|
|
3366
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3367
|
+
body: JSON.stringify({ contribution: args.contribution || 0.3, key })
|
|
3368
|
+
});
|
|
3369
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3370
|
+
const data = await res.json();
|
|
3371
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3828
3372
|
} catch (e) {
|
|
3829
3373
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3830
3374
|
}
|
|
3831
3375
|
}
|
|
3832
3376
|
|
|
3833
|
-
case '
|
|
3377
|
+
case 'edge_balance': {
|
|
3834
3378
|
try {
|
|
3835
|
-
const
|
|
3836
|
-
const
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
const [healthResp, midResp] = await Promise.all([
|
|
3841
|
-
proxyFetch(`${brainUrl}/v1/health`, { headers: hdrs, signal: AbortSignal.timeout(15000) }).then(r => r.json()).catch(e => ({ error: e.message })),
|
|
3842
|
-
proxyFetch(`${brainUrl}/v1/midstream`, { headers: hdrs, signal: AbortSignal.timeout(15000) }).then(r => r.json()).catch(e => ({ error: e.message })),
|
|
3843
|
-
]);
|
|
3844
|
-
|
|
3845
|
-
return { content: [{ type: 'text', text: JSON.stringify({
|
|
3846
|
-
success: true,
|
|
3847
|
-
health: healthResp,
|
|
3848
|
-
midstream: midResp
|
|
3849
|
-
}, null, 2) }] };
|
|
3379
|
+
const key = args.key || process.env.PI || '';
|
|
3380
|
+
const res = await fetch(`https://edge-net-genesis-875130704813.us-central1.run.app/api/balance?key=${encodeURIComponent(key)}`);
|
|
3381
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3382
|
+
const data = await res.json();
|
|
3383
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3850
3384
|
} catch (e) {
|
|
3851
3385
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3852
3386
|
}
|
|
3853
3387
|
}
|
|
3854
3388
|
|
|
3855
|
-
// ── Edge Tool Handlers ───────────────────────────────────────────────
|
|
3856
|
-
case 'edge_status':
|
|
3857
|
-
case 'edge_join':
|
|
3858
|
-
case 'edge_balance':
|
|
3859
3389
|
case 'edge_tasks': {
|
|
3860
3390
|
try {
|
|
3861
|
-
const
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
switch (subCmd) {
|
|
3865
|
-
case 'status': endpoint = '/status'; break;
|
|
3866
|
-
case 'join': endpoint = '/join'; method = 'POST'; body = JSON.stringify({ contribution: args.contribution || 0.3, pi_key: process.env.PI }); break;
|
|
3867
|
-
case 'balance': { const ps = process.env.PI ? require('crypto').createHash('shake256', { outputLength: 16 }).update(process.env.PI).digest('hex') : 'anonymous'; endpoint = `/balance/${ps}`; break; }
|
|
3868
|
-
case 'tasks': endpoint = `/tasks?limit=${args.limit || 20}`; break;
|
|
3869
|
-
}
|
|
3870
|
-
const resp = await proxyFetch(`${genesisUrl}${endpoint}`, {
|
|
3871
|
-
method,
|
|
3872
|
-
headers: { 'Content-Type': 'application/json', ...(process.env.PI ? { 'Authorization': `Bearer ${process.env.PI}` } : {}) },
|
|
3873
|
-
...(body ? { body } : {})
|
|
3874
|
-
});
|
|
3875
|
-
if (!resp.ok) {
|
|
3876
|
-
const errText = await resp.text().catch(() => resp.statusText);
|
|
3877
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: `${resp.status} ${errText}` }, null, 2) }], isError: true };
|
|
3878
|
-
}
|
|
3879
|
-
const data = await resp.json();
|
|
3391
|
+
const res = await fetch('https://edge-net-genesis-875130704813.us-central1.run.app/api/tasks');
|
|
3392
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3393
|
+
const data = await res.json();
|
|
3880
3394
|
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3881
3395
|
} catch (e) {
|
|
3882
3396
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3883
3397
|
}
|
|
3884
3398
|
}
|
|
3885
3399
|
|
|
3886
|
-
// ── Identity Tool Handlers
|
|
3400
|
+
// ── Identity Tool Handlers ──────────────────────────────────────────
|
|
3887
3401
|
case 'identity_generate': {
|
|
3888
3402
|
const crypto = require('crypto');
|
|
3889
3403
|
const key = crypto.randomBytes(32).toString('hex');
|
|
3890
|
-
const
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: true, pi_key: key, pseudonym, warning: 'Store this key securely. Set PI env var to use it.' }, null, 2) }] };
|
|
3404
|
+
const pseudonym = crypto.createHash('shake256', { outputLength: 16 }).update(key).digest('hex');
|
|
3405
|
+
const mcpToken = crypto.createHmac('sha256', key).update('mcp').digest('hex').slice(0, 32);
|
|
3406
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, key, pseudonym, mcp_token: mcpToken, instructions: 'Set PI env var: export PI=' + key }, null, 2) }] };
|
|
3894
3407
|
}
|
|
3895
3408
|
|
|
3896
3409
|
case 'identity_show': {
|
|
3897
|
-
const piKey = process.env.PI;
|
|
3898
|
-
if (!piKey) {
|
|
3899
|
-
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'No PI environment variable set. Run identity_generate first.' }, null, 2) }], isError: true };
|
|
3900
|
-
}
|
|
3901
3410
|
const crypto = require('crypto');
|
|
3902
|
-
const
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3411
|
+
const key = args.key || process.env.PI || '';
|
|
3412
|
+
if (!key) {
|
|
3413
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'No PI key found. Set PI env var or pass key argument' }, null, 2) }] };
|
|
3414
|
+
}
|
|
3415
|
+
const pseudonym = crypto.createHash('shake256', { outputLength: 16 }).update(key).digest('hex');
|
|
3416
|
+
const mcpToken = crypto.createHmac('sha256', key).update('mcp').digest('hex').slice(0, 32);
|
|
3417
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, pseudonym, mcp_token: mcpToken, key_prefix: key.slice(0, 8) + '...' }, null, 2) }] };
|
|
3907
3418
|
}
|
|
3908
3419
|
|
|
3909
3420
|
default:
|
|
@@ -3994,173 +3505,9 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
3994
3505
|
|
|
3995
3506
|
// Start server
|
|
3996
3507
|
async function main() {
|
|
3997
|
-
const
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
const http = require('http');
|
|
4001
|
-
const crypto = require('crypto');
|
|
4002
|
-
const port = parseInt(process.env.MCP_PORT || '8080', 10);
|
|
4003
|
-
const host = process.env.MCP_HOST || '0.0.0.0';
|
|
4004
|
-
|
|
4005
|
-
// SSE MCP Transport Implementation
|
|
4006
|
-
// MCP over SSE uses:
|
|
4007
|
-
// GET /sse - SSE stream for server->client messages
|
|
4008
|
-
// POST /message - client->server JSON-RPC messages
|
|
4009
|
-
|
|
4010
|
-
const sessions = new Map();
|
|
4011
|
-
|
|
4012
|
-
const httpServer = http.createServer(async (req, res) => {
|
|
4013
|
-
// CORS headers
|
|
4014
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
4015
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
4016
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
4017
|
-
|
|
4018
|
-
if (req.method === 'OPTIONS') {
|
|
4019
|
-
res.writeHead(204);
|
|
4020
|
-
res.end();
|
|
4021
|
-
return;
|
|
4022
|
-
}
|
|
4023
|
-
|
|
4024
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
4025
|
-
|
|
4026
|
-
if (req.method === 'GET' && url.pathname === '/sse') {
|
|
4027
|
-
// SSE endpoint - establish persistent connection
|
|
4028
|
-
const sessionId = crypto.randomUUID();
|
|
4029
|
-
|
|
4030
|
-
res.writeHead(200, {
|
|
4031
|
-
'Content-Type': 'text/event-stream',
|
|
4032
|
-
'Cache-Control': 'no-cache',
|
|
4033
|
-
'Connection': 'keep-alive',
|
|
4034
|
-
});
|
|
4035
|
-
|
|
4036
|
-
// Send endpoint event so client knows where to POST
|
|
4037
|
-
const displayHost = host === '0.0.0.0' ? 'localhost' : host;
|
|
4038
|
-
const messageUrl = `http://${displayHost}:${port}/message?sessionId=${sessionId}`;
|
|
4039
|
-
res.write(`event: endpoint\ndata: ${messageUrl}\n\n`);
|
|
4040
|
-
|
|
4041
|
-
// Store session
|
|
4042
|
-
sessions.set(sessionId, {
|
|
4043
|
-
res,
|
|
4044
|
-
messageQueue: [],
|
|
4045
|
-
});
|
|
4046
|
-
|
|
4047
|
-
// Create a custom transport for this session
|
|
4048
|
-
const sessionTransport = {
|
|
4049
|
-
_onMessage: null,
|
|
4050
|
-
_onClose: null,
|
|
4051
|
-
_onError: null,
|
|
4052
|
-
_started: false,
|
|
4053
|
-
|
|
4054
|
-
async start() {
|
|
4055
|
-
this._started = true;
|
|
4056
|
-
},
|
|
4057
|
-
|
|
4058
|
-
async close() {
|
|
4059
|
-
sessions.delete(sessionId);
|
|
4060
|
-
if (!res.writableEnded) {
|
|
4061
|
-
res.end();
|
|
4062
|
-
}
|
|
4063
|
-
},
|
|
4064
|
-
|
|
4065
|
-
async send(message) {
|
|
4066
|
-
if (!res.writableEnded) {
|
|
4067
|
-
res.write(`event: message\ndata: ${JSON.stringify(message)}\n\n`);
|
|
4068
|
-
}
|
|
4069
|
-
},
|
|
4070
|
-
|
|
4071
|
-
set onmessage(handler) { this._onMessage = handler; },
|
|
4072
|
-
get onmessage() { return this._onMessage; },
|
|
4073
|
-
set onclose(handler) { this._onClose = handler; },
|
|
4074
|
-
get onclose() { return this._onClose; },
|
|
4075
|
-
set onerror(handler) { this._onError = handler; },
|
|
4076
|
-
get onerror() { return this._onError; },
|
|
4077
|
-
};
|
|
4078
|
-
|
|
4079
|
-
sessions.get(sessionId).transport = sessionTransport;
|
|
4080
|
-
|
|
4081
|
-
// Connect server to this transport
|
|
4082
|
-
await server.connect(sessionTransport);
|
|
4083
|
-
|
|
4084
|
-
// Process any queued messages
|
|
4085
|
-
const session = sessions.get(sessionId);
|
|
4086
|
-
if (session) {
|
|
4087
|
-
for (const msg of session.messageQueue) {
|
|
4088
|
-
if (sessionTransport._onMessage) {
|
|
4089
|
-
sessionTransport._onMessage(msg);
|
|
4090
|
-
}
|
|
4091
|
-
}
|
|
4092
|
-
session.messageQueue = [];
|
|
4093
|
-
}
|
|
4094
|
-
|
|
4095
|
-
// Handle disconnect
|
|
4096
|
-
req.on('close', () => {
|
|
4097
|
-
sessions.delete(sessionId);
|
|
4098
|
-
if (sessionTransport._onClose) {
|
|
4099
|
-
sessionTransport._onClose();
|
|
4100
|
-
}
|
|
4101
|
-
});
|
|
4102
|
-
|
|
4103
|
-
} else if (req.method === 'POST' && url.pathname === '/message') {
|
|
4104
|
-
// Message endpoint - receive client JSON-RPC messages
|
|
4105
|
-
const sessionId = url.searchParams.get('sessionId');
|
|
4106
|
-
const session = sessions.get(sessionId);
|
|
4107
|
-
|
|
4108
|
-
if (!session) {
|
|
4109
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4110
|
-
res.end(JSON.stringify({ error: 'Session not found' }));
|
|
4111
|
-
return;
|
|
4112
|
-
}
|
|
4113
|
-
|
|
4114
|
-
let body = '';
|
|
4115
|
-
req.on('data', chunk => { body += chunk; });
|
|
4116
|
-
req.on('end', () => {
|
|
4117
|
-
try {
|
|
4118
|
-
const message = JSON.parse(body);
|
|
4119
|
-
|
|
4120
|
-
if (session.transport && session.transport._onMessage) {
|
|
4121
|
-
session.transport._onMessage(message);
|
|
4122
|
-
} else {
|
|
4123
|
-
session.messageQueue.push(message);
|
|
4124
|
-
}
|
|
4125
|
-
|
|
4126
|
-
res.writeHead(202, { 'Content-Type': 'application/json' });
|
|
4127
|
-
res.end(JSON.stringify({ status: 'accepted' }));
|
|
4128
|
-
} catch (e) {
|
|
4129
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
4130
|
-
res.end(JSON.stringify({ error: 'Invalid JSON' }));
|
|
4131
|
-
}
|
|
4132
|
-
});
|
|
4133
|
-
|
|
4134
|
-
} else if (req.method === 'GET' && url.pathname === '/health') {
|
|
4135
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4136
|
-
res.end(JSON.stringify({
|
|
4137
|
-
status: 'ok',
|
|
4138
|
-
transport: 'sse',
|
|
4139
|
-
sessions: sessions.size,
|
|
4140
|
-
tools: 91,
|
|
4141
|
-
version: '0.2.13'
|
|
4142
|
-
}));
|
|
4143
|
-
|
|
4144
|
-
} else {
|
|
4145
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
4146
|
-
res.end(JSON.stringify({ error: 'Not found. Use GET /sse for SSE stream, POST /message for JSON-RPC, GET /health for status.' }));
|
|
4147
|
-
}
|
|
4148
|
-
});
|
|
4149
|
-
|
|
4150
|
-
httpServer.listen(port, host, () => {
|
|
4151
|
-
const displayHost = host === '0.0.0.0' ? 'localhost' : host;
|
|
4152
|
-
console.error(`RuVector MCP server running on SSE at http://${host}:${port}`);
|
|
4153
|
-
console.error(` SSE endpoint: http://${displayHost}:${port}/sse`);
|
|
4154
|
-
console.error(` Message endpoint: http://${displayHost}:${port}/message`);
|
|
4155
|
-
console.error(` Health check: http://${displayHost}:${port}/health`);
|
|
4156
|
-
});
|
|
4157
|
-
|
|
4158
|
-
} else {
|
|
4159
|
-
// Default: stdio transport
|
|
4160
|
-
const transport = new StdioServerTransport();
|
|
4161
|
-
await server.connect(transport);
|
|
4162
|
-
console.error('RuVector MCP server running on stdio');
|
|
4163
|
-
}
|
|
3508
|
+
const transport = new StdioServerTransport();
|
|
3509
|
+
await server.connect(transport);
|
|
3510
|
+
console.error('RuVector MCP server running on stdio');
|
|
4164
3511
|
}
|
|
4165
3512
|
|
|
4166
3513
|
main().catch(console.error);
|