open-agents-ai 0.71.4 → 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 +491 -622
- package/package.json +1 -1
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 {}
|
|
11213
11245
|
}
|
|
11214
|
-
|
|
11246
|
+
|
|
11247
|
+
function writeResp(id, result) {
|
|
11248
|
+
try { writeFileSync(respFile, JSON.stringify({ id, ...result }, null, 2)); } catch {}
|
|
11249
|
+
}
|
|
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
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11273
|
+
writeStatus();
|
|
11274
|
+
writeResp(id, { ok: true, output: 'Joined room: ' + roomId });
|
|
11275
|
+
break;
|
|
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;
|
|
11256
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);
|
|
11453
|
+
result = await this.sendDaemonCmd("discover_peers", args);
|
|
11458
11454
|
break;
|
|
11459
|
-
case "
|
|
11460
|
-
result = await this.
|
|
11461
|
-
break;
|
|
11462
|
-
case "list_services":
|
|
11463
|
-
result = await this.doListServices();
|
|
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,491 +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;
|
|
11488
|
+
}
|
|
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;
|
|
11505
|
+
try {
|
|
11506
|
+
const resp = JSON.parse(await readFile13(respFile, "utf8"));
|
|
11507
|
+
if (resp.id === cmdId) {
|
|
11508
|
+
return resp.output || (resp.ok ? "OK" : "Failed");
|
|
11509
|
+
}
|
|
11510
|
+
} catch {
|
|
11511
|
+
}
|
|
11504
11512
|
}
|
|
11513
|
+
return "Daemon did not respond within 15s. It may still be processing.";
|
|
11514
|
+
}
|
|
11515
|
+
// =========================================================================
|
|
11516
|
+
// Actions
|
|
11517
|
+
// =========================================================================
|
|
11518
|
+
async doConnect(args) {
|
|
11505
11519
|
await this.ensureDir();
|
|
11506
|
-
const
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
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}).`;
|
|
11531
|
+
}
|
|
11532
|
+
try {
|
|
11533
|
+
execSync20(`node -e "require.resolve('open-agents-nexus')"`, { stdio: "pipe", timeout: 5e3 });
|
|
11534
|
+
} catch {
|
|
11513
11535
|
try {
|
|
11514
|
-
|
|
11515
|
-
|
|
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
|
+
});
|
|
11516
11540
|
} catch {
|
|
11541
|
+
throw new Error("Failed to install open-agents-nexus. Run: npm install -g open-agents-nexus");
|
|
11517
11542
|
}
|
|
11518
11543
|
}
|
|
11519
|
-
const
|
|
11520
|
-
|
|
11521
|
-
|
|
11522
|
-
|
|
11523
|
-
|
|
11524
|
-
|
|
11525
|
-
|
|
11526
|
-
|
|
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
|
|
11527
11552
|
});
|
|
11528
|
-
|
|
11529
|
-
|
|
11530
|
-
|
|
11531
|
-
|
|
11532
|
-
|
|
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
|
+
}
|
|
11533
11583
|
}
|
|
11534
|
-
} catch {
|
|
11535
11584
|
}
|
|
11536
|
-
|
|
11537
|
-
|
|
11538
|
-
|
|
11539
|
-
|
|
11540
|
-
|
|
11541
|
-
agentType,
|
|
11542
|
-
connectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11543
|
-
walletAddress: walletAddress || null
|
|
11544
|
-
}, null, 2));
|
|
11545
|
-
return [
|
|
11546
|
-
`Connected to nexus P2P network.`,
|
|
11547
|
-
` Peer ID: ${connectionPeerId}`,
|
|
11548
|
-
` Agent: ${agentName} (${agentType})`,
|
|
11549
|
-
` Role: light`,
|
|
11550
|
-
walletAddress ? ` Wallet: ${walletAddress}` : ` Wallet: not configured (use wallet_create)`,
|
|
11551
|
-
` x402 payments: ${walletAddress ? "enabled" : "disabled"}`,
|
|
11552
|
-
``,
|
|
11553
|
-
`You can now join rooms, discover peers, and participate in the agent mesh.`
|
|
11554
|
-
].join("\n");
|
|
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) : ""}`;
|
|
11588
|
+
}
|
|
11589
|
+
return `Daemon failed to start.${earlyError ? "\n" + earlyError.slice(0, 500) : ""}${earlyOutput ? "\n" + earlyOutput.slice(0, 500) : ""}`;
|
|
11555
11590
|
}
|
|
11556
11591
|
async doDisconnect() {
|
|
11557
|
-
|
|
11558
|
-
|
|
11559
|
-
|
|
11560
|
-
|
|
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));
|
|
11561
11598
|
try {
|
|
11562
|
-
|
|
11599
|
+
process.kill(pid, 0);
|
|
11600
|
+
process.kill(pid, "SIGKILL");
|
|
11563
11601
|
} catch {
|
|
11564
11602
|
}
|
|
11603
|
+
} catch {
|
|
11565
11604
|
}
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
|
|
11571
|
-
const connPath = join28(this.nexusDir, "connection.json");
|
|
11572
|
-
if (existsSync21(connPath)) {
|
|
11573
|
-
const { unlink } = await import("node:fs/promises");
|
|
11574
|
-
await unlink(connPath).catch(() => {
|
|
11575
|
-
});
|
|
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(() => {
|
|
11609
|
+
});
|
|
11576
11610
|
}
|
|
11577
|
-
return `Disconnected from nexus network
|
|
11611
|
+
return `Disconnected from nexus network (killed pid ${pid}).`;
|
|
11578
11612
|
}
|
|
11579
11613
|
async doStatus() {
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
const
|
|
11584
|
-
|
|
11585
|
-
|
|
11586
|
-
|
|
11587
|
-
|
|
11588
|
-
|
|
11589
|
-
|
|
11590
|
-
|
|
11591
|
-
|
|
11592
|
-
|
|
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`);
|
|
11593
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.`;
|
|
11594
11661
|
}
|
|
11595
|
-
return [
|
|
11596
|
-
`Nexus Network Status`,
|
|
11597
|
-
` Connected: true`,
|
|
11598
|
-
` Peer ID: ${connectionPeerId}`,
|
|
11599
|
-
` Rooms joined: ${rooms.length} [${rooms.join(", ")}]`,
|
|
11600
|
-
` Content pinned: ${stats.totalPinned} (${stats.pinnedFromOthers} from others)`,
|
|
11601
|
-
` Tracked CIDs: ${stats.trackedCids}`,
|
|
11602
|
-
` Registered services: ${registeredServices.length}`,
|
|
11603
|
-
` Wallet: ${walletInfo}`,
|
|
11604
|
-
` x402: ${clientInstance.x402?.isEnabled ? "enabled" : "disabled"}`
|
|
11605
|
-
].join("\n");
|
|
11606
|
-
}
|
|
11607
|
-
async doJoinRoom(args) {
|
|
11608
|
-
if (!clientInstance)
|
|
11609
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11610
|
-
const roomId = args.room_id;
|
|
11611
|
-
if (!roomId)
|
|
11612
|
-
throw new Error("room_id is required");
|
|
11613
|
-
if (activeRooms.has(roomId)) {
|
|
11614
|
-
return `Already in room: ${roomId}`;
|
|
11615
|
-
}
|
|
11616
|
-
const room = await clientInstance.joinRoom(roomId);
|
|
11617
|
-
activeRooms.set(roomId, room);
|
|
11618
|
-
room.on("message", (msg) => {
|
|
11619
|
-
const msgDir = join28(this.nexusDir, "messages", roomId);
|
|
11620
|
-
mkdir8(msgDir, { recursive: true }).then(() => {
|
|
11621
|
-
const filename = `${msg.id || Date.now()}.json`;
|
|
11622
|
-
writeFile12(join28(msgDir, filename), JSON.stringify(msg, null, 2)).catch(() => {
|
|
11623
|
-
});
|
|
11624
|
-
}).catch(() => {
|
|
11625
|
-
});
|
|
11626
|
-
});
|
|
11627
|
-
return `Joined room: ${roomId}
|
|
11628
|
-
Listening for messages. Use send_message to communicate.`;
|
|
11629
|
-
}
|
|
11630
|
-
async doLeaveRoom(args) {
|
|
11631
|
-
const roomId = args.room_id;
|
|
11632
|
-
if (!roomId)
|
|
11633
|
-
throw new Error("room_id is required");
|
|
11634
|
-
const room = activeRooms.get(roomId);
|
|
11635
|
-
if (!room)
|
|
11636
|
-
return `Not in room: ${roomId}`;
|
|
11637
|
-
await room.leave();
|
|
11638
|
-
activeRooms.delete(roomId);
|
|
11639
|
-
return `Left room: ${roomId}`;
|
|
11640
11662
|
}
|
|
11641
11663
|
async doSendMessage(args) {
|
|
11642
|
-
if (!clientInstance)
|
|
11643
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11644
|
-
const roomId = args.room_id;
|
|
11645
11664
|
const message = args.message;
|
|
11646
|
-
if (!roomId)
|
|
11647
|
-
throw new Error("room_id is required");
|
|
11648
11665
|
if (!message)
|
|
11649
11666
|
throw new Error("message is required");
|
|
11667
|
+
if (!args.room_id)
|
|
11668
|
+
throw new Error("room_id is required");
|
|
11650
11669
|
if (containsKeyMaterial(message)) {
|
|
11651
11670
|
return [
|
|
11652
11671
|
"BLOCKED: Message contains potential key material or secrets.",
|
|
11653
|
-
"
|
|
11654
|
-
"
|
|
11655
|
-
"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."
|
|
11656
11674
|
].join("\n");
|
|
11657
11675
|
}
|
|
11658
|
-
|
|
11659
|
-
if (!room)
|
|
11660
|
-
throw new Error(`Not in room: ${roomId}. Join it first.`);
|
|
11661
|
-
const msgId = await room.send(message, { format: "text/plain" });
|
|
11662
|
-
return `Message sent to ${roomId} (id: ${msgId})`;
|
|
11663
|
-
}
|
|
11664
|
-
async doListRooms() {
|
|
11665
|
-
if (!clientInstance)
|
|
11666
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11667
|
-
try {
|
|
11668
|
-
const rooms = await clientInstance.listRooms();
|
|
11669
|
-
if (!rooms || rooms.length === 0) {
|
|
11670
|
-
return "No rooms found on the network. Create one by joining a new room ID.";
|
|
11671
|
-
}
|
|
11672
|
-
const lines = rooms.map((r) => ` ${r.roomId} \u2014 ${r.name || "(unnamed)"} [${r.memberCount || 0} members, ${r.type}]`);
|
|
11673
|
-
return `Available rooms:
|
|
11674
|
-
${lines.join("\n")}`;
|
|
11675
|
-
} catch {
|
|
11676
|
-
return "Could not list rooms (DHT may still be bootstrapping). Try again in a moment.";
|
|
11677
|
-
}
|
|
11676
|
+
return this.sendDaemonCmd("send_message", args);
|
|
11678
11677
|
}
|
|
11679
|
-
async
|
|
11680
|
-
|
|
11681
|
-
|
|
11682
|
-
|
|
11683
|
-
const
|
|
11684
|
-
if (!
|
|
11685
|
-
return
|
|
11686
|
-
const
|
|
11687
|
-
if (
|
|
11688
|
-
return
|
|
11689
|
-
}
|
|
11690
|
-
const
|
|
11691
|
-
for (const peerId of peers.slice(0, 20)) {
|
|
11692
|
-
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) {
|
|
11693
11690
|
try {
|
|
11694
|
-
const
|
|
11695
|
-
|
|
11696
|
-
|
|
11697
|
-
} else {
|
|
11698
|
-
lines.push(` ${pid.slice(0, 16)}... \u2014 (no profile)`);
|
|
11699
|
-
}
|
|
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}`);
|
|
11700
11694
|
} catch {
|
|
11701
|
-
lines.push(` ${pid.slice(0, 16)}... \u2014 (lookup failed)`);
|
|
11702
11695
|
}
|
|
11703
11696
|
}
|
|
11704
|
-
|
|
11705
|
-
lines.push(` ... and ${peers.length - 20} more`);
|
|
11706
|
-
}
|
|
11707
|
-
return lines.join("\n");
|
|
11708
|
-
} catch (err) {
|
|
11709
|
-
return `Peer discovery error: ${err.message}`;
|
|
11697
|
+
return messages.join("\n");
|
|
11710
11698
|
}
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
const profile = await clientInstance.findAgent(peerId);
|
|
11719
|
-
if (!profile) {
|
|
11720
|
-
return `Agent not found: ${peerId}`;
|
|
11721
|
-
}
|
|
11722
|
-
const caps = profile.capabilities?.map((c3) => ` - ${c3.name}: ${c3.description} [${c3.pricing}]`) || [];
|
|
11723
|
-
return [
|
|
11724
|
-
`Agent Profile:`,
|
|
11725
|
-
` Peer ID: ${profile.peerId}`,
|
|
11726
|
-
` Name: ${profile.name}`,
|
|
11727
|
-
` Type: ${profile.type}`,
|
|
11728
|
-
` Role: ${profile.role}`,
|
|
11729
|
-
` Capabilities (${caps.length}):`,
|
|
11730
|
-
...caps,
|
|
11731
|
-
` Created: ${new Date(profile.createdAt).toISOString()}`,
|
|
11732
|
-
` Updated: ${new Date(profile.updatedAt).toISOString()}`
|
|
11733
|
-
].join("\n");
|
|
11734
|
-
}
|
|
11735
|
-
async doRegisterService(args) {
|
|
11736
|
-
if (!clientInstance)
|
|
11737
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11738
|
-
const serviceId = args.service_id || `svc-${randomBytes6(4).toString("hex")}`;
|
|
11739
|
-
const name = args.service_name || "inference";
|
|
11740
|
-
const description = args.service_description || "AI inference service";
|
|
11741
|
-
const priceAmount = args.price_amount || "0.001";
|
|
11742
|
-
const rateLimit = args.rate_limit || 60;
|
|
11743
|
-
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11744
|
-
let walletAddress = "";
|
|
11745
|
-
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) {
|
|
11746
11706
|
try {
|
|
11747
|
-
const
|
|
11748
|
-
|
|
11707
|
+
const count = (await readdir3(join28(inboxDir, rd))).length;
|
|
11708
|
+
lines.push(` ${rd}: ${count} message(s)`);
|
|
11749
11709
|
} catch {
|
|
11750
11710
|
}
|
|
11751
11711
|
}
|
|
11752
|
-
|
|
11753
|
-
return "Cannot register paid service without a wallet. Use wallet_create first.";
|
|
11754
|
-
}
|
|
11755
|
-
const offering = {
|
|
11756
|
-
serviceId,
|
|
11757
|
-
name,
|
|
11758
|
-
description,
|
|
11759
|
-
price: {
|
|
11760
|
-
amount: priceAmount,
|
|
11761
|
-
currency: "USDC",
|
|
11762
|
-
network: "base",
|
|
11763
|
-
recipient: walletAddress,
|
|
11764
|
-
description: `Payment for ${name}`,
|
|
11765
|
-
expiresAt: Date.now() + 36e5,
|
|
11766
|
-
// 1 hour
|
|
11767
|
-
requestId: `req-${randomBytes6(8).toString("hex")}`
|
|
11768
|
-
},
|
|
11769
|
-
rateLimit,
|
|
11770
|
-
sensitive: false
|
|
11771
|
-
};
|
|
11772
|
-
clientInstance.x402.registerService(offering);
|
|
11773
|
-
registeredServices.push(offering);
|
|
11774
|
-
await this.ensureDir();
|
|
11775
|
-
await writeFile12(join28(this.nexusDir, "services.json"), JSON.stringify(registeredServices, null, 2));
|
|
11776
|
-
return [
|
|
11777
|
-
`Service registered:`,
|
|
11778
|
-
` ID: ${serviceId}`,
|
|
11779
|
-
` Name: ${name}`,
|
|
11780
|
-
` Description: ${description}`,
|
|
11781
|
-
` Price: ${priceAmount} USDC per request`,
|
|
11782
|
-
` Rate limit: ${rateLimit} req/hour`,
|
|
11783
|
-
` Recipient wallet: ${walletAddress}`
|
|
11784
|
-
].join("\n");
|
|
11785
|
-
}
|
|
11786
|
-
async doListServices() {
|
|
11787
|
-
const services = clientInstance?.x402?.getServices() || registeredServices;
|
|
11788
|
-
if (services.length === 0) {
|
|
11789
|
-
return "No services registered. Use register_service to offer inference.";
|
|
11790
|
-
}
|
|
11791
|
-
const lines = services.map((s) => ` ${s.serviceId} \u2014 ${s.name}: ${s.description} [${s.price?.amount || "?"} ${s.price?.currency || "USDC"}, ${s.rateLimit} req/hr]`);
|
|
11792
|
-
return `Registered services (${services.length}):
|
|
11793
|
-
${lines.join("\n")}`;
|
|
11712
|
+
return lines.join("\n");
|
|
11794
11713
|
}
|
|
11795
11714
|
async doWalletStatus() {
|
|
11796
11715
|
await this.ensureDir();
|
|
11797
11716
|
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11798
11717
|
if (!existsSync21(walletPath)) {
|
|
11799
|
-
return
|
|
11800
|
-
"No wallet configured.",
|
|
11801
|
-
"Use wallet_create to generate a new wallet for x402 micropayments.",
|
|
11802
|
-
"Or provide your own wallet address with wallet_create + wallet_address parameter."
|
|
11803
|
-
].join("\n");
|
|
11718
|
+
return "No wallet configured. Use wallet_create to set one up.";
|
|
11804
11719
|
}
|
|
11805
11720
|
try {
|
|
11806
|
-
const
|
|
11721
|
+
const w = JSON.parse(await readFile13(walletPath, "utf8"));
|
|
11807
11722
|
return [
|
|
11808
11723
|
`Wallet Status:`,
|
|
11809
|
-
` Address: ${
|
|
11810
|
-
` Created: ${
|
|
11724
|
+
` Address: ${w.address}`,
|
|
11725
|
+
` Created: ${w.createdAt}`,
|
|
11811
11726
|
` Encryption: AES-256-GCM + scrypt`,
|
|
11812
|
-
`
|
|
11813
|
-
``,
|
|
11814
|
-
` NOTE: Private key is encrypted and NEVER accessible to the agent.`,
|
|
11815
|
-
` Only the public address is visible. Payment operations use the`,
|
|
11816
|
-
` encrypted key internally without exposing it.`
|
|
11727
|
+
` NOTE: Private key is encrypted and NEVER accessible to the agent.`
|
|
11817
11728
|
].join("\n");
|
|
11818
11729
|
} catch {
|
|
11819
|
-
return "Wallet file exists but could not be read.
|
|
11730
|
+
return "Wallet file exists but could not be read.";
|
|
11820
11731
|
}
|
|
11821
11732
|
}
|
|
11822
11733
|
async doWalletCreate(args) {
|
|
11823
11734
|
await this.ensureDir();
|
|
11824
11735
|
const walletPath = join28(this.nexusDir, "wallet.enc");
|
|
11825
|
-
if (existsSync21(walletPath))
|
|
11826
|
-
return "Wallet already exists.
|
|
11827
|
-
}
|
|
11736
|
+
if (existsSync21(walletPath))
|
|
11737
|
+
return "Wallet already exists.";
|
|
11828
11738
|
const userAddress = args.wallet_address;
|
|
11829
11739
|
if (userAddress) {
|
|
11830
11740
|
if (!/^0x[0-9a-fA-F]{40}$/.test(userAddress)) {
|
|
11831
|
-
return "Invalid
|
|
11741
|
+
return "Invalid address format. Expected 0x + 40 hex chars.";
|
|
11832
11742
|
}
|
|
11833
|
-
const
|
|
11743
|
+
const w2 = {
|
|
11834
11744
|
version: 1,
|
|
11835
11745
|
address: userAddress,
|
|
11836
11746
|
encryptedKey: "",
|
|
11837
|
-
// user-managed key
|
|
11838
11747
|
iv: "",
|
|
11839
11748
|
authTag: "",
|
|
11840
11749
|
salt: "",
|
|
11841
11750
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11842
11751
|
};
|
|
11843
|
-
await writeFile12(walletPath, JSON.stringify(
|
|
11752
|
+
await writeFile12(walletPath, JSON.stringify(w2, null, 2));
|
|
11844
11753
|
await chmod(walletPath, 384);
|
|
11845
|
-
return
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
const
|
|
11857
|
-
const privateKeyHex = privateKeyBytes.toString("hex");
|
|
11858
|
-
let address;
|
|
11859
|
-
try {
|
|
11860
|
-
const { createHash: createHash4 } = await import("node:crypto");
|
|
11861
|
-
const pubHash = createHash4("sha256").update(privateKeyBytes).digest("hex");
|
|
11862
|
-
address = "0x" + pubHash.slice(0, 40);
|
|
11863
|
-
} catch {
|
|
11864
|
-
address = "0x" + randomBytes6(20).toString("hex");
|
|
11865
|
-
}
|
|
11866
|
-
const machineId = `${__require("node:os").hostname()}:${__require("node:os").userInfo().username}:nexus-wallet`;
|
|
11867
|
-
const { encrypted, iv, authTag, salt } = encryptKey(privateKeyHex, machineId);
|
|
11868
|
-
privateKeyBytes.fill(0);
|
|
11869
|
-
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 = {
|
|
11870
11766
|
version: 1,
|
|
11871
11767
|
address,
|
|
11872
|
-
encryptedKey:
|
|
11873
|
-
iv,
|
|
11874
|
-
authTag,
|
|
11875
|
-
salt,
|
|
11768
|
+
encryptedKey: enc,
|
|
11769
|
+
iv: iv.toString("hex"),
|
|
11770
|
+
authTag: cipher.getAuthTag().toString("hex"),
|
|
11771
|
+
salt: salt.toString("hex"),
|
|
11876
11772
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
11877
11773
|
};
|
|
11878
|
-
await writeFile12(walletPath, JSON.stringify(
|
|
11774
|
+
await writeFile12(walletPath, JSON.stringify(w, null, 2));
|
|
11879
11775
|
await chmod(walletPath, 384);
|
|
11880
11776
|
return [
|
|
11881
|
-
`Wallet created
|
|
11882
|
-
`
|
|
11883
|
-
`
|
|
11884
|
-
` Key file: ${walletPath} (permissions: 0600)`,
|
|
11885
|
-
``,
|
|
11886
|
-
` SECURITY NOTES:`,
|
|
11887
|
-
` - Private key is encrypted at rest and NEVER visible to the agent`,
|
|
11888
|
-
` - Key material is cleared from memory after encryption`,
|
|
11889
|
-
` - The encryption password is derived from machine identity`,
|
|
11890
|
-
` - Only payment operations can use the key (internally)`,
|
|
11891
|
-
` - 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)`
|
|
11892
11780
|
].join("\n");
|
|
11893
11781
|
}
|
|
11894
11782
|
async doInferenceProof() {
|
|
11895
|
-
|
|
11896
|
-
|
|
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));
|
|
11897
11818
|
return [
|
|
11898
|
-
|
|
11899
|
-
|
|
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)}...`
|
|
11900
11824
|
].join("\n");
|
|
11825
|
+
} catch {
|
|
11826
|
+
return "Could not generate proof. Ensure Ollama is running.";
|
|
11901
11827
|
}
|
|
11902
|
-
await this.ensureDir();
|
|
11903
|
-
const proofPath = join28(this.nexusDir, "inference-proof.json");
|
|
11904
|
-
await writeFile12(proofPath, JSON.stringify(proof, null, 2));
|
|
11905
|
-
const memScore = proof.vramMb > 24e3 ? 95 : proof.vramMb > 16e3 ? 80 : proof.vramMb > 8e3 ? 60 : proof.vramMb > 0 ? 40 : 20;
|
|
11906
|
-
const speedScore = proof.tokensPerSecond > 50 ? 95 : proof.tokensPerSecond > 30 ? 80 : proof.tokensPerSecond > 15 ? 60 : proof.tokensPerSecond > 5 ? 40 : 20;
|
|
11907
|
-
const overall = Math.round((memScore + speedScore) / 2);
|
|
11908
|
-
const bar = (score) => {
|
|
11909
|
-
const filled = Math.round(score / 5);
|
|
11910
|
-
const empty = 20 - filled;
|
|
11911
|
-
return "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
11912
|
-
};
|
|
11913
|
-
return [
|
|
11914
|
-
`Inference Capability Proof`,
|
|
11915
|
-
`\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`,
|
|
11916
|
-
` Model: ${proof.modelName} (${proof.modelSize})`,
|
|
11917
|
-
` GPU: ${proof.gpuName} (${proof.vramMb} MB VRAM)`,
|
|
11918
|
-
` Speed: ${proof.tokensPerSecond} tok/s`,
|
|
11919
|
-
` Context: ${proof.contextLength} tokens`,
|
|
11920
|
-
``,
|
|
11921
|
-
` Memory [${bar(memScore)}] ${memScore}%`,
|
|
11922
|
-
` Speed [${bar(speedScore)}] ${speedScore}%`,
|
|
11923
|
-
` Overall [${bar(overall)}] ${overall}%`,
|
|
11924
|
-
``,
|
|
11925
|
-
` Benchmark hash: ${proof.benchmarkHash.slice(0, 16)}...`,
|
|
11926
|
-
` Timestamp: ${proof.timestamp}`,
|
|
11927
|
-
` Proof saved: ${proofPath}`,
|
|
11928
|
-
``,
|
|
11929
|
-
` Anti-spoofing: SHA-256 hash of model+timing+nonce`,
|
|
11930
|
-
` Verification: peers can request live re-benchmark`
|
|
11931
|
-
].join("\n");
|
|
11932
|
-
}
|
|
11933
|
-
async doStoreContent(args) {
|
|
11934
|
-
if (!clientInstance)
|
|
11935
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11936
|
-
const content = args.content;
|
|
11937
|
-
if (!content)
|
|
11938
|
-
throw new Error("content is required");
|
|
11939
|
-
if (containsKeyMaterial(content)) {
|
|
11940
|
-
return "BLOCKED: Content contains potential key material. Cannot store secrets on IPFS.";
|
|
11941
|
-
}
|
|
11942
|
-
const cid = await clientInstance.store(content);
|
|
11943
|
-
return `Content stored on IPFS.
|
|
11944
|
-
CID: ${cid}
|
|
11945
|
-
Retrieve with: retrieve_content + cid="${cid}"`;
|
|
11946
|
-
}
|
|
11947
|
-
async doRetrieveContent(args) {
|
|
11948
|
-
if (!clientInstance)
|
|
11949
|
-
throw new Error("Not connected. Use 'connect' first.");
|
|
11950
|
-
const cid = args.cid;
|
|
11951
|
-
if (!cid)
|
|
11952
|
-
throw new Error("cid is required");
|
|
11953
|
-
const data = await clientInstance.retrieve(cid);
|
|
11954
|
-
if (typeof data === "string")
|
|
11955
|
-
return data;
|
|
11956
|
-
if (typeof data === "object")
|
|
11957
|
-
return JSON.stringify(data, null, 2);
|
|
11958
|
-
return String(data);
|
|
11959
11828
|
}
|
|
11960
11829
|
};
|
|
11961
11830
|
}
|
|
@@ -13215,7 +13084,7 @@ var init_code_retriever = __esm({
|
|
|
13215
13084
|
// packages/retrieval/dist/lexicalSearch.js
|
|
13216
13085
|
import { execFile as execFile5 } from "node:child_process";
|
|
13217
13086
|
import { promisify as promisify4 } from "node:util";
|
|
13218
|
-
import { readFile as readFile14, readdir as
|
|
13087
|
+
import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "node:fs/promises";
|
|
13219
13088
|
import { join as join29, extname as extname7 } from "node:path";
|
|
13220
13089
|
async function searchByPath(pathPattern, options) {
|
|
13221
13090
|
const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
|
|
@@ -13349,7 +13218,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
|
|
|
13349
13218
|
async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
13350
13219
|
let entries;
|
|
13351
13220
|
try {
|
|
13352
|
-
entries = await
|
|
13221
|
+
entries = await readdir4(dir, { withFileTypes: true, encoding: "utf-8" });
|
|
13353
13222
|
} catch {
|
|
13354
13223
|
return;
|
|
13355
13224
|
}
|
|
@@ -17770,7 +17639,7 @@ __export(listen_exports, {
|
|
|
17770
17639
|
isVideoPath: () => isVideoPath,
|
|
17771
17640
|
waitForTranscribeCli: () => waitForTranscribeCli
|
|
17772
17641
|
});
|
|
17773
|
-
import { spawn as
|
|
17642
|
+
import { spawn as spawn11, execSync as execSync21 } from "node:child_process";
|
|
17774
17643
|
import { existsSync as existsSync22, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6 } from "node:fs";
|
|
17775
17644
|
import { join as join31, dirname as dirname10 } from "node:path";
|
|
17776
17645
|
import { homedir as homedir8 } from "node:os";
|
|
@@ -17980,7 +17849,7 @@ var init_listen = __esm({
|
|
|
17980
17849
|
const timeout = setTimeout(() => {
|
|
17981
17850
|
reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
|
|
17982
17851
|
}, 3e5);
|
|
17983
|
-
this.process =
|
|
17852
|
+
this.process = spawn11("python3", [
|
|
17984
17853
|
this.scriptPath,
|
|
17985
17854
|
"--model",
|
|
17986
17855
|
this.model,
|
|
@@ -18262,7 +18131,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
|
|
|
18262
18131
|
return `Failed to start live transcription: ${msg}${tcHint}`;
|
|
18263
18132
|
}
|
|
18264
18133
|
}
|
|
18265
|
-
this.micProcess =
|
|
18134
|
+
this.micProcess = spawn11(micCmd.cmd, micCmd.args, {
|
|
18266
18135
|
stdio: ["pipe", "pipe", "pipe"],
|
|
18267
18136
|
env: { ...process.env }
|
|
18268
18137
|
});
|
|
@@ -20681,7 +20550,7 @@ var require_websocket = __commonJS({
|
|
|
20681
20550
|
var http = __require("http");
|
|
20682
20551
|
var net = __require("net");
|
|
20683
20552
|
var tls = __require("tls");
|
|
20684
|
-
var { randomBytes: randomBytes10, createHash:
|
|
20553
|
+
var { randomBytes: randomBytes10, createHash: createHash5 } = __require("crypto");
|
|
20685
20554
|
var { Duplex, Readable } = __require("stream");
|
|
20686
20555
|
var { URL: URL3 } = __require("url");
|
|
20687
20556
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -21341,7 +21210,7 @@ var require_websocket = __commonJS({
|
|
|
21341
21210
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
21342
21211
|
return;
|
|
21343
21212
|
}
|
|
21344
|
-
const digest =
|
|
21213
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
21345
21214
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
21346
21215
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
21347
21216
|
return;
|
|
@@ -21708,7 +21577,7 @@ var require_websocket_server = __commonJS({
|
|
|
21708
21577
|
var EventEmitter7 = __require("events");
|
|
21709
21578
|
var http = __require("http");
|
|
21710
21579
|
var { Duplex } = __require("stream");
|
|
21711
|
-
var { createHash:
|
|
21580
|
+
var { createHash: createHash5 } = __require("crypto");
|
|
21712
21581
|
var extension = require_extension();
|
|
21713
21582
|
var PerMessageDeflate = require_permessage_deflate();
|
|
21714
21583
|
var subprotocol = require_subprotocol();
|
|
@@ -22009,7 +21878,7 @@ var require_websocket_server = __commonJS({
|
|
|
22009
21878
|
);
|
|
22010
21879
|
}
|
|
22011
21880
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
22012
|
-
const digest =
|
|
21881
|
+
const digest = createHash5("sha1").update(key + GUID).digest("base64");
|
|
22013
21882
|
const headers = [
|
|
22014
21883
|
"HTTP/1.1 101 Switching Protocols",
|
|
22015
21884
|
"Upgrade: websocket",
|
|
@@ -22998,7 +22867,7 @@ var init_render = __esm({
|
|
|
22998
22867
|
|
|
22999
22868
|
// packages/cli/dist/tui/voice-session.js
|
|
23000
22869
|
import { createServer } from "node:http";
|
|
23001
|
-
import { spawn as
|
|
22870
|
+
import { spawn as spawn12, execSync as execSync22 } from "node:child_process";
|
|
23002
22871
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
23003
22872
|
function generateFrontendHTML() {
|
|
23004
22873
|
return `<!DOCTYPE html>
|
|
@@ -23652,7 +23521,7 @@ var init_voice_session = __esm({
|
|
|
23652
23521
|
const timeout = setTimeout(() => {
|
|
23653
23522
|
reject(new Error("Cloudflared tunnel start timeout (30s)"));
|
|
23654
23523
|
}, 3e4);
|
|
23655
|
-
this.cloudflaredProcess =
|
|
23524
|
+
this.cloudflaredProcess = spawn12("cloudflared", [
|
|
23656
23525
|
"tunnel",
|
|
23657
23526
|
"--url",
|
|
23658
23527
|
`http://127.0.0.1:${port}`
|
|
@@ -23726,7 +23595,7 @@ var init_voice_session = __esm({
|
|
|
23726
23595
|
|
|
23727
23596
|
// packages/cli/dist/tui/expose.js
|
|
23728
23597
|
import { createServer as createServer2, request as httpRequest } from "node:http";
|
|
23729
|
-
import { spawn as
|
|
23598
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
23730
23599
|
import { EventEmitter as EventEmitter3 } from "node:events";
|
|
23731
23600
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
23732
23601
|
import { URL as URL2 } from "node:url";
|
|
@@ -23902,7 +23771,7 @@ var init_expose = __esm({
|
|
|
23902
23771
|
const timeout = setTimeout(() => {
|
|
23903
23772
|
reject(new Error("Cloudflared tunnel start timeout (30s)"));
|
|
23904
23773
|
}, 3e4);
|
|
23905
|
-
this.cloudflaredProcess =
|
|
23774
|
+
this.cloudflaredProcess = spawn13("cloudflared", [
|
|
23906
23775
|
"tunnel",
|
|
23907
23776
|
"--url",
|
|
23908
23777
|
`http://127.0.0.1:${port}`
|
|
@@ -24004,10 +23873,10 @@ var init_types = __esm({
|
|
|
24004
23873
|
});
|
|
24005
23874
|
|
|
24006
23875
|
// packages/cli/dist/tui/p2p/secret-vault.js
|
|
24007
|
-
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";
|
|
24008
23877
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, existsSync as existsSync23, mkdirSync as mkdirSync7 } from "node:fs";
|
|
24009
23878
|
import { join as join32, dirname as dirname11 } from "node:path";
|
|
24010
|
-
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;
|
|
24011
23880
|
var init_secret_vault = __esm({
|
|
24012
23881
|
"packages/cli/dist/tui/p2p/secret-vault.js"() {
|
|
24013
23882
|
"use strict";
|
|
@@ -24017,7 +23886,7 @@ var init_secret_vault = __esm({
|
|
|
24017
23886
|
CIPHER_ALGO = "aes-256-gcm";
|
|
24018
23887
|
SALT_LEN = 16;
|
|
24019
23888
|
IV_LEN = 12;
|
|
24020
|
-
|
|
23889
|
+
KEY_LEN = 32;
|
|
24021
23890
|
SecretVault = class {
|
|
24022
23891
|
storePath;
|
|
24023
23892
|
secrets = /* @__PURE__ */ new Map();
|
|
@@ -24211,7 +24080,7 @@ var init_secret_vault = __esm({
|
|
|
24211
24080
|
createdAt: s.createdAt
|
|
24212
24081
|
})));
|
|
24213
24082
|
const salt = randomBytes8(SALT_LEN);
|
|
24214
|
-
const key = scryptSync2(passphrase, salt,
|
|
24083
|
+
const key = scryptSync2(passphrase, salt, KEY_LEN);
|
|
24215
24084
|
const iv = randomBytes8(IV_LEN);
|
|
24216
24085
|
const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
|
|
24217
24086
|
const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
|
|
@@ -24237,7 +24106,7 @@ var init_secret_vault = __esm({
|
|
|
24237
24106
|
const iv = blob.subarray(SALT_LEN, SALT_LEN + IV_LEN);
|
|
24238
24107
|
const tag = blob.subarray(SALT_LEN + IV_LEN, SALT_LEN + IV_LEN + 16);
|
|
24239
24108
|
const encrypted = blob.subarray(SALT_LEN + IV_LEN + 16);
|
|
24240
|
-
const key = scryptSync2(passphrase, salt,
|
|
24109
|
+
const key = scryptSync2(passphrase, salt, KEY_LEN);
|
|
24241
24110
|
const decipher = createDecipheriv2(CIPHER_ALGO, key, iv);
|
|
24242
24111
|
decipher.setAuthTag(tag);
|
|
24243
24112
|
let data;
|
|
@@ -24255,7 +24124,7 @@ var init_secret_vault = __esm({
|
|
|
24255
24124
|
/** Generate a deterministic fingerprint of vault contents (for sync verification) */
|
|
24256
24125
|
fingerprint() {
|
|
24257
24126
|
const names = Array.from(this.secrets.keys()).sort();
|
|
24258
|
-
const hash =
|
|
24127
|
+
const hash = createHash2("sha256");
|
|
24259
24128
|
for (const name of names) {
|
|
24260
24129
|
hash.update(name + ":");
|
|
24261
24130
|
hash.update(this.secrets.get(name).value);
|
|
@@ -24270,7 +24139,7 @@ var init_secret_vault = __esm({
|
|
|
24270
24139
|
// packages/cli/dist/tui/p2p/peer-mesh.js
|
|
24271
24140
|
import { EventEmitter as EventEmitter4 } from "node:events";
|
|
24272
24141
|
import { createServer as createServer3 } from "node:http";
|
|
24273
|
-
import { randomBytes as randomBytes9, createHash as
|
|
24142
|
+
import { randomBytes as randomBytes9, createHash as createHash3, generateKeyPairSync } from "node:crypto";
|
|
24274
24143
|
var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
|
|
24275
24144
|
var init_peer_mesh = __esm({
|
|
24276
24145
|
"packages/cli/dist/tui/p2p/peer-mesh.js"() {
|
|
@@ -24319,7 +24188,7 @@ var init_peer_mesh = __esm({
|
|
|
24319
24188
|
const { publicKey, privateKey } = generateKeyPairSync("ed25519");
|
|
24320
24189
|
this.publicKey = publicKey.export({ type: "spki", format: "der" });
|
|
24321
24190
|
this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
|
|
24322
|
-
this.peerId =
|
|
24191
|
+
this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
|
|
24323
24192
|
this.capabilities = options.capabilities;
|
|
24324
24193
|
this.displayName = options.displayName;
|
|
24325
24194
|
this._authKey = options.authKey ?? randomBytes9(24).toString("base64url");
|
|
@@ -26037,7 +25906,7 @@ var init_oa_directory = __esm({
|
|
|
26037
25906
|
|
|
26038
25907
|
// packages/cli/dist/tui/setup.js
|
|
26039
25908
|
import * as readline from "node:readline";
|
|
26040
|
-
import { execSync as execSync23, spawn as
|
|
25909
|
+
import { execSync as execSync23, spawn as spawn14 } from "node:child_process";
|
|
26041
25910
|
import { existsSync as existsSync25, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
|
|
26042
25911
|
import { join as join35 } from "node:path";
|
|
26043
25912
|
import { homedir as homedir10, platform } from "node:os";
|
|
@@ -26380,7 +26249,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
|
|
|
26380
26249
|
process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
|
|
26381
26250
|
`);
|
|
26382
26251
|
try {
|
|
26383
|
-
const child =
|
|
26252
|
+
const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
26384
26253
|
child.unref();
|
|
26385
26254
|
} catch {
|
|
26386
26255
|
process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
|
|
@@ -26848,7 +26717,7 @@ async function doSetup(config, rl) {
|
|
|
26848
26717
|
${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
|
|
26849
26718
|
`);
|
|
26850
26719
|
try {
|
|
26851
|
-
const child =
|
|
26720
|
+
const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
26852
26721
|
child.unref();
|
|
26853
26722
|
await new Promise((resolve31) => setTimeout(resolve31, 3e3));
|
|
26854
26723
|
try {
|
|
@@ -26876,7 +26745,7 @@ async function doSetup(config, rl) {
|
|
|
26876
26745
|
${c2.cyan("\u25CF")} Starting ollama serve...
|
|
26877
26746
|
`);
|
|
26878
26747
|
try {
|
|
26879
|
-
const child =
|
|
26748
|
+
const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
|
|
26880
26749
|
child.unref();
|
|
26881
26750
|
await new Promise((resolve31) => setTimeout(resolve31, 3e3));
|
|
26882
26751
|
try {
|
|
@@ -40310,13 +40179,13 @@ NEW TASK: ${fullInput}`;
|
|
|
40310
40179
|
writeContent(() => renderError(errMsg));
|
|
40311
40180
|
if (failureStore) {
|
|
40312
40181
|
try {
|
|
40313
|
-
const { createHash:
|
|
40182
|
+
const { createHash: createHash5 } = await import("node:crypto");
|
|
40314
40183
|
failureStore.insert({
|
|
40315
40184
|
taskId: "",
|
|
40316
40185
|
sessionId: `${Date.now()}`,
|
|
40317
40186
|
repoRoot,
|
|
40318
40187
|
failureType: "runtime-error",
|
|
40319
|
-
fingerprint:
|
|
40188
|
+
fingerprint: createHash5("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
|
|
40320
40189
|
filePath: null,
|
|
40321
40190
|
errorMessage: errMsg.slice(0, 500),
|
|
40322
40191
|
context: null,
|
|
@@ -40594,7 +40463,7 @@ var init_run = __esm({
|
|
|
40594
40463
|
import { glob } from "glob";
|
|
40595
40464
|
import ignore from "ignore";
|
|
40596
40465
|
import { readFile as readFile16, stat as stat4 } from "node:fs/promises";
|
|
40597
|
-
import { createHash as
|
|
40466
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
40598
40467
|
import { join as join45, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
|
|
40599
40468
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
40600
40469
|
var init_codebase_indexer = __esm({
|
|
@@ -40660,7 +40529,7 @@ var init_codebase_indexer = __esm({
|
|
|
40660
40529
|
if (fileStat.size > this.config.maxFileSize)
|
|
40661
40530
|
continue;
|
|
40662
40531
|
const content = await readFile16(fullPath);
|
|
40663
|
-
const hash =
|
|
40532
|
+
const hash = createHash4("sha256").update(content).digest("hex");
|
|
40664
40533
|
const ext = extname10(relativePath);
|
|
40665
40534
|
indexed.push({
|
|
40666
40535
|
path: fullPath,
|
|
@@ -41200,7 +41069,7 @@ var serve_exports = {};
|
|
|
41200
41069
|
__export(serve_exports, {
|
|
41201
41070
|
serveCommand: () => serveCommand
|
|
41202
41071
|
});
|
|
41203
|
-
import { spawn as
|
|
41072
|
+
import { spawn as spawn15 } from "node:child_process";
|
|
41204
41073
|
async function serveCommand(opts, config) {
|
|
41205
41074
|
const backendType = config.backendType;
|
|
41206
41075
|
if (backendType === "ollama") {
|
|
@@ -41293,7 +41162,7 @@ async function serveVllm(opts, config) {
|
|
|
41293
41162
|
}
|
|
41294
41163
|
async function runVllmServer(args, verbose) {
|
|
41295
41164
|
return new Promise((resolve31, reject) => {
|
|
41296
|
-
const child =
|
|
41165
|
+
const child = spawn15("python", args, {
|
|
41297
41166
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
41298
41167
|
env: { ...process.env }
|
|
41299
41168
|
});
|