ruvector 0.2.18 → 0.2.20
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 +1569 -1553
- package/bin/mcp-server.js +508 -892
- package/package.json +23 -13
- package/src/decompiler/index.js +407 -0
- package/src/decompiler/metrics.js +86 -0
- package/src/decompiler/module-splitter.js +498 -0
- package/src/decompiler/module-tree.js +142 -0
- package/src/decompiler/name-predictor.js +400 -0
- package/src/decompiler/npm-fetch.js +176 -0
- package/src/decompiler/reconstructor.js +499 -0
- package/src/decompiler/reference-tracker.js +285 -0
- package/src/decompiler/statement-parser.js +285 -0
- package/src/decompiler/style-improver.js +438 -0
- package/src/decompiler/subcategories.js +339 -0
- package/src/decompiler/validator.js +379 -0
- package/src/decompiler/witness.js +140 -0
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,200 @@ 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: '
|
|
1394
|
+
description: 'Sync LoRA weights',
|
|
1460
1395
|
inputSchema: {
|
|
1461
1396
|
type: 'object',
|
|
1462
1397
|
properties: {
|
|
1463
|
-
direction: { type: 'string',
|
|
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)' }
|
|
1398
|
+
direction: { type: 'string', enum: ['pull', 'push', 'both'], description: 'Sync direction', default: 'both' }
|
|
1523
1399
|
},
|
|
1524
|
-
required: [
|
|
1400
|
+
required: []
|
|
1525
1401
|
}
|
|
1526
1402
|
},
|
|
1403
|
+
|
|
1404
|
+
// ── Edge Tools (Distributed Compute) ──────────────────────────────────
|
|
1527
1405
|
{
|
|
1528
|
-
name: '
|
|
1529
|
-
description: '
|
|
1406
|
+
name: 'edge_status',
|
|
1407
|
+
description: 'Query edge network status',
|
|
1530
1408
|
inputSchema: {
|
|
1531
1409
|
type: 'object',
|
|
1532
|
-
properties: {
|
|
1533
|
-
|
|
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']
|
|
1410
|
+
properties: {},
|
|
1411
|
+
required: []
|
|
1540
1412
|
}
|
|
1541
1413
|
},
|
|
1542
1414
|
{
|
|
1543
|
-
name: '
|
|
1544
|
-
description: '
|
|
1415
|
+
name: 'edge_join',
|
|
1416
|
+
description: 'Join as compute node',
|
|
1545
1417
|
inputSchema: {
|
|
1546
1418
|
type: 'object',
|
|
1547
1419
|
properties: {
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
content_diff: { type: 'string', description: 'Content diff or new content' },
|
|
1551
|
-
evidence_links: { type: 'string', description: 'JSON array of evidence links' }
|
|
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)' }
|
|
1552
1422
|
},
|
|
1553
|
-
required: [
|
|
1423
|
+
required: []
|
|
1554
1424
|
}
|
|
1555
1425
|
},
|
|
1556
1426
|
{
|
|
1557
|
-
name: '
|
|
1558
|
-
description: '
|
|
1427
|
+
name: 'edge_balance',
|
|
1428
|
+
description: 'Check rUv balance',
|
|
1559
1429
|
inputSchema: {
|
|
1560
1430
|
type: 'object',
|
|
1561
1431
|
properties: {
|
|
1562
|
-
|
|
1432
|
+
key: { type: 'string', description: 'PI key (optional, defaults to PI env var)' }
|
|
1563
1433
|
},
|
|
1564
|
-
required: [
|
|
1434
|
+
required: []
|
|
1565
1435
|
}
|
|
1566
1436
|
},
|
|
1567
|
-
// ── WASM Node Tools (4) ── Executable compute node management ──
|
|
1568
1437
|
{
|
|
1569
|
-
name: '
|
|
1570
|
-
description: 'List
|
|
1438
|
+
name: 'edge_tasks',
|
|
1439
|
+
description: 'List available distributed compute tasks',
|
|
1571
1440
|
inputSchema: {
|
|
1572
1441
|
type: 'object',
|
|
1573
|
-
properties: {
|
|
1574
|
-
|
|
1575
|
-
}
|
|
1442
|
+
properties: {},
|
|
1443
|
+
required: []
|
|
1576
1444
|
}
|
|
1577
1445
|
},
|
|
1446
|
+
|
|
1447
|
+
// ── Identity Tools (PI Key Management) ────────────────────────────────
|
|
1578
1448
|
{
|
|
1579
|
-
name: '
|
|
1580
|
-
description: '
|
|
1449
|
+
name: 'identity_generate',
|
|
1450
|
+
description: 'Generate a new PI key with SHAKE-256 pseudonym',
|
|
1581
1451
|
inputSchema: {
|
|
1582
1452
|
type: 'object',
|
|
1583
|
-
properties: {
|
|
1584
|
-
|
|
1585
|
-
},
|
|
1586
|
-
required: ['id']
|
|
1453
|
+
properties: {},
|
|
1454
|
+
required: []
|
|
1587
1455
|
}
|
|
1588
1456
|
},
|
|
1589
1457
|
{
|
|
1590
|
-
name: '
|
|
1591
|
-
description: '
|
|
1458
|
+
name: 'identity_show',
|
|
1459
|
+
description: 'Show current identity derived from PI key',
|
|
1592
1460
|
inputSchema: {
|
|
1593
1461
|
type: 'object',
|
|
1594
1462
|
properties: {
|
|
1595
|
-
|
|
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' }
|
|
1463
|
+
key: { type: 'string', description: 'PI key (optional, defaults to PI env var)' }
|
|
1599
1464
|
},
|
|
1600
|
-
required: [
|
|
1465
|
+
required: []
|
|
1601
1466
|
}
|
|
1602
1467
|
},
|
|
1468
|
+
|
|
1469
|
+
// ── Decompiler Tools ───────────────────────────────────────────────────
|
|
1603
1470
|
{
|
|
1604
|
-
name: '
|
|
1605
|
-
description: '
|
|
1471
|
+
name: 'decompile_package',
|
|
1472
|
+
description: 'Decompile an npm package. Fetches from registry, extracts bundle, splits into modules, computes metrics and witness chain.',
|
|
1606
1473
|
inputSchema: {
|
|
1607
1474
|
type: 'object',
|
|
1608
1475
|
properties: {
|
|
1609
|
-
|
|
1476
|
+
package: { type: 'string', description: 'npm package name (e.g. "express", "@anthropic-ai/claude-code")' },
|
|
1477
|
+
version: { type: 'string', description: 'Version (default: latest)' },
|
|
1478
|
+
min_confidence: { type: 'number', description: 'Minimum confidence threshold (0-1, default: 0.3)' }
|
|
1610
1479
|
},
|
|
1611
|
-
required: ['
|
|
1480
|
+
required: ['package']
|
|
1612
1481
|
}
|
|
1613
1482
|
},
|
|
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
1483
|
{
|
|
1621
|
-
name: '
|
|
1622
|
-
description: '
|
|
1484
|
+
name: 'decompile_file',
|
|
1485
|
+
description: 'Decompile a local JavaScript file. Beautifies, splits into modules, computes metrics.',
|
|
1623
1486
|
inputSchema: {
|
|
1624
1487
|
type: 'object',
|
|
1625
1488
|
properties: {
|
|
1626
|
-
|
|
1627
|
-
|
|
1489
|
+
path: { type: 'string', description: 'Path to .js file' },
|
|
1490
|
+
min_confidence: { type: 'number', description: 'Minimum confidence threshold (0-1, default: 0.3)' }
|
|
1491
|
+
},
|
|
1492
|
+
required: ['path']
|
|
1628
1493
|
}
|
|
1629
1494
|
},
|
|
1630
1495
|
{
|
|
1631
|
-
name: '
|
|
1632
|
-
description: '
|
|
1633
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1634
|
-
},
|
|
1635
|
-
{
|
|
1636
|
-
name: 'midstream_benchmark',
|
|
1637
|
-
description: 'Run sequential + concurrent latency benchmark against brain backend',
|
|
1496
|
+
name: 'decompile_url',
|
|
1497
|
+
description: 'Decompile JavaScript from a URL (unpkg, CDN, raw GitHub, etc).',
|
|
1638
1498
|
inputSchema: {
|
|
1639
1499
|
type: 'object',
|
|
1640
1500
|
properties: {
|
|
1641
|
-
|
|
1642
|
-
|
|
1501
|
+
url: { type: 'string', description: 'URL to fetch JavaScript from' },
|
|
1502
|
+
min_confidence: { type: 'number', description: 'Minimum confidence threshold (0-1, default: 0.3)' }
|
|
1503
|
+
},
|
|
1504
|
+
required: ['url']
|
|
1643
1505
|
}
|
|
1644
1506
|
},
|
|
1645
1507
|
{
|
|
1646
|
-
name: '
|
|
1647
|
-
description: '
|
|
1508
|
+
name: 'decompile_search',
|
|
1509
|
+
description: 'Search decompiled code for patterns, function names, or string literals.',
|
|
1648
1510
|
inputSchema: {
|
|
1649
1511
|
type: 'object',
|
|
1650
1512
|
properties: {
|
|
1651
|
-
query: { type: 'string', description: 'Search query' },
|
|
1652
|
-
|
|
1513
|
+
query: { type: 'string', description: 'Search query (regex supported)' },
|
|
1514
|
+
package: { type: 'string', description: 'npm package to decompile and search' },
|
|
1515
|
+
version: { type: 'string', description: 'Package version (default: latest)' },
|
|
1516
|
+
path: { type: 'string', description: 'Local file path to decompile and search (alternative to package)' }
|
|
1653
1517
|
},
|
|
1654
1518
|
required: ['query']
|
|
1655
1519
|
}
|
|
1656
1520
|
},
|
|
1657
1521
|
{
|
|
1658
|
-
name: '
|
|
1659
|
-
description: '
|
|
1660
|
-
inputSchema: { type: 'object', properties: {} }
|
|
1661
|
-
},
|
|
1662
|
-
// ── Edge Tools (4) ── Distributed compute via @ruvector/edge-net ──
|
|
1663
|
-
{
|
|
1664
|
-
name: 'edge_status',
|
|
1665
|
-
description: 'Get edge compute network status (genesis, relay, nodes, rUv supply)',
|
|
1666
|
-
inputSchema: {
|
|
1667
|
-
type: 'object',
|
|
1668
|
-
properties: {}
|
|
1669
|
-
}
|
|
1670
|
-
},
|
|
1671
|
-
{
|
|
1672
|
-
name: 'edge_join',
|
|
1673
|
-
description: 'Join the edge compute network as a compute node',
|
|
1522
|
+
name: 'decompile_diff',
|
|
1523
|
+
description: 'Compare decompiled output between two versions of an npm package. Shows added/removed/changed modules.',
|
|
1674
1524
|
inputSchema: {
|
|
1675
1525
|
type: 'object',
|
|
1676
1526
|
properties: {
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
name: 'edge_balance',
|
|
1683
|
-
description: 'Check rUv credit balance for current identity',
|
|
1684
|
-
inputSchema: {
|
|
1685
|
-
type: 'object',
|
|
1686
|
-
properties: {}
|
|
1527
|
+
package: { type: 'string', description: 'npm package name' },
|
|
1528
|
+
version_a: { type: 'string', description: 'First version' },
|
|
1529
|
+
version_b: { type: 'string', description: 'Second version' }
|
|
1530
|
+
},
|
|
1531
|
+
required: ['package', 'version_a', 'version_b']
|
|
1687
1532
|
}
|
|
1688
1533
|
},
|
|
1689
1534
|
{
|
|
1690
|
-
name: '
|
|
1691
|
-
description: '
|
|
1535
|
+
name: 'decompile_witness',
|
|
1536
|
+
description: 'Verify the cryptographic witness chain of a decompilation. Proves output derives faithfully from input.',
|
|
1692
1537
|
inputSchema: {
|
|
1693
1538
|
type: 'object',
|
|
1694
1539
|
properties: {
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
// ── Identity Tools (2) ── Pi key management ──
|
|
1700
|
-
{
|
|
1701
|
-
name: 'identity_generate',
|
|
1702
|
-
description: 'Generate a new pi key and derive pseudonym',
|
|
1703
|
-
inputSchema: {
|
|
1704
|
-
type: 'object',
|
|
1705
|
-
properties: {}
|
|
1706
|
-
}
|
|
1707
|
-
},
|
|
1708
|
-
{
|
|
1709
|
-
name: 'identity_show',
|
|
1710
|
-
description: 'Show current pi key pseudonym and derived identities',
|
|
1711
|
-
inputSchema: {
|
|
1712
|
-
type: 'object',
|
|
1713
|
-
properties: {}
|
|
1540
|
+
witness_path: { type: 'string', description: 'Path to witness.json file' },
|
|
1541
|
+
source_path: { type: 'string', description: 'Path to original bundle (optional, for source hash verification)' }
|
|
1542
|
+
},
|
|
1543
|
+
required: ['witness_path']
|
|
1714
1544
|
}
|
|
1715
1545
|
}
|
|
1716
1546
|
];
|
|
@@ -3054,15 +2884,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3054
2884
|
}
|
|
3055
2885
|
|
|
3056
2886
|
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
|
-
}
|
|
2887
|
+
const name = args.name;
|
|
2888
|
+
const preset = args.preset || 'quick-scan';
|
|
2889
|
+
const triggers = args.triggers;
|
|
3066
2890
|
try {
|
|
3067
2891
|
let cmd = `npx agentic-flow@alpha workers create "${name}" --preset ${preset}`;
|
|
3068
2892
|
if (triggers) cmd += ` --triggers "${triggers}"`;
|
|
@@ -3292,85 +3116,31 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3292
3116
|
}
|
|
3293
3117
|
|
|
3294
3118
|
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
|
-
|
|
3119
|
+
const BASE_URL = 'https://raw.githubusercontent.com/ruvnet/ruvector/main/examples/rvf/output';
|
|
3120
|
+
const examples = [
|
|
3121
|
+
{ name: 'basic_store', size: '152 KB', desc: '1,000 vectors, dim 128' },
|
|
3122
|
+
{ name: 'semantic_search', size: '755 KB', desc: 'Semantic search with HNSW' },
|
|
3123
|
+
{ name: 'rag_pipeline', size: '303 KB', desc: 'RAG pipeline embeddings' },
|
|
3124
|
+
{ name: 'agent_memory', size: '32 KB', desc: 'AI agent episodic memory' },
|
|
3125
|
+
{ name: 'swarm_knowledge', size: '86 KB', desc: 'Multi-agent knowledge base' },
|
|
3126
|
+
{ name: 'self_booting', size: '31 KB', desc: 'Self-booting with kernel' },
|
|
3127
|
+
{ name: 'ebpf_accelerator', size: '153 KB', desc: 'eBPF distance accelerator' },
|
|
3128
|
+
{ name: 'tee_attestation', size: '102 KB', desc: 'TEE attestation + witnesses' },
|
|
3129
|
+
{ name: 'lineage_parent', size: '52 KB', desc: 'COW parent file' },
|
|
3130
|
+
{ name: 'lineage_child', size: '26 KB', desc: 'COW child (derived)' },
|
|
3131
|
+
{ name: 'claude_code_appliance', size: '17 KB', desc: 'Claude Code appliance' },
|
|
3132
|
+
{ name: 'progressive_index', size: '2.5 MB', desc: 'Large-scale HNSW index' },
|
|
3133
|
+
];
|
|
3134
|
+
let filtered = examples;
|
|
3351
3135
|
if (args.filter) {
|
|
3352
3136
|
const f = args.filter.toLowerCase();
|
|
3353
|
-
|
|
3354
|
-
e.name.includes(f) ||
|
|
3355
|
-
(e.description || '').toLowerCase().includes(f) ||
|
|
3356
|
-
(e.category || '').includes(f)
|
|
3357
|
-
);
|
|
3137
|
+
filtered = examples.filter(e => e.name.includes(f) || e.desc.toLowerCase().includes(f));
|
|
3358
3138
|
}
|
|
3359
|
-
|
|
3360
|
-
if (args.category) {
|
|
3361
|
-
examples = examples.filter(e => e.category === args.category);
|
|
3362
|
-
}
|
|
3363
|
-
|
|
3364
3139
|
return { content: [{ type: 'text', text: JSON.stringify({
|
|
3365
3140
|
success: true,
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
examples: examples.map(e => ({
|
|
3370
|
-
...e,
|
|
3371
|
-
url: `${baseUrl}/${e.name}.rvf`
|
|
3372
|
-
})),
|
|
3373
|
-
categories: manifest.categories || {},
|
|
3141
|
+
total: 45,
|
|
3142
|
+
shown: filtered.length,
|
|
3143
|
+
examples: filtered.map(e => ({ ...e, url: `${BASE_URL}/${e.name}.rvf` })),
|
|
3374
3144
|
catalog: 'https://github.com/ruvnet/ruvector/tree/main/examples/rvf/output'
|
|
3375
3145
|
}, null, 2) }] };
|
|
3376
3146
|
}
|
|
@@ -3466,444 +3236,454 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
3466
3236
|
}
|
|
3467
3237
|
}
|
|
3468
3238
|
|
|
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': {
|
|
3239
|
+
// ── Brain Tool Handlers ─────────────────────────────────────────────
|
|
3240
|
+
case 'brain_search': {
|
|
3482
3241
|
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) }] };
|
|
3242
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3243
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3244
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3245
|
+
const key = process.env.PI || '';
|
|
3246
|
+
const client = new PiBrainClient({ url, key });
|
|
3247
|
+
const results = await client.search(args.query, { limit: args.limit || 10, category: args.category });
|
|
3248
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...results }, null, 2) }] };
|
|
3565
3249
|
} catch (e) {
|
|
3250
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3251
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3252
|
+
}
|
|
3566
3253
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3567
3254
|
}
|
|
3568
3255
|
}
|
|
3569
3256
|
|
|
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': {
|
|
3257
|
+
case 'brain_share': {
|
|
3576
3258
|
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();
|
|
3259
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3260
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3261
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3262
|
+
const key = process.env.PI || '';
|
|
3263
|
+
const client = new PiBrainClient({ url, key });
|
|
3264
|
+
const result = await client.share({ title: args.title, content: args.content, category: args.category || 'pattern', tags: args.tags });
|
|
3619
3265
|
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3620
3266
|
} catch (e) {
|
|
3267
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3268
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3269
|
+
}
|
|
3621
3270
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3622
3271
|
}
|
|
3623
3272
|
}
|
|
3624
3273
|
|
|
3625
|
-
|
|
3626
|
-
case 'brain_node_list':
|
|
3627
|
-
case 'brain_node_get':
|
|
3628
|
-
case 'brain_node_publish':
|
|
3629
|
-
case 'brain_node_revoke': {
|
|
3274
|
+
case 'brain_get': {
|
|
3630
3275
|
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) }] };
|
|
3276
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3277
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3278
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3279
|
+
const key = process.env.PI || '';
|
|
3280
|
+
const client = new PiBrainClient({ url, key });
|
|
3281
|
+
const result = await client.get(args.id);
|
|
3282
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3667
3283
|
} catch (e) {
|
|
3284
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3285
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3286
|
+
}
|
|
3668
3287
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3669
3288
|
}
|
|
3670
3289
|
}
|
|
3671
3290
|
|
|
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': {
|
|
3291
|
+
case 'brain_vote': {
|
|
3679
3292
|
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;
|
|
3293
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3294
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3295
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3296
|
+
const key = process.env.PI || '';
|
|
3297
|
+
const client = new PiBrainClient({ url, key });
|
|
3298
|
+
const result = await client.vote(args.id, args.direction);
|
|
3299
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3300
|
+
} catch (e) {
|
|
3301
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3302
|
+
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
3303
|
}
|
|
3304
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3721
3307
|
|
|
3722
|
-
|
|
3308
|
+
case 'brain_list': {
|
|
3309
|
+
try {
|
|
3310
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3311
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3312
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3313
|
+
const key = process.env.PI || '';
|
|
3314
|
+
const client = new PiBrainClient({ url, key });
|
|
3315
|
+
const results = await client.list({ category: args.category, limit: args.limit || 20 });
|
|
3316
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...results }, null, 2) }] };
|
|
3723
3317
|
} catch (e) {
|
|
3318
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3319
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3320
|
+
}
|
|
3724
3321
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3725
3322
|
}
|
|
3726
3323
|
}
|
|
3727
3324
|
|
|
3728
|
-
|
|
3729
|
-
case 'midstream_status':
|
|
3730
|
-
case 'midstream_attractor':
|
|
3731
|
-
case 'midstream_scheduler': {
|
|
3325
|
+
case 'brain_delete': {
|
|
3732
3326
|
try {
|
|
3733
|
-
const
|
|
3734
|
-
const
|
|
3735
|
-
const
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
const
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3327
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3328
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3329
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3330
|
+
const key = process.env.PI || '';
|
|
3331
|
+
const client = new PiBrainClient({ url, key });
|
|
3332
|
+
const result = await client.delete(args.id);
|
|
3333
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3334
|
+
} catch (e) {
|
|
3335
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3336
|
+
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
3337
|
}
|
|
3743
|
-
|
|
3338
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3744
3341
|
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3342
|
+
case 'brain_status': {
|
|
3343
|
+
try {
|
|
3344
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3345
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3346
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3347
|
+
const key = process.env.PI || '';
|
|
3348
|
+
const client = new PiBrainClient({ url, key });
|
|
3349
|
+
const result = await client.status();
|
|
3350
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3351
|
+
} catch (e) {
|
|
3352
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3353
|
+
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
3354
|
}
|
|
3355
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3751
3358
|
|
|
3752
|
-
|
|
3359
|
+
case 'brain_drift': {
|
|
3360
|
+
try {
|
|
3361
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3362
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3363
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3364
|
+
const key = process.env.PI || '';
|
|
3365
|
+
const client = new PiBrainClient({ url, key });
|
|
3366
|
+
const result = await client.drift({ domain: args.domain });
|
|
3367
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3753
3368
|
} catch (e) {
|
|
3369
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3370
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'Brain tools require @ruvector/pi-brain', hint: 'npm install @ruvector/pi-brain' }, null, 2) }] };
|
|
3371
|
+
}
|
|
3754
3372
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3755
3373
|
}
|
|
3756
3374
|
}
|
|
3757
3375
|
|
|
3758
|
-
case '
|
|
3376
|
+
case 'brain_partition': {
|
|
3759
3377
|
try {
|
|
3760
|
-
const
|
|
3761
|
-
const
|
|
3762
|
-
const
|
|
3763
|
-
|
|
3764
|
-
const
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
return {
|
|
3378
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3379
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3380
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3381
|
+
const key = process.env.PI || '';
|
|
3382
|
+
const client = new PiBrainClient({ url, key });
|
|
3383
|
+
const result = await client.partition({ domain: args.domain, min_cluster_size: args.min_cluster_size || 3 });
|
|
3384
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3385
|
+
} catch (e) {
|
|
3386
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3387
|
+
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
3388
|
}
|
|
3389
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3771
3392
|
|
|
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
|
-
};
|
|
3393
|
+
case 'brain_transfer': {
|
|
3394
|
+
try {
|
|
3395
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3396
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3397
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3398
|
+
const key = process.env.PI || '';
|
|
3399
|
+
const client = new PiBrainClient({ url, key });
|
|
3400
|
+
const result = await client.transfer(args.source, args.target);
|
|
3401
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3402
|
+
} catch (e) {
|
|
3403
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3404
|
+
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
3405
|
}
|
|
3406
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3407
|
+
}
|
|
3408
|
+
}
|
|
3793
3409
|
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3410
|
+
case 'brain_sync': {
|
|
3411
|
+
try {
|
|
3412
|
+
const piBrain = require('@ruvector/pi-brain');
|
|
3413
|
+
const PiBrainClient = piBrain.PiBrainClient || piBrain.default;
|
|
3414
|
+
const url = process.env.BRAIN_URL || 'https://pi.ruv.io';
|
|
3415
|
+
const key = process.env.PI || '';
|
|
3416
|
+
const client = new PiBrainClient({ url, key });
|
|
3417
|
+
const result = await client.sync({ direction: args.direction || 'both' });
|
|
3418
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }, null, 2) }] };
|
|
3419
|
+
} catch (e) {
|
|
3420
|
+
if (e.code === 'MODULE_NOT_FOUND') {
|
|
3421
|
+
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
3422
|
}
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3423
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3802
3426
|
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3427
|
+
// ── Edge Tool Handlers ──────────────────────────────────────────────
|
|
3428
|
+
case 'edge_status': {
|
|
3429
|
+
try {
|
|
3430
|
+
const res = await fetch('https://edge-net-genesis-875130704813.us-central1.run.app/api/status');
|
|
3431
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3432
|
+
const data = await res.json();
|
|
3433
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3808
3434
|
} catch (e) {
|
|
3809
3435
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3810
3436
|
}
|
|
3811
3437
|
}
|
|
3812
3438
|
|
|
3813
|
-
case '
|
|
3439
|
+
case 'edge_join': {
|
|
3814
3440
|
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) }] };
|
|
3441
|
+
const key = args.key || process.env.PI || '';
|
|
3442
|
+
const res = await fetch('https://edge-net-genesis-875130704813.us-central1.run.app/api/join', {
|
|
3443
|
+
method: 'POST',
|
|
3444
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3445
|
+
body: JSON.stringify({ contribution: args.contribution || 0.3, key })
|
|
3446
|
+
});
|
|
3447
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3448
|
+
const data = await res.json();
|
|
3449
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3828
3450
|
} catch (e) {
|
|
3829
3451
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3830
3452
|
}
|
|
3831
3453
|
}
|
|
3832
3454
|
|
|
3833
|
-
case '
|
|
3455
|
+
case 'edge_balance': {
|
|
3834
3456
|
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) }] };
|
|
3457
|
+
const key = args.key || process.env.PI || '';
|
|
3458
|
+
const res = await fetch(`https://edge-net-genesis-875130704813.us-central1.run.app/api/balance?key=${encodeURIComponent(key)}`);
|
|
3459
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3460
|
+
const data = await res.json();
|
|
3461
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3850
3462
|
} catch (e) {
|
|
3851
3463
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3852
3464
|
}
|
|
3853
3465
|
}
|
|
3854
3466
|
|
|
3855
|
-
// ── Edge Tool Handlers ───────────────────────────────────────────────
|
|
3856
|
-
case 'edge_status':
|
|
3857
|
-
case 'edge_join':
|
|
3858
|
-
case 'edge_balance':
|
|
3859
3467
|
case 'edge_tasks': {
|
|
3860
3468
|
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();
|
|
3469
|
+
const res = await fetch('https://edge-net-genesis-875130704813.us-central1.run.app/api/tasks');
|
|
3470
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
3471
|
+
const data = await res.json();
|
|
3880
3472
|
return { content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }] };
|
|
3881
3473
|
} catch (e) {
|
|
3882
3474
|
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: e.message }, null, 2) }], isError: true };
|
|
3883
3475
|
}
|
|
3884
3476
|
}
|
|
3885
3477
|
|
|
3886
|
-
// ── Identity Tool Handlers
|
|
3478
|
+
// ── Identity Tool Handlers ──────────────────────────────────────────
|
|
3887
3479
|
case 'identity_generate': {
|
|
3888
3480
|
const crypto = require('crypto');
|
|
3889
3481
|
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) }] };
|
|
3482
|
+
const pseudonym = crypto.createHash('shake256', { outputLength: 16 }).update(key).digest('hex');
|
|
3483
|
+
const mcpToken = crypto.createHmac('sha256', key).update('mcp').digest('hex').slice(0, 32);
|
|
3484
|
+
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
3485
|
}
|
|
3895
3486
|
|
|
3896
3487
|
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
3488
|
const crypto = require('crypto');
|
|
3902
|
-
const
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3489
|
+
const key = args.key || process.env.PI || '';
|
|
3490
|
+
if (!key) {
|
|
3491
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: 'No PI key found. Set PI env var or pass key argument' }, null, 2) }] };
|
|
3492
|
+
}
|
|
3493
|
+
const pseudonym = crypto.createHash('shake256', { outputLength: 16 }).update(key).digest('hex');
|
|
3494
|
+
const mcpToken = crypto.createHmac('sha256', key).update('mcp').digest('hex').slice(0, 32);
|
|
3495
|
+
return { content: [{ type: 'text', text: JSON.stringify({ success: true, pseudonym, mcp_token: mcpToken, key_prefix: key.slice(0, 8) + '...' }, null, 2) }] };
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
// ── Decompiler Tool Handlers ─────────────────────────────────────────
|
|
3499
|
+
case 'decompile_package': {
|
|
3500
|
+
const decompiler = require('../src/decompiler/index.js');
|
|
3501
|
+
const result = await decompiler.decompilePackage(
|
|
3502
|
+
args.package,
|
|
3503
|
+
args.version || undefined,
|
|
3504
|
+
{ minConfidence: args.min_confidence || 0.3 }
|
|
3505
|
+
);
|
|
3506
|
+
return {
|
|
3507
|
+
content: [{
|
|
3508
|
+
type: 'text',
|
|
3509
|
+
text: JSON.stringify({
|
|
3510
|
+
success: true,
|
|
3511
|
+
packageInfo: result.packageInfo,
|
|
3512
|
+
modules: result.modules.map(m => ({
|
|
3513
|
+
name: m.name, fragments: m.fragments, confidence: m.confidence,
|
|
3514
|
+
contentPreview: m.content.slice(0, 500) + (m.content.length > 500 ? '...' : ''),
|
|
3515
|
+
})),
|
|
3516
|
+
metrics: result.metrics,
|
|
3517
|
+
witness_root: result.witness ? result.witness.root : null,
|
|
3518
|
+
}, null, 2)
|
|
3519
|
+
}]
|
|
3520
|
+
};
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
case 'decompile_file': {
|
|
3524
|
+
const decompiler = require('../src/decompiler/index.js');
|
|
3525
|
+
const safePath = validateRvfPath(args.path);
|
|
3526
|
+
const result = decompiler.decompileFile(safePath, {
|
|
3527
|
+
minConfidence: args.min_confidence || 0.3
|
|
3528
|
+
});
|
|
3529
|
+
return {
|
|
3530
|
+
content: [{
|
|
3531
|
+
type: 'text',
|
|
3532
|
+
text: JSON.stringify({
|
|
3533
|
+
success: true,
|
|
3534
|
+
filePath: result.filePath,
|
|
3535
|
+
modules: result.modules.map(m => ({
|
|
3536
|
+
name: m.name, fragments: m.fragments, confidence: m.confidence,
|
|
3537
|
+
contentPreview: m.content.slice(0, 500) + (m.content.length > 500 ? '...' : ''),
|
|
3538
|
+
})),
|
|
3539
|
+
metrics: result.metrics,
|
|
3540
|
+
witness_root: result.witness ? result.witness.root : null,
|
|
3541
|
+
}, null, 2)
|
|
3542
|
+
}]
|
|
3543
|
+
};
|
|
3544
|
+
}
|
|
3545
|
+
|
|
3546
|
+
case 'decompile_url': {
|
|
3547
|
+
const decompiler = require('../src/decompiler/index.js');
|
|
3548
|
+
const urlStr = args.url;
|
|
3549
|
+
// Basic URL validation
|
|
3550
|
+
if (!urlStr.startsWith('http://') && !urlStr.startsWith('https://')) {
|
|
3551
|
+
throw new Error('URL must start with http:// or https://');
|
|
3552
|
+
}
|
|
3553
|
+
const result = await decompiler.decompileUrl(urlStr, {
|
|
3554
|
+
minConfidence: args.min_confidence || 0.3
|
|
3555
|
+
});
|
|
3556
|
+
return {
|
|
3557
|
+
content: [{
|
|
3558
|
+
type: 'text',
|
|
3559
|
+
text: JSON.stringify({
|
|
3560
|
+
success: true,
|
|
3561
|
+
url: result.url,
|
|
3562
|
+
modules: result.modules.map(m => ({
|
|
3563
|
+
name: m.name, fragments: m.fragments, confidence: m.confidence,
|
|
3564
|
+
contentPreview: m.content.slice(0, 500) + (m.content.length > 500 ? '...' : ''),
|
|
3565
|
+
})),
|
|
3566
|
+
metrics: result.metrics,
|
|
3567
|
+
witness_root: result.witness ? result.witness.root : null,
|
|
3568
|
+
}, null, 2)
|
|
3569
|
+
}]
|
|
3570
|
+
};
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
case 'decompile_search': {
|
|
3574
|
+
const decompiler = require('../src/decompiler/index.js');
|
|
3575
|
+
let result;
|
|
3576
|
+
if (args.path) {
|
|
3577
|
+
const safePath = validateRvfPath(args.path);
|
|
3578
|
+
result = decompiler.decompileFile(safePath);
|
|
3579
|
+
} else if (args.package) {
|
|
3580
|
+
result = await decompiler.decompilePackage(args.package, args.version || undefined);
|
|
3581
|
+
} else {
|
|
3582
|
+
throw new Error('Either "package" or "path" must be provided');
|
|
3583
|
+
}
|
|
3584
|
+
|
|
3585
|
+
const query = args.query;
|
|
3586
|
+
let regex;
|
|
3587
|
+
try { regex = new RegExp(query, 'gi'); } catch { regex = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'); }
|
|
3588
|
+
|
|
3589
|
+
const matches = [];
|
|
3590
|
+
for (const mod of result.modules) {
|
|
3591
|
+
const lines = mod.content.split('\n');
|
|
3592
|
+
for (let i = 0; i < lines.length; i++) {
|
|
3593
|
+
if (regex.test(lines[i])) {
|
|
3594
|
+
matches.push({
|
|
3595
|
+
module: mod.name,
|
|
3596
|
+
line: i + 1,
|
|
3597
|
+
content: lines[i].trim().slice(0, 200),
|
|
3598
|
+
});
|
|
3599
|
+
regex.lastIndex = 0;
|
|
3600
|
+
}
|
|
3601
|
+
if (matches.length >= 50) break;
|
|
3602
|
+
}
|
|
3603
|
+
if (matches.length >= 50) break;
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3606
|
+
return {
|
|
3607
|
+
content: [{
|
|
3608
|
+
type: 'text',
|
|
3609
|
+
text: JSON.stringify({
|
|
3610
|
+
success: true,
|
|
3611
|
+
query,
|
|
3612
|
+
total_matches: matches.length,
|
|
3613
|
+
matches,
|
|
3614
|
+
}, null, 2)
|
|
3615
|
+
}]
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
case 'decompile_diff': {
|
|
3620
|
+
const decompiler = require('../src/decompiler/index.js');
|
|
3621
|
+
const [resultA, resultB] = await Promise.all([
|
|
3622
|
+
decompiler.decompilePackage(args.package, args.version_a),
|
|
3623
|
+
decompiler.decompilePackage(args.package, args.version_b),
|
|
3624
|
+
]);
|
|
3625
|
+
|
|
3626
|
+
const namesA = new Set(resultA.modules.map(m => m.name));
|
|
3627
|
+
const namesB = new Set(resultB.modules.map(m => m.name));
|
|
3628
|
+
const added = [...namesB].filter(n => !namesA.has(n));
|
|
3629
|
+
const removed = [...namesA].filter(n => !namesB.has(n));
|
|
3630
|
+
const common = [...namesA].filter(n => namesB.has(n));
|
|
3631
|
+
|
|
3632
|
+
// Compare declarations in common modules
|
|
3633
|
+
const changedDeclarations = [];
|
|
3634
|
+
for (const name of common) {
|
|
3635
|
+
const modA = resultA.modules.find(m => m.name === name);
|
|
3636
|
+
const modB = resultB.modules.find(m => m.name === name);
|
|
3637
|
+
if (modA && modB && modA.content !== modB.content) {
|
|
3638
|
+
changedDeclarations.push({
|
|
3639
|
+
module: name,
|
|
3640
|
+
sizeChange: modB.content.length - modA.content.length,
|
|
3641
|
+
fragmentsA: modA.fragments,
|
|
3642
|
+
fragmentsB: modB.fragments,
|
|
3643
|
+
});
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
return {
|
|
3648
|
+
content: [{
|
|
3649
|
+
type: 'text',
|
|
3650
|
+
text: JSON.stringify({
|
|
3651
|
+
success: true,
|
|
3652
|
+
package: args.package,
|
|
3653
|
+
version_a: args.version_a,
|
|
3654
|
+
version_b: args.version_b,
|
|
3655
|
+
added_modules: added,
|
|
3656
|
+
removed_modules: removed,
|
|
3657
|
+
common_modules: common.length,
|
|
3658
|
+
changed_declarations: changedDeclarations,
|
|
3659
|
+
metrics_a: resultA.metrics.source,
|
|
3660
|
+
metrics_b: resultB.metrics.source,
|
|
3661
|
+
}, null, 2)
|
|
3662
|
+
}]
|
|
3663
|
+
};
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
case 'decompile_witness': {
|
|
3667
|
+
const decompiler = require('../src/decompiler/index.js');
|
|
3668
|
+
const witnessPath = validateRvfPath(args.witness_path);
|
|
3669
|
+
const witnessData = JSON.parse(fs.readFileSync(witnessPath, 'utf-8'));
|
|
3670
|
+
|
|
3671
|
+
let sourceContent = undefined;
|
|
3672
|
+
if (args.source_path) {
|
|
3673
|
+
const sourcePath = validateRvfPath(args.source_path);
|
|
3674
|
+
sourceContent = fs.readFileSync(sourcePath, 'utf-8');
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
const verification = decompiler.verifyWitnessChain(witnessData, sourceContent);
|
|
3678
|
+
return {
|
|
3679
|
+
content: [{
|
|
3680
|
+
type: 'text',
|
|
3681
|
+
text: JSON.stringify({
|
|
3682
|
+
success: true,
|
|
3683
|
+
...verification,
|
|
3684
|
+
}, null, 2)
|
|
3685
|
+
}]
|
|
3686
|
+
};
|
|
3907
3687
|
}
|
|
3908
3688
|
|
|
3909
3689
|
default:
|
|
@@ -3994,173 +3774,9 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
3994
3774
|
|
|
3995
3775
|
// Start server
|
|
3996
3776
|
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
|
-
}
|
|
3777
|
+
const transport = new StdioServerTransport();
|
|
3778
|
+
await server.connect(transport);
|
|
3779
|
+
console.error('RuVector MCP server running on stdio');
|
|
4164
3780
|
}
|
|
4165
3781
|
|
|
4166
3782
|
main().catch(console.error);
|