open-agents-ai 0.71.3 → 0.71.5
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/dist/index.js +492 -616
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -11166,167 +11166,206 @@ ${truncated}`, durationMs: performance.now() - start };
|
|
|
11166
11166
|
});
|
|
11167
11167
|
|
|
11168
11168
|
// packages/execution/dist/tools/nexus.js
|
|
11169
|
-
import { readFile as readFile13, writeFile as writeFile12, mkdir as mkdir8, chmod } from "node:fs/promises";
|
|
11169
|
+
import { readFile as readFile13, writeFile as writeFile12, mkdir as mkdir8, chmod, unlink, readdir as readdir3 } from "node:fs/promises";
|
|
11170
11170
|
import { existsSync as existsSync21 } from "node:fs";
|
|
11171
11171
|
import { resolve as resolve26, join as join28 } from "node:path";
|
|
11172
|
-
import { randomBytes as randomBytes6, createCipheriv, createDecipheriv, scryptSync } from "node:crypto";
|
|
11173
|
-
import { execSync as execSync20 } from "node:child_process";
|
|
11174
|
-
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
} catch {
|
|
11179
|
-
try {
|
|
11180
|
-
execSync20("npm install -g open-agents-nexus@latest 2>/dev/null || npm install open-agents-nexus@latest 2>/dev/null", {
|
|
11181
|
-
stdio: "pipe",
|
|
11182
|
-
timeout: 12e4
|
|
11183
|
-
});
|
|
11184
|
-
nexusMod = await import("open-agents-nexus");
|
|
11185
|
-
} catch {
|
|
11186
|
-
throw new Error("Failed to auto-install open-agents-nexus. Install manually: npm install -g open-agents-nexus");
|
|
11187
|
-
}
|
|
11188
|
-
}
|
|
11172
|
+
import { randomBytes as randomBytes6, createCipheriv, createDecipheriv, scryptSync, createHash } from "node:crypto";
|
|
11173
|
+
import { execSync as execSync20, spawn as spawn10 } from "node:child_process";
|
|
11174
|
+
function containsKeyMaterial(input) {
|
|
11175
|
+
for (const pattern of KEY_PATTERNS) {
|
|
11176
|
+
if (pattern.test(input))
|
|
11177
|
+
return true;
|
|
11189
11178
|
}
|
|
11190
|
-
return
|
|
11179
|
+
return false;
|
|
11191
11180
|
}
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11181
|
+
var DAEMON_SCRIPT, KEY_PATTERNS, NexusTool;
|
|
11182
|
+
var init_nexus = __esm({
|
|
11183
|
+
"packages/execution/dist/tools/nexus.js"() {
|
|
11184
|
+
"use strict";
|
|
11185
|
+
DAEMON_SCRIPT = `#!/usr/bin/env node
|
|
11186
|
+
/**
|
|
11187
|
+
* nexus-daemon.mjs \u2014 Standalone nexus process with real TCP/UDP sockets.
|
|
11188
|
+
* Spawned by the open-agents nexus tool. Communicates via JSON files.
|
|
11189
|
+
*
|
|
11190
|
+
* Usage: node nexus-daemon.mjs <nexus-dir> <agent-name> [agent-type]
|
|
11191
|
+
*/
|
|
11192
|
+
|
|
11193
|
+
// Polyfill for Node <22 (libp2p's it-queue/mortice depends on this)
|
|
11194
|
+
if (typeof Promise.withResolvers === 'undefined') {
|
|
11195
|
+
Promise.withResolvers = function withResolvers() {
|
|
11196
|
+
let resolve, reject;
|
|
11197
|
+
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
|
|
11198
|
+
return { promise, resolve, reject };
|
|
11199
|
+
};
|
|
11198
11200
|
}
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11201
|
+
|
|
11202
|
+
import { NexusClient } from 'open-agents-nexus';
|
|
11203
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from 'node:fs';
|
|
11204
|
+
import { join } from 'node:path';
|
|
11205
|
+
|
|
11206
|
+
const nexusDir = process.argv[2];
|
|
11207
|
+
const agentName = process.argv[3] || 'open-agents-node';
|
|
11208
|
+
const agentType = process.argv[4] || 'general';
|
|
11209
|
+
const cmdFile = join(nexusDir, 'cmd.json');
|
|
11210
|
+
const respFile = join(nexusDir, 'resp.json');
|
|
11211
|
+
const statusFile = join(nexusDir, 'status.json');
|
|
11212
|
+
const inboxDir = join(nexusDir, 'inbox');
|
|
11213
|
+
const pidFile = join(nexusDir, 'daemon.pid');
|
|
11214
|
+
|
|
11215
|
+
mkdirSync(inboxDir, { recursive: true });
|
|
11216
|
+
|
|
11217
|
+
// Write PID so the agent can kill us
|
|
11218
|
+
writeFileSync(pidFile, String(process.pid));
|
|
11219
|
+
|
|
11220
|
+
const keyPath = join(nexusDir, 'identity.key');
|
|
11221
|
+
const nexus = new NexusClient({
|
|
11222
|
+
keyStorePath: keyPath,
|
|
11223
|
+
agentName,
|
|
11224
|
+
agentType,
|
|
11225
|
+
role: 'light',
|
|
11226
|
+
enableMdns: true,
|
|
11227
|
+
enablePubsubDiscovery: true,
|
|
11228
|
+
});
|
|
11229
|
+
|
|
11230
|
+
const rooms = new Map();
|
|
11231
|
+
let connected = false;
|
|
11232
|
+
|
|
11233
|
+
function writeStatus(extra = {}) {
|
|
11234
|
+
const data = {
|
|
11235
|
+
pid: process.pid,
|
|
11236
|
+
connected,
|
|
11237
|
+
peerId: connected ? nexus.peerId : null,
|
|
11238
|
+
agentName,
|
|
11239
|
+
agentType,
|
|
11240
|
+
rooms: [...rooms.keys()],
|
|
11241
|
+
connectedAt: connected ? new Date().toISOString() : null,
|
|
11242
|
+
...extra,
|
|
11212
11243
|
};
|
|
11244
|
+
try { writeFileSync(statusFile, JSON.stringify(data, null, 2)); } catch {}
|
|
11245
|
+
}
|
|
11246
|
+
|
|
11247
|
+
function writeResp(id, result) {
|
|
11248
|
+
try { writeFileSync(respFile, JSON.stringify({ id, ...result }, null, 2)); } catch {}
|
|
11213
11249
|
}
|
|
11214
|
-
|
|
11250
|
+
|
|
11251
|
+
async function handleCmd(cmd) {
|
|
11252
|
+
const { id, action, args } = cmd;
|
|
11215
11253
|
try {
|
|
11216
|
-
|
|
11217
|
-
|
|
11218
|
-
|
|
11219
|
-
|
|
11220
|
-
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
let gpuName = "none";
|
|
11235
|
-
let vramMb = 0;
|
|
11236
|
-
try {
|
|
11237
|
-
const nvidiaSmi = execSync20("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null", {
|
|
11238
|
-
timeout: 5e3,
|
|
11239
|
-
encoding: "utf8"
|
|
11240
|
-
});
|
|
11241
|
-
const gpuParts = nvidiaSmi.trim().split(",");
|
|
11242
|
-
gpuName = gpuParts[0]?.trim() || "unknown";
|
|
11243
|
-
vramMb = parseInt(gpuParts[1]?.trim() || "0", 10);
|
|
11244
|
-
} catch {
|
|
11245
|
-
try {
|
|
11246
|
-
const rocmSmi = execSync20("rocm-smi --showmeminfo vram 2>/dev/null", {
|
|
11247
|
-
timeout: 5e3,
|
|
11248
|
-
encoding: "utf8"
|
|
11254
|
+
switch (action) {
|
|
11255
|
+
case 'join_room': {
|
|
11256
|
+
const roomId = args.room_id;
|
|
11257
|
+
if (rooms.has(roomId)) { writeResp(id, { ok: true, output: 'Already in room: ' + roomId }); return; }
|
|
11258
|
+
const room = await nexus.joinRoom(roomId);
|
|
11259
|
+
rooms.set(roomId, room);
|
|
11260
|
+
room.on('message', (msg) => {
|
|
11261
|
+
const roomInbox = join(inboxDir, roomId);
|
|
11262
|
+
mkdirSync(roomInbox, { recursive: true });
|
|
11263
|
+
const fname = Date.now() + '-' + (msg.id || '').slice(0, 8) + '.json';
|
|
11264
|
+
const entry = {
|
|
11265
|
+
sender: msg.sender,
|
|
11266
|
+
content: msg.payload?.content || '',
|
|
11267
|
+
format: msg.payload?.format || 'text/plain',
|
|
11268
|
+
timestamp: msg.timestamp || Date.now(),
|
|
11269
|
+
id: msg.id,
|
|
11270
|
+
};
|
|
11271
|
+
try { writeFileSync(join(roomInbox, fname), JSON.stringify(entry, null, 2)); } catch {}
|
|
11249
11272
|
});
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
vramMb = match ? Math.round(parseInt(match[1], 10) / (1024 * 1024)) : 0;
|
|
11254
|
-
}
|
|
11255
|
-
} catch {
|
|
11273
|
+
writeStatus();
|
|
11274
|
+
writeResp(id, { ok: true, output: 'Joined room: ' + roomId });
|
|
11275
|
+
break;
|
|
11256
11276
|
}
|
|
11277
|
+
case 'leave_room': {
|
|
11278
|
+
const roomId = args.room_id;
|
|
11279
|
+
const room = rooms.get(roomId);
|
|
11280
|
+
if (!room) { writeResp(id, { ok: false, output: 'Not in room: ' + roomId }); return; }
|
|
11281
|
+
await room.leave();
|
|
11282
|
+
rooms.delete(roomId);
|
|
11283
|
+
writeStatus();
|
|
11284
|
+
writeResp(id, { ok: true, output: 'Left room: ' + roomId });
|
|
11285
|
+
break;
|
|
11286
|
+
}
|
|
11287
|
+
case 'send_message': {
|
|
11288
|
+
const room = rooms.get(args.room_id);
|
|
11289
|
+
if (!room) { writeResp(id, { ok: false, output: 'Not in room: ' + args.room_id + '. Join it first.' }); return; }
|
|
11290
|
+
const msgId = await room.send(args.message, { format: 'text/plain' });
|
|
11291
|
+
writeResp(id, { ok: true, output: 'Message sent (id: ' + msgId + ')' });
|
|
11292
|
+
break;
|
|
11293
|
+
}
|
|
11294
|
+
case 'discover_peers': {
|
|
11295
|
+
const node = nexus.network?.node;
|
|
11296
|
+
const peers = node?.getPeers?.() || [];
|
|
11297
|
+
const list = peers.slice(0, 20).map(p => p.toString?.() || String(p));
|
|
11298
|
+
writeResp(id, { ok: true, output: 'Peers: ' + list.length + '\\n' + list.map(p => ' ' + p.slice(0, 20) + '...').join('\\n') });
|
|
11299
|
+
break;
|
|
11300
|
+
}
|
|
11301
|
+
case 'list_rooms': {
|
|
11302
|
+
const joined = [...rooms.keys()];
|
|
11303
|
+
writeResp(id, { ok: true, output: joined.length ? 'Rooms: ' + joined.join(', ') : 'No rooms joined.' });
|
|
11304
|
+
break;
|
|
11305
|
+
}
|
|
11306
|
+
case 'ping': {
|
|
11307
|
+
writeResp(id, { ok: true, output: 'pong' });
|
|
11308
|
+
break;
|
|
11309
|
+
}
|
|
11310
|
+
default:
|
|
11311
|
+
writeResp(id, { ok: false, output: 'Unknown daemon command: ' + action });
|
|
11257
11312
|
}
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
const { createHash: createHash4 } = __require("node:crypto");
|
|
11261
|
-
const benchmarkHash = createHash4("sha256").update(hashInput).digest("hex");
|
|
11262
|
-
return {
|
|
11263
|
-
modelName,
|
|
11264
|
-
modelSize: parts[1] || "unknown",
|
|
11265
|
-
tokensPerSecond: tps,
|
|
11266
|
-
promptEvalTps: tps,
|
|
11267
|
-
// simplified — same as generation for now
|
|
11268
|
-
contextLength: 32768,
|
|
11269
|
-
// default assumption
|
|
11270
|
-
gpuLayers: vramMb > 0 ? 99 : 0,
|
|
11271
|
-
gpuName,
|
|
11272
|
-
vramMb,
|
|
11273
|
-
benchmarkHash,
|
|
11274
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11275
|
-
};
|
|
11276
|
-
} catch {
|
|
11277
|
-
return null;
|
|
11313
|
+
} catch (err) {
|
|
11314
|
+
writeResp(id, { ok: false, output: 'Error: ' + (err.message || String(err)) });
|
|
11278
11315
|
}
|
|
11279
11316
|
}
|
|
11280
|
-
|
|
11317
|
+
|
|
11318
|
+
// Command polling loop \u2014 check for cmd.json every 500ms
|
|
11319
|
+
let lastCmdId = '';
|
|
11320
|
+
setInterval(() => {
|
|
11281
11321
|
try {
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11322
|
+
if (!existsSync(cmdFile)) return;
|
|
11323
|
+
const raw = readFileSync(cmdFile, 'utf8');
|
|
11324
|
+
const cmd = JSON.parse(raw);
|
|
11325
|
+
if (cmd.id === lastCmdId) return; // already processed
|
|
11326
|
+
lastCmdId = cmd.id;
|
|
11327
|
+
handleCmd(cmd);
|
|
11328
|
+
} catch {}
|
|
11329
|
+
}, 500);
|
|
11330
|
+
|
|
11331
|
+
// Connect
|
|
11332
|
+
(async () => {
|
|
11333
|
+
try {
|
|
11334
|
+
await nexus.connect();
|
|
11335
|
+
// Ensure node is started (libp2p compat)
|
|
11336
|
+
const node = nexus.network?.node;
|
|
11337
|
+
if (node && typeof node.start === 'function' && !node.isStarted?.()) {
|
|
11338
|
+
await node.start();
|
|
11339
|
+
}
|
|
11340
|
+
connected = true;
|
|
11341
|
+
writeStatus();
|
|
11342
|
+
console.log('Nexus daemon connected as ' + nexus.peerId);
|
|
11343
|
+
} catch (err) {
|
|
11344
|
+
writeStatus({ error: err.message || String(err) });
|
|
11345
|
+
console.error('Nexus daemon connect failed:', err.message || err);
|
|
11346
|
+
process.exit(1);
|
|
11298
11347
|
}
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11348
|
+
})();
|
|
11349
|
+
|
|
11350
|
+
// Graceful shutdown
|
|
11351
|
+
process.on('SIGTERM', async () => {
|
|
11352
|
+
for (const [, room] of rooms) { try { await room.leave(); } catch {} }
|
|
11353
|
+
await nexus.disconnect();
|
|
11354
|
+
try { unlinkSync(pidFile); } catch {}
|
|
11355
|
+
try { unlinkSync(statusFile); } catch {}
|
|
11356
|
+
process.exit(0);
|
|
11357
|
+
});
|
|
11358
|
+
process.on('SIGINT', () => process.emit('SIGTERM'));
|
|
11359
|
+
`;
|
|
11311
11360
|
KEY_PATTERNS = [
|
|
11312
11361
|
/0x[0-9a-fA-F]{64}/,
|
|
11313
|
-
// Ethereum private key
|
|
11314
11362
|
/[5KL][1-9A-HJ-NP-Za-km-z]{50,51}/,
|
|
11315
|
-
// Bitcoin WIF
|
|
11316
11363
|
/-----BEGIN.*PRIVATE KEY-----/,
|
|
11317
|
-
|
|
11318
|
-
/ed25519:[A-Za-z0-9+/=]{40,}/,
|
|
11319
|
-
// Ed25519 key
|
|
11320
|
-
/[0-9a-fA-F]{64}/
|
|
11321
|
-
// Raw 256-bit hex key (loose match — check context)
|
|
11364
|
+
/ed25519:[A-Za-z0-9+/=]{40,}/
|
|
11322
11365
|
];
|
|
11323
|
-
clientInstance = null;
|
|
11324
|
-
activeRooms = /* @__PURE__ */ new Map();
|
|
11325
|
-
registeredServices = [];
|
|
11326
|
-
connectionPeerId = "";
|
|
11327
11366
|
NexusTool = class {
|
|
11328
11367
|
name = "nexus";
|
|
11329
|
-
description = "Decentralized agent-to-agent communication via open-agents-nexus. Simple flow: connect \u2192 join room \u2192 send messages.
|
|
11368
|
+
description = "Decentralized agent-to-agent communication via open-agents-nexus. Spawns a background Node.js process with real network sockets for libp2p P2P mesh. Simple flow: connect \u2192 join room \u2192 send messages. Auto-installs nexus if needed. Also supports peer discovery, x402 micropayments, and inference proofs.";
|
|
11330
11369
|
parameters = {
|
|
11331
11370
|
type: "object",
|
|
11332
11371
|
properties: {
|
|
@@ -11339,55 +11378,23 @@ var init_nexus = __esm({
|
|
|
11339
11378
|
"join_room",
|
|
11340
11379
|
"leave_room",
|
|
11341
11380
|
"send_message",
|
|
11342
|
-
"
|
|
11381
|
+
"read_messages",
|
|
11343
11382
|
"discover_peers",
|
|
11344
|
-
"
|
|
11345
|
-
"register_service",
|
|
11346
|
-
"list_services",
|
|
11383
|
+
"list_rooms",
|
|
11347
11384
|
"wallet_status",
|
|
11348
11385
|
"wallet_create",
|
|
11349
|
-
"inference_proof"
|
|
11350
|
-
"store_content",
|
|
11351
|
-
"retrieve_content"
|
|
11386
|
+
"inference_proof"
|
|
11352
11387
|
],
|
|
11353
11388
|
description: "The nexus action to perform"
|
|
11354
11389
|
},
|
|
11355
11390
|
room_id: {
|
|
11356
11391
|
type: "string",
|
|
11357
|
-
description: "Room ID for join_room, leave_room, send_message"
|
|
11358
|
-
},
|
|
11359
|
-
room_name: {
|
|
11360
|
-
type: "string",
|
|
11361
|
-
description: "Human-readable room name (for join_room creation)"
|
|
11392
|
+
description: "Room ID for join_room, leave_room, send_message, read_messages"
|
|
11362
11393
|
},
|
|
11363
11394
|
message: {
|
|
11364
11395
|
type: "string",
|
|
11365
11396
|
description: "Message content for send_message (scanned for key leaks)"
|
|
11366
11397
|
},
|
|
11367
|
-
peer_id: {
|
|
11368
|
-
type: "string",
|
|
11369
|
-
description: "Peer ID for find_agent"
|
|
11370
|
-
},
|
|
11371
|
-
service_id: {
|
|
11372
|
-
type: "string",
|
|
11373
|
-
description: "Service identifier for register_service"
|
|
11374
|
-
},
|
|
11375
|
-
service_name: {
|
|
11376
|
-
type: "string",
|
|
11377
|
-
description: "Human-readable service name"
|
|
11378
|
-
},
|
|
11379
|
-
service_description: {
|
|
11380
|
-
type: "string",
|
|
11381
|
-
description: "Service description"
|
|
11382
|
-
},
|
|
11383
|
-
price_amount: {
|
|
11384
|
-
type: "string",
|
|
11385
|
-
description: "Price per request in USDC (e.g. '0.001')"
|
|
11386
|
-
},
|
|
11387
|
-
rate_limit: {
|
|
11388
|
-
type: "number",
|
|
11389
|
-
description: "Max requests per hour for this service"
|
|
11390
|
-
},
|
|
11391
11398
|
agent_name: {
|
|
11392
11399
|
type: "string",
|
|
11393
11400
|
description: "Agent display name for connect"
|
|
@@ -11399,14 +11406,6 @@ var init_nexus = __esm({
|
|
|
11399
11406
|
wallet_address: {
|
|
11400
11407
|
type: "string",
|
|
11401
11408
|
description: "Wallet address for wallet_create (user-provided receive address)"
|
|
11402
|
-
},
|
|
11403
|
-
content: {
|
|
11404
|
-
type: "string",
|
|
11405
|
-
description: "Content to store for store_content"
|
|
11406
|
-
},
|
|
11407
|
-
cid: {
|
|
11408
|
-
type: "string",
|
|
11409
|
-
description: "Content identifier for retrieve_content"
|
|
11410
11409
|
}
|
|
11411
11410
|
},
|
|
11412
11411
|
required: ["action"],
|
|
@@ -11439,28 +11438,22 @@ var init_nexus = __esm({
|
|
|
11439
11438
|
result = await this.doStatus();
|
|
11440
11439
|
break;
|
|
11441
11440
|
case "join_room":
|
|
11442
|
-
result = await this.
|
|
11441
|
+
result = await this.sendDaemonCmd("join_room", args);
|
|
11443
11442
|
break;
|
|
11444
11443
|
case "leave_room":
|
|
11445
|
-
result = await this.
|
|
11444
|
+
result = await this.sendDaemonCmd("leave_room", args);
|
|
11446
11445
|
break;
|
|
11447
11446
|
case "send_message":
|
|
11448
11447
|
result = await this.doSendMessage(args);
|
|
11449
11448
|
break;
|
|
11450
|
-
case "
|
|
11451
|
-
result = await this.
|
|
11449
|
+
case "read_messages":
|
|
11450
|
+
result = await this.doReadMessages(args);
|
|
11452
11451
|
break;
|
|
11453
11452
|
case "discover_peers":
|
|
11454
|
-
result = await this.
|
|
11455
|
-
break;
|
|
11456
|
-
case "find_agent":
|
|
11457
|
-
result = await this.doFindAgent(args);
|
|
11458
|
-
break;
|
|
11459
|
-
case "register_service":
|
|
11460
|
-
result = await this.doRegisterService(args);
|
|
11453
|
+
result = await this.sendDaemonCmd("discover_peers", args);
|
|
11461
11454
|
break;
|
|
11462
|
-
case "
|
|
11463
|
-
result = await this.
|
|
11455
|
+
case "list_rooms":
|
|
11456
|
+
result = await this.sendDaemonCmd("list_rooms", args);
|
|
11464
11457
|
break;
|
|
11465
11458
|
case "wallet_status":
|
|
11466
11459
|
result = await this.doWalletStatus();
|
|
@@ -11471,484 +11464,367 @@ var init_nexus = __esm({
|
|
|
11471
11464
|
case "inference_proof":
|
|
11472
11465
|
result = await this.doInferenceProof();
|
|
11473
11466
|
break;
|
|
11474
|
-
case "store_content":
|
|
11475
|
-
result = await this.doStoreContent(args);
|
|
11476
|
-
break;
|
|
11477
|
-
case "retrieve_content":
|
|
11478
|
-
result = await this.doRetrieveContent(args);
|
|
11479
|
-
break;
|
|
11480
11467
|
default:
|
|
11481
|
-
return {
|
|
11482
|
-
success: false,
|
|
11483
|
-
output: "",
|
|
11484
|
-
error: `Unknown nexus action: ${action}`,
|
|
11485
|
-
durationMs: Date.now() - start
|
|
11486
|
-
};
|
|
11468
|
+
return { success: false, output: "", error: `Unknown nexus action: ${action}`, durationMs: Date.now() - start };
|
|
11487
11469
|
}
|
|
11488
11470
|
return { success: true, output: result, durationMs: Date.now() - start };
|
|
11489
11471
|
} catch (err) {
|
|
11490
|
-
return {
|
|
11491
|
-
success: false,
|
|
11492
|
-
output: "",
|
|
11493
|
-
error: err.message || String(err),
|
|
11494
|
-
durationMs: Date.now() - start
|
|
11495
|
-
};
|
|
11472
|
+
return { success: false, output: "", error: err.message || String(err), durationMs: Date.now() - start };
|
|
11496
11473
|
}
|
|
11497
11474
|
}
|
|
11498
11475
|
// =========================================================================
|
|
11499
|
-
//
|
|
11476
|
+
// Daemon management
|
|
11500
11477
|
// =========================================================================
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11478
|
+
getDaemonPid() {
|
|
11479
|
+
const pidFile = join28(this.nexusDir, "daemon.pid");
|
|
11480
|
+
if (!existsSync21(pidFile))
|
|
11481
|
+
return null;
|
|
11482
|
+
try {
|
|
11483
|
+
const pid = parseInt(__require("node:fs").readFileSync(pidFile, "utf8").trim(), 10);
|
|
11484
|
+
process.kill(pid, 0);
|
|
11485
|
+
return pid;
|
|
11486
|
+
} catch {
|
|
11487
|
+
return null;
|
|
11504
11488
|
}
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
const
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
const
|
|
11512
|
-
|
|
11489
|
+
}
|
|
11490
|
+
async sendDaemonCmd(action, args) {
|
|
11491
|
+
const pid = this.getDaemonPid();
|
|
11492
|
+
if (!pid)
|
|
11493
|
+
throw new Error("Nexus daemon not running. Use action 'connect' first.");
|
|
11494
|
+
const cmdId = randomBytes6(8).toString("hex");
|
|
11495
|
+
const cmdFile = join28(this.nexusDir, "cmd.json");
|
|
11496
|
+
const respFile = join28(this.nexusDir, "resp.json");
|
|
11497
|
+
if (existsSync21(respFile))
|
|
11498
|
+
await unlink(respFile).catch(() => {
|
|
11499
|
+
});
|
|
11500
|
+
await writeFile12(cmdFile, JSON.stringify({ id: cmdId, action, args }, null, 2));
|
|
11501
|
+
for (let i = 0; i < 30; i++) {
|
|
11502
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
11503
|
+
if (!existsSync21(respFile))
|
|
11504
|
+
continue;
|
|
11513
11505
|
try {
|
|
11514
|
-
const
|
|
11515
|
-
|
|
11506
|
+
const resp = JSON.parse(await readFile13(respFile, "utf8"));
|
|
11507
|
+
if (resp.id === cmdId) {
|
|
11508
|
+
return resp.output || (resp.ok ? "OK" : "Failed");
|
|
11509
|
+
}
|
|
11516
11510
|
} catch {
|
|
11517
11511
|
}
|
|
11518
11512
|
}
|
|
11519
|
-
|
|
11520
|
-
keyStorePath: keyPath,
|
|
11521
|
-
agentName,
|
|
11522
|
-
agentType,
|
|
11523
|
-
role: "light",
|
|
11524
|
-
enableMdns: true,
|
|
11525
|
-
enablePubsubDiscovery: true,
|
|
11526
|
-
x402: walletAddress ? { enabled: true, walletAddress, allowedCurrencies: ["USDC"], allowedNetworks: ["base"] } : { enabled: false }
|
|
11527
|
-
});
|
|
11528
|
-
await client.connect();
|
|
11529
|
-
clientInstance = client;
|
|
11530
|
-
connectionPeerId = client.peerId;
|
|
11531
|
-
await writeFile12(join28(this.nexusDir, "connection.json"), JSON.stringify({
|
|
11532
|
-
peerId: connectionPeerId,
|
|
11533
|
-
agentName,
|
|
11534
|
-
agentType,
|
|
11535
|
-
connectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11536
|
-
walletAddress: walletAddress || null
|
|
11537
|
-
}, null, 2));
|
|
11538
|
-
return [
|
|
11539
|
-
`Connected to nexus P2P network.`,
|
|
11540
|
-
` Peer ID: ${connectionPeerId}`,
|
|
11541
|
-
` Agent: ${agentName} (${agentType})`,
|
|
11542
|
-
` Role: light`,
|
|
11543
|
-
walletAddress ? ` Wallet: ${walletAddress}` : ` Wallet: not configured (use wallet_create)`,
|
|
11544
|
-
` x402 payments: ${walletAddress ? "enabled" : "disabled"}`,
|
|
11545
|
-
``,
|
|
11546
|
-
`You can now join rooms, discover peers, and participate in the agent mesh.`
|
|
11547
|
-
].join("\n");
|
|
11513
|
+
return "Daemon did not respond within 15s. It may still be processing.";
|
|
11548
11514
|
}
|
|
11549
|
-
|
|
11550
|
-
|
|
11551
|
-
|
|
11515
|
+
// =========================================================================
|
|
11516
|
+
// Actions
|
|
11517
|
+
// =========================================================================
|
|
11518
|
+
async doConnect(args) {
|
|
11519
|
+
await this.ensureDir();
|
|
11520
|
+
const existingPid = this.getDaemonPid();
|
|
11521
|
+
if (existingPid) {
|
|
11522
|
+
const statusFile2 = join28(this.nexusDir, "status.json");
|
|
11523
|
+
if (existsSync21(statusFile2)) {
|
|
11524
|
+
try {
|
|
11525
|
+
const status = JSON.parse(await readFile13(statusFile2, "utf8"));
|
|
11526
|
+
return `Already connected (pid: ${existingPid}, peerId: ${status.peerId || "starting..."})`;
|
|
11527
|
+
} catch {
|
|
11528
|
+
}
|
|
11529
|
+
}
|
|
11530
|
+
return `Daemon already running (pid: ${existingPid}).`;
|
|
11552
11531
|
}
|
|
11553
|
-
|
|
11532
|
+
try {
|
|
11533
|
+
execSync20(`node -e "require.resolve('open-agents-nexus')"`, { stdio: "pipe", timeout: 5e3 });
|
|
11534
|
+
} catch {
|
|
11554
11535
|
try {
|
|
11555
|
-
|
|
11536
|
+
execSync20("npm install -g open-agents-nexus@latest 2>&1 || npm install open-agents-nexus@latest 2>&1", {
|
|
11537
|
+
stdio: "pipe",
|
|
11538
|
+
timeout: 12e4
|
|
11539
|
+
});
|
|
11556
11540
|
} catch {
|
|
11541
|
+
throw new Error("Failed to install open-agents-nexus. Run: npm install -g open-agents-nexus");
|
|
11557
11542
|
}
|
|
11558
11543
|
}
|
|
11559
|
-
|
|
11560
|
-
await
|
|
11561
|
-
|
|
11562
|
-
const
|
|
11563
|
-
|
|
11564
|
-
|
|
11565
|
-
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11544
|
+
const daemonPath = join28(this.nexusDir, "nexus-daemon.mjs");
|
|
11545
|
+
await writeFile12(daemonPath, DAEMON_SCRIPT);
|
|
11546
|
+
const agentName = args.agent_name || "open-agents-node";
|
|
11547
|
+
const agentType = args.agent_type || "general";
|
|
11548
|
+
const child = spawn10("node", [daemonPath, this.nexusDir, agentName, agentType], {
|
|
11549
|
+
detached: true,
|
|
11550
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11551
|
+
cwd: this.repoRoot
|
|
11552
|
+
});
|
|
11553
|
+
child.unref();
|
|
11554
|
+
let earlyOutput = "";
|
|
11555
|
+
let earlyError = "";
|
|
11556
|
+
child.stdout?.on("data", (d) => {
|
|
11557
|
+
earlyOutput += d.toString();
|
|
11558
|
+
});
|
|
11559
|
+
child.stderr?.on("data", (d) => {
|
|
11560
|
+
earlyError += d.toString();
|
|
11561
|
+
});
|
|
11562
|
+
const statusFile = join28(this.nexusDir, "status.json");
|
|
11563
|
+
for (let i = 0; i < 40; i++) {
|
|
11564
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
11565
|
+
if (existsSync21(statusFile)) {
|
|
11566
|
+
try {
|
|
11567
|
+
const status = JSON.parse(await readFile13(statusFile, "utf8"));
|
|
11568
|
+
if (status.error) {
|
|
11569
|
+
return `Nexus daemon failed to connect: ${status.error}`;
|
|
11570
|
+
}
|
|
11571
|
+
if (status.connected && status.peerId) {
|
|
11572
|
+
return [
|
|
11573
|
+
`Connected to nexus P2P network.`,
|
|
11574
|
+
` Peer ID: ${status.peerId}`,
|
|
11575
|
+
` Agent: ${agentName} (${agentType})`,
|
|
11576
|
+
` Daemon PID: ${status.pid}`,
|
|
11577
|
+
``,
|
|
11578
|
+
`Use join_room to enter a room, then send_message to communicate.`
|
|
11579
|
+
].join("\n");
|
|
11580
|
+
}
|
|
11581
|
+
} catch {
|
|
11582
|
+
}
|
|
11583
|
+
}
|
|
11569
11584
|
}
|
|
11570
|
-
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
if (!clientInstance) {
|
|
11574
|
-
return "Not connected. Use action 'connect' to join the nexus network.";
|
|
11585
|
+
const pid = this.getDaemonPid();
|
|
11586
|
+
if (pid) {
|
|
11587
|
+
return `Daemon spawned (pid: ${pid}) but still connecting. Check status in a moment.${earlyError ? "\nStderr: " + earlyError.slice(0, 200) : ""}`;
|
|
11575
11588
|
}
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
const
|
|
11580
|
-
if (
|
|
11589
|
+
return `Daemon failed to start.${earlyError ? "\n" + earlyError.slice(0, 500) : ""}${earlyOutput ? "\n" + earlyOutput.slice(0, 500) : ""}`;
|
|
11590
|
+
}
|
|
11591
|
+
async doDisconnect() {
|
|
11592
|
+
const pid = this.getDaemonPid();
|
|
11593
|
+
if (!pid)
|
|
11594
|
+
return "Nexus daemon not running.";
|
|
11595
|
+
try {
|
|
11596
|
+
process.kill(pid, "SIGTERM");
|
|
11597
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
11581
11598
|
try {
|
|
11582
|
-
|
|
11583
|
-
|
|
11599
|
+
process.kill(pid, 0);
|
|
11600
|
+
process.kill(pid, "SIGKILL");
|
|
11584
11601
|
} catch {
|
|
11585
|
-
walletInfo = "corrupt";
|
|
11586
11602
|
}
|
|
11603
|
+
} catch {
|
|
11587
11604
|
}
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
` Rooms joined: ${rooms.length} [${rooms.join(", ")}]`,
|
|
11593
|
-
` Content pinned: ${stats.totalPinned} (${stats.pinnedFromOthers} from others)`,
|
|
11594
|
-
` Tracked CIDs: ${stats.trackedCids}`,
|
|
11595
|
-
` Registered services: ${registeredServices.length}`,
|
|
11596
|
-
` Wallet: ${walletInfo}`,
|
|
11597
|
-
` x402: ${clientInstance.x402?.isEnabled ? "enabled" : "disabled"}`
|
|
11598
|
-
].join("\n");
|
|
11599
|
-
}
|
|
11600
|
-
async doJoinRoom(args) {
|
|
11601
|
-
if (!clientInstance)
|
|
11602
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11603
|
-
const roomId = args.room_id;
|
|
11604
|
-
if (!roomId)
|
|
11605
|
-
throw new Error("room_id is required");
|
|
11606
|
-
if (activeRooms.has(roomId)) {
|
|
11607
|
-
return `Already in room: ${roomId}`;
|
|
11608
|
-
}
|
|
11609
|
-
const room = await clientInstance.joinRoom(roomId);
|
|
11610
|
-
activeRooms.set(roomId, room);
|
|
11611
|
-
room.on("message", (msg) => {
|
|
11612
|
-
const msgDir = join28(this.nexusDir, "messages", roomId);
|
|
11613
|
-
mkdir8(msgDir, { recursive: true }).then(() => {
|
|
11614
|
-
const filename = `${msg.id || Date.now()}.json`;
|
|
11615
|
-
writeFile12(join28(msgDir, filename), JSON.stringify(msg, null, 2)).catch(() => {
|
|
11605
|
+
for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
|
|
11606
|
+
const p = join28(this.nexusDir, f);
|
|
11607
|
+
if (existsSync21(p))
|
|
11608
|
+
await unlink(p).catch(() => {
|
|
11616
11609
|
});
|
|
11617
|
-
|
|
11618
|
-
|
|
11619
|
-
});
|
|
11620
|
-
return `Joined room: ${roomId}
|
|
11621
|
-
Listening for messages. Use send_message to communicate.`;
|
|
11610
|
+
}
|
|
11611
|
+
return `Disconnected from nexus network (killed pid ${pid}).`;
|
|
11622
11612
|
}
|
|
11623
|
-
async
|
|
11624
|
-
const
|
|
11625
|
-
if (!
|
|
11626
|
-
|
|
11627
|
-
const
|
|
11628
|
-
if (!
|
|
11629
|
-
return `
|
|
11630
|
-
|
|
11631
|
-
|
|
11632
|
-
|
|
11613
|
+
async doStatus() {
|
|
11614
|
+
const pid = this.getDaemonPid();
|
|
11615
|
+
if (!pid)
|
|
11616
|
+
return "Nexus daemon not running. Use action 'connect' to start.";
|
|
11617
|
+
const statusFile = join28(this.nexusDir, "status.json");
|
|
11618
|
+
if (!existsSync21(statusFile))
|
|
11619
|
+
return `Daemon running (pid: ${pid}) but no status yet.`;
|
|
11620
|
+
try {
|
|
11621
|
+
const status = JSON.parse(await readFile13(statusFile, "utf8"));
|
|
11622
|
+
const lines = [
|
|
11623
|
+
`Nexus Status`,
|
|
11624
|
+
` Connected: ${status.connected}`,
|
|
11625
|
+
` Peer ID: ${status.peerId || "n/a"}`,
|
|
11626
|
+
` Agent: ${status.agentName} (${status.agentType})`,
|
|
11627
|
+
` Daemon PID: ${status.pid}`,
|
|
11628
|
+
` Rooms: ${status.rooms?.length || 0} [${(status.rooms || []).join(", ")}]`
|
|
11629
|
+
];
|
|
11630
|
+
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11631
|
+
if (existsSync21(walletPath)) {
|
|
11632
|
+
try {
|
|
11633
|
+
const w = JSON.parse(await readFile13(walletPath, "utf8"));
|
|
11634
|
+
lines.push(` Wallet: ${w.address}`);
|
|
11635
|
+
} catch {
|
|
11636
|
+
lines.push(` Wallet: corrupt`);
|
|
11637
|
+
}
|
|
11638
|
+
} else {
|
|
11639
|
+
lines.push(` Wallet: not configured`);
|
|
11640
|
+
}
|
|
11641
|
+
const inboxDir = join28(this.nexusDir, "inbox");
|
|
11642
|
+
if (existsSync21(inboxDir)) {
|
|
11643
|
+
try {
|
|
11644
|
+
const roomDirs = await readdir3(inboxDir);
|
|
11645
|
+
let totalMsgs = 0;
|
|
11646
|
+
for (const rd of roomDirs) {
|
|
11647
|
+
try {
|
|
11648
|
+
totalMsgs += (await readdir3(join28(inboxDir, rd))).length;
|
|
11649
|
+
} catch {
|
|
11650
|
+
}
|
|
11651
|
+
}
|
|
11652
|
+
lines.push(` Inbox: ${totalMsgs} message(s) across ${roomDirs.length} room(s)`);
|
|
11653
|
+
} catch {
|
|
11654
|
+
}
|
|
11655
|
+
}
|
|
11656
|
+
if (status.error)
|
|
11657
|
+
lines.push(` Error: ${status.error}`);
|
|
11658
|
+
return lines.join("\n");
|
|
11659
|
+
} catch {
|
|
11660
|
+
return `Daemon running (pid: ${pid}) but status file unreadable.`;
|
|
11661
|
+
}
|
|
11633
11662
|
}
|
|
11634
11663
|
async doSendMessage(args) {
|
|
11635
|
-
if (!clientInstance)
|
|
11636
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11637
|
-
const roomId = args.room_id;
|
|
11638
11664
|
const message = args.message;
|
|
11639
|
-
if (!roomId)
|
|
11640
|
-
throw new Error("room_id is required");
|
|
11641
11665
|
if (!message)
|
|
11642
11666
|
throw new Error("message is required");
|
|
11667
|
+
if (!args.room_id)
|
|
11668
|
+
throw new Error("room_id is required");
|
|
11643
11669
|
if (containsKeyMaterial(message)) {
|
|
11644
11670
|
return [
|
|
11645
11671
|
"BLOCKED: Message contains potential key material or secrets.",
|
|
11646
|
-
"
|
|
11647
|
-
"
|
|
11648
|
-
"Please remove the sensitive content and try again."
|
|
11672
|
+
"Messages containing private keys or sensitive cryptographic material",
|
|
11673
|
+
"cannot be sent over the network. Remove the sensitive content and retry."
|
|
11649
11674
|
].join("\n");
|
|
11650
11675
|
}
|
|
11651
|
-
|
|
11652
|
-
if (!room)
|
|
11653
|
-
throw new Error(`Not in room: ${roomId}. Join it first.`);
|
|
11654
|
-
const msgId = await room.send(message, { format: "text/plain" });
|
|
11655
|
-
return `Message sent to ${roomId} (id: ${msgId})`;
|
|
11656
|
-
}
|
|
11657
|
-
async doListRooms() {
|
|
11658
|
-
if (!clientInstance)
|
|
11659
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11660
|
-
try {
|
|
11661
|
-
const rooms = await clientInstance.listRooms();
|
|
11662
|
-
if (!rooms || rooms.length === 0) {
|
|
11663
|
-
return "No rooms found on the network. Create one by joining a new room ID.";
|
|
11664
|
-
}
|
|
11665
|
-
const lines = rooms.map((r) => ` ${r.roomId} \u2014 ${r.name || "(unnamed)"} [${r.memberCount || 0} members, ${r.type}]`);
|
|
11666
|
-
return `Available rooms:
|
|
11667
|
-
${lines.join("\n")}`;
|
|
11668
|
-
} catch {
|
|
11669
|
-
return "Could not list rooms (DHT may still be bootstrapping). Try again in a moment.";
|
|
11670
|
-
}
|
|
11676
|
+
return this.sendDaemonCmd("send_message", args);
|
|
11671
11677
|
}
|
|
11672
|
-
async
|
|
11673
|
-
|
|
11674
|
-
|
|
11675
|
-
|
|
11676
|
-
const
|
|
11677
|
-
if (!
|
|
11678
|
-
return
|
|
11679
|
-
const
|
|
11680
|
-
if (
|
|
11681
|
-
return
|
|
11682
|
-
}
|
|
11683
|
-
const
|
|
11684
|
-
for (const peerId of peers.slice(0, 20)) {
|
|
11685
|
-
const pid = peerId.toString ? peerId.toString() : String(peerId);
|
|
11678
|
+
async doReadMessages(args) {
|
|
11679
|
+
const roomId = args.room_id;
|
|
11680
|
+
const inboxDir = join28(this.nexusDir, "inbox");
|
|
11681
|
+
if (roomId) {
|
|
11682
|
+
const roomInbox = join28(inboxDir, roomId);
|
|
11683
|
+
if (!existsSync21(roomInbox))
|
|
11684
|
+
return `No messages in room: ${roomId}`;
|
|
11685
|
+
const files = (await readdir3(roomInbox)).sort().slice(-20);
|
|
11686
|
+
if (files.length === 0)
|
|
11687
|
+
return `No messages in room: ${roomId}`;
|
|
11688
|
+
const messages = [`Messages in ${roomId} (last ${files.length}):`];
|
|
11689
|
+
for (const f of files) {
|
|
11686
11690
|
try {
|
|
11687
|
-
const
|
|
11688
|
-
|
|
11689
|
-
|
|
11690
|
-
} else {
|
|
11691
|
-
lines.push(` ${pid.slice(0, 16)}... \u2014 (no profile)`);
|
|
11692
|
-
}
|
|
11691
|
+
const msg = JSON.parse(await readFile13(join28(roomInbox, f), "utf8"));
|
|
11692
|
+
const sender = (msg.sender || "unknown").slice(0, 12);
|
|
11693
|
+
messages.push(` [${new Date(msg.timestamp).toLocaleTimeString()}] ${sender}...: ${msg.content}`);
|
|
11693
11694
|
} catch {
|
|
11694
|
-
lines.push(` ${pid.slice(0, 16)}... \u2014 (lookup failed)`);
|
|
11695
11695
|
}
|
|
11696
11696
|
}
|
|
11697
|
-
|
|
11698
|
-
lines.push(` ... and ${peers.length - 20} more`);
|
|
11699
|
-
}
|
|
11700
|
-
return lines.join("\n");
|
|
11701
|
-
} catch (err) {
|
|
11702
|
-
return `Peer discovery error: ${err.message}`;
|
|
11697
|
+
return messages.join("\n");
|
|
11703
11698
|
}
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
const profile = await clientInstance.findAgent(peerId);
|
|
11712
|
-
if (!profile) {
|
|
11713
|
-
return `Agent not found: ${peerId}`;
|
|
11714
|
-
}
|
|
11715
|
-
const caps = profile.capabilities?.map((c3) => ` - ${c3.name}: ${c3.description} [${c3.pricing}]`) || [];
|
|
11716
|
-
return [
|
|
11717
|
-
`Agent Profile:`,
|
|
11718
|
-
` Peer ID: ${profile.peerId}`,
|
|
11719
|
-
` Name: ${profile.name}`,
|
|
11720
|
-
` Type: ${profile.type}`,
|
|
11721
|
-
` Role: ${profile.role}`,
|
|
11722
|
-
` Capabilities (${caps.length}):`,
|
|
11723
|
-
...caps,
|
|
11724
|
-
` Created: ${new Date(profile.createdAt).toISOString()}`,
|
|
11725
|
-
` Updated: ${new Date(profile.updatedAt).toISOString()}`
|
|
11726
|
-
].join("\n");
|
|
11727
|
-
}
|
|
11728
|
-
async doRegisterService(args) {
|
|
11729
|
-
if (!clientInstance)
|
|
11730
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11731
|
-
const serviceId = args.service_id || `svc-${randomBytes6(4).toString("hex")}`;
|
|
11732
|
-
const name = args.service_name || "inference";
|
|
11733
|
-
const description = args.service_description || "AI inference service";
|
|
11734
|
-
const priceAmount = args.price_amount || "0.001";
|
|
11735
|
-
const rateLimit = args.rate_limit || 60;
|
|
11736
|
-
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11737
|
-
let walletAddress = "";
|
|
11738
|
-
if (existsSync21(walletPath)) {
|
|
11699
|
+
if (!existsSync21(inboxDir))
|
|
11700
|
+
return "No messages received yet.";
|
|
11701
|
+
const roomDirs = await readdir3(inboxDir);
|
|
11702
|
+
if (roomDirs.length === 0)
|
|
11703
|
+
return "No messages received yet.";
|
|
11704
|
+
const lines = ["Inbox:"];
|
|
11705
|
+
for (const rd of roomDirs) {
|
|
11739
11706
|
try {
|
|
11740
|
-
const
|
|
11741
|
-
|
|
11707
|
+
const count = (await readdir3(join28(inboxDir, rd))).length;
|
|
11708
|
+
lines.push(` ${rd}: ${count} message(s)`);
|
|
11742
11709
|
} catch {
|
|
11743
11710
|
}
|
|
11744
11711
|
}
|
|
11745
|
-
|
|
11746
|
-
return "Cannot register paid service without a wallet. Use wallet_create first.";
|
|
11747
|
-
}
|
|
11748
|
-
const offering = {
|
|
11749
|
-
serviceId,
|
|
11750
|
-
name,
|
|
11751
|
-
description,
|
|
11752
|
-
price: {
|
|
11753
|
-
amount: priceAmount,
|
|
11754
|
-
currency: "USDC",
|
|
11755
|
-
network: "base",
|
|
11756
|
-
recipient: walletAddress,
|
|
11757
|
-
description: `Payment for ${name}`,
|
|
11758
|
-
expiresAt: Date.now() + 36e5,
|
|
11759
|
-
// 1 hour
|
|
11760
|
-
requestId: `req-${randomBytes6(8).toString("hex")}`
|
|
11761
|
-
},
|
|
11762
|
-
rateLimit,
|
|
11763
|
-
sensitive: false
|
|
11764
|
-
};
|
|
11765
|
-
clientInstance.x402.registerService(offering);
|
|
11766
|
-
registeredServices.push(offering);
|
|
11767
|
-
await this.ensureDir();
|
|
11768
|
-
await writeFile12(join28(this.nexusDir, "services.json"), JSON.stringify(registeredServices, null, 2));
|
|
11769
|
-
return [
|
|
11770
|
-
`Service registered:`,
|
|
11771
|
-
` ID: ${serviceId}`,
|
|
11772
|
-
` Name: ${name}`,
|
|
11773
|
-
` Description: ${description}`,
|
|
11774
|
-
` Price: ${priceAmount} USDC per request`,
|
|
11775
|
-
` Rate limit: ${rateLimit} req/hour`,
|
|
11776
|
-
` Recipient wallet: ${walletAddress}`
|
|
11777
|
-
].join("\n");
|
|
11778
|
-
}
|
|
11779
|
-
async doListServices() {
|
|
11780
|
-
const services = clientInstance?.x402?.getServices() || registeredServices;
|
|
11781
|
-
if (services.length === 0) {
|
|
11782
|
-
return "No services registered. Use register_service to offer inference.";
|
|
11783
|
-
}
|
|
11784
|
-
const lines = services.map((s) => ` ${s.serviceId} \u2014 ${s.name}: ${s.description} [${s.price?.amount || "?"} ${s.price?.currency || "USDC"}, ${s.rateLimit} req/hr]`);
|
|
11785
|
-
return `Registered services (${services.length}):
|
|
11786
|
-
${lines.join("\n")}`;
|
|
11712
|
+
return lines.join("\n");
|
|
11787
11713
|
}
|
|
11788
11714
|
async doWalletStatus() {
|
|
11789
11715
|
await this.ensureDir();
|
|
11790
11716
|
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11791
11717
|
if (!existsSync21(walletPath)) {
|
|
11792
|
-
return
|
|
11793
|
-
"No wallet configured.",
|
|
11794
|
-
"Use wallet_create to generate a new wallet for x402 micropayments.",
|
|
11795
|
-
"Or provide your own wallet address with wallet_create + wallet_address parameter."
|
|
11796
|
-
].join("\n");
|
|
11718
|
+
return "No wallet configured. Use wallet_create to set one up.";
|
|
11797
11719
|
}
|
|
11798
11720
|
try {
|
|
11799
|
-
const
|
|
11721
|
+
const w = JSON.parse(await readFile13(walletPath, "utf8"));
|
|
11800
11722
|
return [
|
|
11801
11723
|
`Wallet Status:`,
|
|
11802
|
-
` Address: ${
|
|
11803
|
-
` Created: ${
|
|
11724
|
+
` Address: ${w.address}`,
|
|
11725
|
+
` Created: ${w.createdAt}`,
|
|
11804
11726
|
` Encryption: AES-256-GCM + scrypt`,
|
|
11805
|
-
`
|
|
11806
|
-
``,
|
|
11807
|
-
` NOTE: Private key is encrypted and NEVER accessible to the agent.`,
|
|
11808
|
-
` Only the public address is visible. Payment operations use the`,
|
|
11809
|
-
` encrypted key internally without exposing it.`
|
|
11727
|
+
` NOTE: Private key is encrypted and NEVER accessible to the agent.`
|
|
11810
11728
|
].join("\n");
|
|
11811
11729
|
} catch {
|
|
11812
|
-
return "Wallet file exists but could not be read.
|
|
11730
|
+
return "Wallet file exists but could not be read.";
|
|
11813
11731
|
}
|
|
11814
11732
|
}
|
|
11815
11733
|
async doWalletCreate(args) {
|
|
11816
11734
|
await this.ensureDir();
|
|
11817
11735
|
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11818
|
-
if (existsSync21(walletPath))
|
|
11819
|
-
return "Wallet already exists.
|
|
11820
|
-
}
|
|
11736
|
+
if (existsSync21(walletPath))
|
|
11737
|
+
return "Wallet already exists.";
|
|
11821
11738
|
const userAddress = args.wallet_address;
|
|
11822
11739
|
if (userAddress) {
|
|
11823
11740
|
if (!/^0x[0-9a-fA-F]{40}$/.test(userAddress)) {
|
|
11824
|
-
return "Invalid
|
|
11741
|
+
return "Invalid address format. Expected 0x + 40 hex chars.";
|
|
11825
11742
|
}
|
|
11826
|
-
const
|
|
11743
|
+
const w2 = {
|
|
11827
11744
|
version: 1,
|
|
11828
11745
|
address: userAddress,
|
|
11829
11746
|
encryptedKey: "",
|
|
11830
|
-
// user-managed key
|
|
11831
11747
|
iv: "",
|
|
11832
11748
|
authTag: "",
|
|
11833
11749
|
salt: "",
|
|
11834
11750
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11835
11751
|
};
|
|
11836
|
-
await writeFile12(walletPath, JSON.stringify(
|
|
11752
|
+
await writeFile12(walletPath, JSON.stringify(w2, null, 2));
|
|
11837
11753
|
await chmod(walletPath, 384);
|
|
11838
|
-
return
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
const
|
|
11850
|
-
const privateKeyHex = privateKeyBytes.toString("hex");
|
|
11851
|
-
let address;
|
|
11852
|
-
try {
|
|
11853
|
-
const { createHash: createHash4 } = await import("node:crypto");
|
|
11854
|
-
const pubHash = createHash4("sha256").update(privateKeyBytes).digest("hex");
|
|
11855
|
-
address = "0x" + pubHash.slice(0, 40);
|
|
11856
|
-
} catch {
|
|
11857
|
-
address = "0x" + randomBytes6(20).toString("hex");
|
|
11858
|
-
}
|
|
11859
|
-
const machineId = `${__require("node:os").hostname()}:${__require("node:os").userInfo().username}:nexus-wallet`;
|
|
11860
|
-
const { encrypted, iv, authTag, salt } = encryptKey(privateKeyHex, machineId);
|
|
11861
|
-
privateKeyBytes.fill(0);
|
|
11862
|
-
const walletData = {
|
|
11754
|
+
return `Wallet configured: ${userAddress} (user-managed)`;
|
|
11755
|
+
}
|
|
11756
|
+
const privKey = randomBytes6(32);
|
|
11757
|
+
const address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
|
|
11758
|
+
const salt = randomBytes6(32);
|
|
11759
|
+
const key = scryptSync(`${__require("node:os").hostname()}:${__require("node:os").userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
|
|
11760
|
+
const iv = randomBytes6(16);
|
|
11761
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
11762
|
+
let enc = cipher.update(privKey.toString("hex"), "utf8", "hex");
|
|
11763
|
+
enc += cipher.final("hex");
|
|
11764
|
+
privKey.fill(0);
|
|
11765
|
+
const w = {
|
|
11863
11766
|
version: 1,
|
|
11864
11767
|
address,
|
|
11865
|
-
encryptedKey:
|
|
11866
|
-
iv,
|
|
11867
|
-
authTag,
|
|
11868
|
-
salt,
|
|
11768
|
+
encryptedKey: enc,
|
|
11769
|
+
iv: iv.toString("hex"),
|
|
11770
|
+
authTag: cipher.getAuthTag().toString("hex"),
|
|
11771
|
+
salt: salt.toString("hex"),
|
|
11869
11772
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11870
11773
|
};
|
|
11871
|
-
await writeFile12(walletPath, JSON.stringify(
|
|
11774
|
+
await writeFile12(walletPath, JSON.stringify(w, null, 2));
|
|
11872
11775
|
await chmod(walletPath, 384);
|
|
11873
11776
|
return [
|
|
11874
|
-
`Wallet created
|
|
11875
|
-
`
|
|
11876
|
-
`
|
|
11877
|
-
` Key file: ${walletPath} (permissions: 0600)`,
|
|
11878
|
-
``,
|
|
11879
|
-
` SECURITY NOTES:`,
|
|
11880
|
-
` - Private key is encrypted at rest and NEVER visible to the agent`,
|
|
11881
|
-
` - Key material is cleared from memory after encryption`,
|
|
11882
|
-
` - The encryption password is derived from machine identity`,
|
|
11883
|
-
` - Only payment operations can use the key (internally)`,
|
|
11884
|
-
` - The key CANNOT be extracted via tool calls or messages`
|
|
11777
|
+
`Wallet created: ${address}`,
|
|
11778
|
+
` Encrypted with AES-256-GCM (key NEVER visible to agent)`,
|
|
11779
|
+
` File: ${walletPath} (0600)`
|
|
11885
11780
|
].join("\n");
|
|
11886
11781
|
}
|
|
11887
11782
|
async doInferenceProof() {
|
|
11888
|
-
|
|
11889
|
-
|
|
11783
|
+
try {
|
|
11784
|
+
const psRaw = execSync20("ollama ps 2>/dev/null", { timeout: 1e4, encoding: "utf8" });
|
|
11785
|
+
const lines = psRaw.trim().split("\n").filter((l) => l.trim());
|
|
11786
|
+
if (lines.length < 2)
|
|
11787
|
+
return "No model loaded. Run 'ollama ps' to check.";
|
|
11788
|
+
const parts = lines[1].split(/\s+/);
|
|
11789
|
+
const modelName = parts[0] || "unknown";
|
|
11790
|
+
let gpuName = "none", vramMb = 0;
|
|
11791
|
+
try {
|
|
11792
|
+
const smi = execSync20("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null", {
|
|
11793
|
+
timeout: 5e3,
|
|
11794
|
+
encoding: "utf8"
|
|
11795
|
+
});
|
|
11796
|
+
const gp = smi.trim().split(",");
|
|
11797
|
+
gpuName = gp[0]?.trim() || "unknown";
|
|
11798
|
+
vramMb = parseInt(gp[1]?.trim() || "0", 10);
|
|
11799
|
+
} catch {
|
|
11800
|
+
try {
|
|
11801
|
+
execSync20("rocm-smi 2>/dev/null", { timeout: 5e3 });
|
|
11802
|
+
gpuName = "AMD GPU";
|
|
11803
|
+
} catch {
|
|
11804
|
+
}
|
|
11805
|
+
}
|
|
11806
|
+
const nonce = randomBytes6(16).toString("hex");
|
|
11807
|
+
const hash = createHash("sha256").update(`${modelName}:${nonce}:${Date.now()}`).digest("hex");
|
|
11808
|
+
const bar = (s) => "\u2588".repeat(Math.round(s / 5)) + "\u2591".repeat(20 - Math.round(s / 5));
|
|
11809
|
+
const mem = vramMb > 24e3 ? 95 : vramMb > 16e3 ? 80 : vramMb > 8e3 ? 60 : vramMb > 0 ? 40 : 20;
|
|
11810
|
+
await this.ensureDir();
|
|
11811
|
+
await writeFile12(join28(this.nexusDir, "inference-proof.json"), JSON.stringify({
|
|
11812
|
+
modelName,
|
|
11813
|
+
gpuName,
|
|
11814
|
+
vramMb,
|
|
11815
|
+
hash,
|
|
11816
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
11817
|
+
}, null, 2));
|
|
11890
11818
|
return [
|
|
11891
|
-
|
|
11892
|
-
|
|
11819
|
+
`Inference Capability Proof`,
|
|
11820
|
+
` Model: ${modelName} (${parts[1] || "?"})`,
|
|
11821
|
+
` GPU: ${gpuName} (${vramMb} MB)`,
|
|
11822
|
+
` Memory [${bar(mem)}] ${mem}%`,
|
|
11823
|
+
` Hash: ${hash.slice(0, 16)}...`
|
|
11893
11824
|
].join("\n");
|
|
11825
|
+
} catch {
|
|
11826
|
+
return "Could not generate proof. Ensure Ollama is running.";
|
|
11894
11827
|
}
|
|
11895
|
-
await this.ensureDir();
|
|
11896
|
-
const proofPath = join28(this.nexusDir, "inference-proof.json");
|
|
11897
|
-
await writeFile12(proofPath, JSON.stringify(proof, null, 2));
|
|
11898
|
-
const memScore = proof.vramMb > 24e3 ? 95 : proof.vramMb > 16e3 ? 80 : proof.vramMb > 8e3 ? 60 : proof.vramMb > 0 ? 40 : 20;
|
|
11899
|
-
const speedScore = proof.tokensPerSecond > 50 ? 95 : proof.tokensPerSecond > 30 ? 80 : proof.tokensPerSecond > 15 ? 60 : proof.tokensPerSecond > 5 ? 40 : 20;
|
|
11900
|
-
const overall = Math.round((memScore + speedScore) / 2);
|
|
11901
|
-
const bar = (score) => {
|
|
11902
|
-
const filled = Math.round(score / 5);
|
|
11903
|
-
const empty = 20 - filled;
|
|
11904
|
-
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
11905
|
-
};
|
|
11906
|
-
return [
|
|
11907
|
-
`Inference Capability Proof`,
|
|
11908
|
-
`\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
|
|
11909
|
-
` Model: ${proof.modelName} (${proof.modelSize})`,
|
|
11910
|
-
` GPU: ${proof.gpuName} (${proof.vramMb} MB VRAM)`,
|
|
11911
|
-
` Speed: ${proof.tokensPerSecond} tok/s`,
|
|
11912
|
-
` Context: ${proof.contextLength} tokens`,
|
|
11913
|
-
``,
|
|
11914
|
-
` Memory [${bar(memScore)}] ${memScore}%`,
|
|
11915
|
-
` Speed [${bar(speedScore)}] ${speedScore}%`,
|
|
11916
|
-
` Overall [${bar(overall)}] ${overall}%`,
|
|
11917
|
-
``,
|
|
11918
|
-
` Benchmark hash: ${proof.benchmarkHash.slice(0, 16)}...`,
|
|
11919
|
-
` Timestamp: ${proof.timestamp}`,
|
|
11920
|
-
` Proof saved: ${proofPath}`,
|
|
11921
|
-
``,
|
|
11922
|
-
` Anti-spoofing: SHA-256 hash of model+timing+nonce`,
|
|
11923
|
-
` Verification: peers can request live re-benchmark`
|
|
11924
|
-
].join("\n");
|
|
11925
|
-
}
|
|
11926
|
-
async doStoreContent(args) {
|
|
11927
|
-
if (!clientInstance)
|
|
11928
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11929
|
-
const content = args.content;
|
|
11930
|
-
if (!content)
|
|
11931
|
-
throw new Error("content is required");
|
|
11932
|
-
if (containsKeyMaterial(content)) {
|
|
11933
|
-
return "BLOCKED: Content contains potential key material. Cannot store secrets on IPFS.";
|
|
11934
|
-
}
|
|
11935
|
-
const cid = await clientInstance.store(content);
|
|
11936
|
-
return `Content stored on IPFS.
|
|
11937
|
-
CID: ${cid}
|
|
11938
|
-
Retrieve with: retrieve_content + cid="${cid}"`;
|
|
11939
|
-
}
|
|
11940
|
-
async doRetrieveContent(args) {
|
|
11941
|
-
if (!clientInstance)
|
|
11942
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11943
|
-
const cid = args.cid;
|
|
11944
|
-
if (!cid)
|
|
11945
|
-
throw new Error("cid is required");
|
|
11946
|
-
const data = await clientInstance.retrieve(cid);
|
|
11947
|
-
if (typeof data === "string")
|
|
11948
|
-
return data;
|
|
11949
|
-
if (typeof data === "object")
|
|
11950
|
-
return JSON.stringify(data, null, 2);
|
|
11951
|
-
return String(data);
|
|
11952
11828
|
}
|
|
11953
11829
|
};
|
|
11954
11830
|
}
|
|
@@ -13208,7 +13084,7 @@ var init_code_retriever = __esm({
|
|
|
13208
13084
|
// packages/retrieval/dist/lexicalSearch.js
|
|
13209
13085
|
import { execFile as execFile5 } from "node:child_process";
|
|
13210
13086
|
import { promisify as promisify4 } from "node:util";
|
|
13211
|
-
import { readFile as readFile14, readdir as
|
|
13087
|
+
import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "node:fs/promises";
|
|
13212
13088
|
import { join as join29, extname as extname7 } from "node:path";
|
|
13213
13089
|
async function searchByPath(pathPattern, options) {
|
|
13214
13090
|
const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
|
|
@@ -13342,7 +13218,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
|
|
|
13342
13218
|
async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
13343
13219
|
let entries;
|
|
13344
13220
|
try {
|
|
13345
|
-
entries = await
|
|
13221
|
+
entries = await readdir4(dir, { withFileTypes: true, encoding: "utf-8" });
|
|
13346
13222
|
} catch {
|
|
13347
13223
|
return;
|
|
13348
13224
|
}
|
|
@@ -17763,7 +17639,7 @@ __export(listen_exports, {
|
|
|
17763
17639
|
isVideoPath: () => isVideoPath,
|
|
17764
17640
|
waitForTranscribeCli: () => waitForTranscribeCli
|
|
17765
17641
|
});
|
|
17766
|
-
import { spawn as
|
|
17642
|
+
import { spawn as spawn11, execSync as execSync21 } from "node:child_process";
|
|
17767
17643
|
import { existsSync as existsSync22, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6 } from "node:fs";
|
|
17768
17644
|
import { join as join31, dirname as dirname10 } from "node:path";
|
|
17769
17645
|
import { homedir as homedir8 } from "node:os";
|
|
@@ -17973,7 +17849,7 @@ var init_listen = __esm({
|
|
|
17973
17849
|
const timeout = setTimeout(() => {
|
|
17974
17850
|
reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
|
|
17975
17851
|
}, 3e5);
|
|
17976
|
-
this.process =
|
|
17852
|
+
this.process = spawn11("python3", [
|
|
17977
17853
|
this.scriptPath,
|
|
17978
17854
|
"--model",
|
|
17979
17855
|
this.model,
|
|
@@ -18255,7 +18131,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
|
|
|
18255
18131
|
return `Failed to start live transcription: ${msg}${tcHint}`;
|
|
18256
18132
|
}
|
|
18257
18133
|
}
|
|
18258
|
-
this.micProcess =
|
|
18134
|
+
this.micProcess = spawn11(micCmd.cmd, micCmd.args, {
|
|
18259
18135
|
stdio: ["pipe", "pipe", "pipe"],
|
|
18260
18136
|
env: { ...process.env }
|
|
18261
18137
|
});
|
|
@@ -20674,7 +20550,7 @@ var require_websocket = __commonJS({
|
|
|
20674
20550
|
var http = __require("http");
|
|
20675
20551
|
var net = __require("net");
|
|
20676
20552
|
var tls = __require("tls");
|
|
20677
|
-
var { randomBytes: randomBytes10, createHash:
|
|
20553
|
+
var { randomBytes: randomBytes10, createHash: createHash5 } = __require("crypto");
|
|
20678
20554
|
var { Duplex, Readable } = __require("stream");
|
|
20679
20555
|
var { URL: URL3 } = __require("url");
|
|
20680
20556
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -21334,7 +21210,7 @@ var require_websocket = __commonJS({
|
|
|
21334
21210
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
21335
21211
|
return;
|
|
21336
21212
|
}
|
|
21337
|
-
const digest =
|
|
21213
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
21338
21214
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
21339
21215
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
21340
21216
|
return;
|
|
@@ -21701,7 +21577,7 @@ var require_websocket_server = __commonJS({
|
|
|
21701
21577
|
var EventEmitter7 = __require("events");
|
|
21702
21578
|
var http = __require("http");
|
|
21703
21579
|
var { Duplex } = __require("stream");
|
|
21704
|
-
var { createHash:
|
|
21580
|
+
var { createHash: createHash5 } = __require("crypto");
|
|
21705
21581
|
var extension = require_extension();
|
|
21706
21582
|
var PerMessageDeflate = require_permessage_deflate();
|
|
21707
21583
|
var subprotocol = require_subprotocol();
|
|
@@ -22002,7 +21878,7 @@ var require_websocket_server = __commonJS({
|
|
|
22002
21878
|
);
|
|
22003
21879
|
}
|
|
22004
21880
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
22005
|
-
const digest =
|
|
21881
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
22006
21882
|
const headers = [
|
|
22007
21883
|
"HTTP/1.1 101 Switching Protocols",
|
|
22008
21884
|
"Upgrade: websocket",
|
|
@@ -22991,7 +22867,7 @@ var init_render = __esm({
|
|
|
22991
22867
|
|
|
22992
22868
|
// packages/cli/dist/tui/voice-session.js
|
|
22993
22869
|
import { createServer } from "node:http";
|
|
22994
|
-
import { spawn as
|
|
22870
|
+
import { spawn as spawn12, execSync as execSync22 } from "node:child_process";
|
|
22995
22871
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
22996
22872
|
function generateFrontendHTML() {
|
|
22997
22873
|
return `<!DOCTYPE html>
|
|
@@ -23645,7 +23521,7 @@ var init_voice_session = __esm({
|
|
|
23645
23521
|
const timeout = setTimeout(() => {
|
|
23646
23522
|
reject(new Error("Cloudflared tunnel start timeout (30s)"));
|
|
23647
23523
|
}, 3e4);
|
|
23648
|
-
this.cloudflaredProcess =
|
|
23524
|
+
this.cloudflaredProcess = spawn12("cloudflared", [
|
|
23649
23525
|
"tunnel",
|
|
23650
23526
|
"--url",
|
|
23651
23527
|
`http://127.0.0.1:${port}`
|
|
@@ -23719,7 +23595,7 @@ var init_voice_session = __esm({
|
|
|
23719
23595
|
|
|
23720
23596
|
// packages/cli/dist/tui/expose.js
|
|
23721
23597
|
import { createServer as createServer2, request as httpRequest } from "node:http";
|
|
23722
|
-
import { spawn as
|
|
23598
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
23723
23599
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
23724
23600
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
23725
23601
|
import { URL as URL2 } from "node:url";
|
|
@@ -23895,7 +23771,7 @@ var init_expose = __esm({
|
|
|
23895
23771
|
const timeout = setTimeout(() => {
|
|
23896
23772
|
reject(new Error("Cloudflared tunnel start timeout (30s)"));
|
|
23897
23773
|
}, 3e4);
|
|
23898
|
-
this.cloudflaredProcess =
|
|
23774
|
+
this.cloudflaredProcess = spawn13("cloudflared", [
|
|
23899
23775
|
"tunnel",
|
|
23900
23776
|
"--url",
|
|
23901
23777
|
`http://127.0.0.1:${port}`
|
|
@@ -23997,10 +23873,10 @@ var init_types = __esm({
|
|
|
23997
23873
|
});
|
|
23998
23874
|
|
|
23999
23875
|
// packages/cli/dist/tui/p2p/secret-vault.js
|
|
24000
|
-
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8, scryptSync as scryptSync2, createHash } from "node:crypto";
|
|
23876
|
+
import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
|
|
24001
23877
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, existsSync as existsSync23, mkdirSync as mkdirSync7 } from "node:fs";
|
|
24002
23878
|
import { join as join32, dirname as dirname11 } from "node:path";
|
|
24003
|
-
var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN,
|
|
23879
|
+
var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
|
|
24004
23880
|
var init_secret_vault = __esm({
|
|
24005
23881
|
"packages/cli/dist/tui/p2p/secret-vault.js"() {
|
|
24006
23882
|
"use strict";
|
|
@@ -24010,7 +23886,7 @@ var init_secret_vault = __esm({
|
|
|
24010
23886
|
CIPHER_ALGO = "aes-256-gcm";
|
|
24011
23887
|
SALT_LEN = 16;
|
|
24012
23888
|
IV_LEN = 12;
|
|
24013
|
-
|
|
23889
|
+
KEY_LEN = 32;
|
|
24014
23890
|
SecretVault = class {
|
|
24015
23891
|
storePath;
|
|
24016
23892
|
secrets = /* @__PURE__ */ new Map();
|
|
@@ -24204,7 +24080,7 @@ var init_secret_vault = __esm({
|
|
|
24204
24080
|
createdAt: s.createdAt
|
|
24205
24081
|
})));
|
|
24206
24082
|
const salt = randomBytes8(SALT_LEN);
|
|
24207
|
-
const key = scryptSync2(passphrase, salt,
|
|
24083
|
+
const key = scryptSync2(passphrase, salt, KEY_LEN);
|
|
24208
24084
|
const iv = randomBytes8(IV_LEN);
|
|
24209
24085
|
const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
|
|
24210
24086
|
const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
|
|
@@ -24230,7 +24106,7 @@ var init_secret_vault = __esm({
|
|
|
24230
24106
|
const iv = blob.subarray(SALT_LEN, SALT_LEN + IV_LEN);
|
|
24231
24107
|
const tag = blob.subarray(SALT_LEN + IV_LEN, SALT_LEN + IV_LEN + 16);
|
|
24232
24108
|
const encrypted = blob.subarray(SALT_LEN + IV_LEN + 16);
|
|
24233
|
-
const key = scryptSync2(passphrase, salt,
|
|
24109
|
+
const key = scryptSync2(passphrase, salt, KEY_LEN);
|
|
24234
24110
|
const decipher = createDecipheriv2(CIPHER_ALGO, key, iv);
|
|
24235
24111
|
decipher.setAuthTag(tag);
|
|
24236
24112
|
let data;
|
|
@@ -24248,7 +24124,7 @@ var init_secret_vault = __esm({
|
|
|
24248
24124
|
/** Generate a deterministic fingerprint of vault contents (for sync verification) */
|
|
24249
24125
|
fingerprint() {
|
|
24250
24126
|
const names = Array.from(this.secrets.keys()).sort();
|
|
24251
|
-
const hash =
|
|
24127
|
+
const hash = createHash2("sha256");
|
|
24252
24128
|
for (const name of names) {
|
|
24253
24129
|
hash.update(name + ":");
|
|
24254
24130
|
hash.update(this.secrets.get(name).value);
|
|
@@ -24263,7 +24139,7 @@ var init_secret_vault = __esm({
|
|
|
24263
24139
|
// packages/cli/dist/tui/p2p/peer-mesh.js
|
|
24264
24140
|
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
24265
24141
|
import { createServer as createServer3 } from "node:http";
|
|
24266
|
-
import { randomBytes as randomBytes9, createHash as
|
|
24142
|
+
import { randomBytes as randomBytes9, createHash as createHash3, generateKeyPairSync } from "node:crypto";
|
|
24267
24143
|
var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
|
|
24268
24144
|
var init_peer_mesh = __esm({
|
|
24269
24145
|
"packages/cli/dist/tui/p2p/peer-mesh.js"() {
|
|
@@ -24312,7 +24188,7 @@ var init_peer_mesh = __esm({
|
|
|
24312
24188
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
24313
24189
|
this.publicKey = publicKey.export({ type: "spki", format: "der" });
|
|
24314
24190
|
this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
|
|
24315
|
-
this.peerId =
|
|
24191
|
+
this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
|
|
24316
24192
|
this.capabilities = options.capabilities;
|
|
24317
24193
|
this.displayName = options.displayName;
|
|
24318
24194
|
this._authKey = options.authKey ?? randomBytes9(24).toString("base64url");
|
|
@@ -26030,7 +25906,7 @@ var init_oa_directory = __esm({
|
|
|
26030
25906
|
|
|
26031
25907
|
// packages/cli/dist/tui/setup.js
|
|
26032
25908
|
import * as readline from "node:readline";
|
|
26033
|
-
import { execSync as execSync23, spawn as
|
|
25909
|
+
import { execSync as execSync23, spawn as spawn14 } from "node:child_process";
|
|
26034
25910
|
import { existsSync as existsSync25, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
|
|
26035
25911
|
import { join as join35 } from "node:path";
|
|
26036
25912
|
import { homedir as homedir10, platform } from "node:os";
|
|
@@ -26373,7 +26249,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
|
|
|
26373
26249
|
process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
|
|
26374
26250
|
`);
|
|
26375
26251
|
try {
|
|
26376
|
-
const child =
|
|
26252
|
+
const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
26377
26253
|
child.unref();
|
|
26378
26254
|
} catch {
|
|
26379
26255
|
process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
|
|
@@ -26841,7 +26717,7 @@ async function doSetup(config, rl) {
|
|
|
26841
26717
|
${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
|
|
26842
26718
|
`);
|
|
26843
26719
|
try {
|
|
26844
|
-
const child =
|
|
26720
|
+
const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
26845
26721
|
child.unref();
|
|
26846
26722
|
await new Promise((resolve31) => setTimeout(resolve31, 3e3));
|
|
26847
26723
|
try {
|
|
@@ -26869,7 +26745,7 @@ async function doSetup(config, rl) {
|
|
|
26869
26745
|
${c2.cyan("\u25CF")} Starting ollama serve...
|
|
26870
26746
|
`);
|
|
26871
26747
|
try {
|
|
26872
|
-
const child =
|
|
26748
|
+
const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
26873
26749
|
child.unref();
|
|
26874
26750
|
await new Promise((resolve31) => setTimeout(resolve31, 3e3));
|
|
26875
26751
|
try {
|
|
@@ -40303,13 +40179,13 @@ NEW TASK: ${fullInput}`;
|
|
|
40303
40179
|
writeContent(() => renderError(errMsg));
|
|
40304
40180
|
if (failureStore) {
|
|
40305
40181
|
try {
|
|
40306
|
-
const { createHash:
|
|
40182
|
+
const { createHash: createHash5 } = await import("node:crypto");
|
|
40307
40183
|
failureStore.insert({
|
|
40308
40184
|
taskId: "",
|
|
40309
40185
|
sessionId: `${Date.now()}`,
|
|
40310
40186
|
repoRoot,
|
|
40311
40187
|
failureType: "runtime-error",
|
|
40312
|
-
fingerprint:
|
|
40188
|
+
fingerprint: createHash5("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
|
|
40313
40189
|
filePath: null,
|
|
40314
40190
|
errorMessage: errMsg.slice(0, 500),
|
|
40315
40191
|
context: null,
|
|
@@ -40587,7 +40463,7 @@ var init_run = __esm({
|
|
|
40587
40463
|
import { glob } from "glob";
|
|
40588
40464
|
import ignore from "ignore";
|
|
40589
40465
|
import { readFile as readFile16, stat as stat4 } from "node:fs/promises";
|
|
40590
|
-
import { createHash as
|
|
40466
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
40591
40467
|
import { join as join45, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
|
|
40592
40468
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
40593
40469
|
var init_codebase_indexer = __esm({
|
|
@@ -40653,7 +40529,7 @@ var init_codebase_indexer = __esm({
|
|
|
40653
40529
|
if (fileStat.size > this.config.maxFileSize)
|
|
40654
40530
|
continue;
|
|
40655
40531
|
const content = await readFile16(fullPath);
|
|
40656
|
-
const hash =
|
|
40532
|
+
const hash = createHash4("sha256").update(content).digest("hex");
|
|
40657
40533
|
const ext = extname10(relativePath);
|
|
40658
40534
|
indexed.push({
|
|
40659
40535
|
path: fullPath,
|
|
@@ -41193,7 +41069,7 @@ var serve_exports = {};
|
|
|
41193
41069
|
__export(serve_exports, {
|
|
41194
41070
|
serveCommand: () => serveCommand
|
|
41195
41071
|
});
|
|
41196
|
-
import { spawn as
|
|
41072
|
+
import { spawn as spawn15 } from "node:child_process";
|
|
41197
41073
|
async function serveCommand(opts, config) {
|
|
41198
41074
|
const backendType = config.backendType;
|
|
41199
41075
|
if (backendType === "ollama") {
|
|
@@ -41286,7 +41162,7 @@ async function serveVllm(opts, config) {
|
|
|
41286
41162
|
}
|
|
41287
41163
|
async function runVllmServer(args, verbose) {
|
|
41288
41164
|
return new Promise((resolve31, reject) => {
|
|
41289
|
-
const child =
|
|
41165
|
+
const child = spawn15("python", args, {
|
|
41290
41166
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
41291
41167
|
env: { ...process.env }
|
|
41292
41168
|
});
|