open-agents-ai 0.71.4 → 0.71.6

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.
Files changed (2) hide show
  1. package/dist/index.js +514 -621
  2. 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
- async function loadNexus() {
11175
- if (!nexusMod) {
11176
- try {
11177
- nexusMod = await import("open-agents-nexus");
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 nexusMod;
11179
+ return false;
11191
11180
  }
11192
- function deriveEncryptionKey(password, salt) {
11193
- return scryptSync(password, salt, KEY_LEN, {
11194
- N: SCRYPT_N,
11195
- r: SCRYPT_R,
11196
- p: SCRYPT_P
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
- function encryptKey(privateKeyHex, password) {
11200
- const salt = randomBytes6(32);
11201
- const key = deriveEncryptionKey(password, salt);
11202
- const iv = randomBytes6(16);
11203
- const cipher = createCipheriv(WALLET_ALGO, key, iv);
11204
- let encrypted = cipher.update(privateKeyHex, "utf8", "hex");
11205
- encrypted += cipher.final("hex");
11206
- const authTag = cipher.getAuthTag();
11207
- return {
11208
- encrypted,
11209
- iv: iv.toString("hex"),
11210
- authTag: authTag.toString("hex"),
11211
- salt: salt.toString("hex")
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
- function runInferenceBenchmark(repoRoot) {
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
- const psRaw = execSync20("ollama ps 2>/dev/null", { timeout: 1e4, encoding: "utf8" });
11217
- const lines = psRaw.trim().split("\n").filter((l) => l.trim());
11218
- if (lines.length < 2)
11219
- return null;
11220
- const modelLine = lines[1];
11221
- const parts = modelLine.split(/\s+/);
11222
- const modelName = parts[0] || "unknown";
11223
- const startTime = Date.now();
11224
- const benchPrompt = "Count from 1 to 50, one number per line:";
11225
- let benchResult;
11226
- try {
11227
- benchResult = execSync20(`echo "${benchPrompt}" | ollama run ${modelName} --nowordwrap 2>/dev/null`, { timeout: 3e4, encoding: "utf8" });
11228
- } catch {
11229
- benchResult = "";
11230
- }
11231
- const elapsed = (Date.now() - startTime) / 1e3;
11232
- const tokenEstimate = benchResult.split(/\s+/).length;
11233
- const tps = elapsed > 0 ? Math.round(tokenEstimate / elapsed) : 0;
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
- if (rocmSmi.includes("Total")) {
11251
- gpuName = "AMD GPU";
11252
- const match = rocmSmi.match(/Total Memory.*?(\d+)/);
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
- const nonce = randomBytes6(16).toString("hex");
11259
- const hashInput = `${modelName}:${tps}:${elapsed}:${tokenEstimate}:${nonce}`;
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
- function containsKeyMaterial(input) {
11317
+
11318
+ // Command polling loop \u2014 check for cmd.json every 500ms
11319
+ let lastCmdId = '';
11320
+ setInterval(() => {
11281
11321
  try {
11282
- const { X402PaymentRail } = __require("open-agents-nexus");
11283
- if (X402PaymentRail.containsKeyMaterial(input))
11284
- return true;
11285
- } catch {
11286
- }
11287
- for (const pattern of KEY_PATTERNS) {
11288
- if (pattern.test(input)) {
11289
- if (pattern.source === "[0-9a-fA-F]{64}") {
11290
- const lower = input.toLowerCase();
11291
- if (lower.includes("key") || lower.includes("private") || lower.includes("secret") || lower.includes("wallet")) {
11292
- return true;
11293
- }
11294
- continue;
11295
- }
11296
- return true;
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
- return false;
11300
- }
11301
- var nexusMod, WALLET_ALGO, SCRYPT_N, SCRYPT_R, SCRYPT_P, KEY_LEN, KEY_PATTERNS, clientInstance, activeRooms, registeredServices, connectionPeerId, NexusTool;
11302
- var init_nexus = __esm({
11303
- "packages/execution/dist/tools/nexus.js"() {
11304
- "use strict";
11305
- nexusMod = null;
11306
- WALLET_ALGO = "aes-256-gcm";
11307
- SCRYPT_N = 16384;
11308
- SCRYPT_R = 8;
11309
- SCRYPT_P = 1;
11310
- KEY_LEN = 32;
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
- // PEM private key
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. Everything else is automatic. Also supports peer discovery, IPFS storage, x402 micropayments, and inference proofs. Wallet keys are NEVER exposed \u2014 only public address and balance visible.";
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
- "list_rooms",
11381
+ "read_messages",
11343
11382
  "discover_peers",
11344
- "find_agent",
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.doJoinRoom(args);
11441
+ result = await this.sendDaemonCmd("join_room", args);
11443
11442
  break;
11444
11443
  case "leave_room":
11445
- result = await this.doLeaveRoom(args);
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 "list_rooms":
11451
- result = await this.doListRooms();
11449
+ case "read_messages":
11450
+ result = await this.doReadMessages(args);
11452
11451
  break;
11453
11452
  case "discover_peers":
11454
- result = await this.doDiscoverPeers();
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 "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,391 @@ 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
- // Action implementations
11476
+ // Daemon management
11500
11477
  // =========================================================================
11501
- async doConnect(args) {
11502
- if (clientInstance) {
11503
- return `Already connected as ${connectionPeerId}. Use 'disconnect' first to reconnect.`;
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
- await this.ensureDir();
11506
- const nexus = await loadNexus();
11507
- const agentName = args.agent_name || "open-agents-node";
11508
- const agentType = args.agent_type || "general";
11509
- const keyPath = join28(this.nexusDir, "identity.key");
11510
- let walletAddress;
11511
- const walletPath = join28(this.nexusDir, "wallet.enc");
11512
- if (existsSync21(walletPath)) {
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 walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11515
- walletAddress = walletData.address;
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
- const client = new nexus.NexusClient({
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();
11513
+ return "Daemon did not respond within 15s. It may still be processing.";
11514
+ }
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}).`;
11531
+ }
11532
+ const nodeModulesDir = resolve26(this.repoRoot, "node_modules");
11533
+ let nexusResolved = false;
11529
11534
  try {
11530
- const node = client.network?.node;
11531
- if (node && typeof node.start === "function" && !node.isStarted?.()) {
11532
- await node.start();
11535
+ const nexusPkg = join28(nodeModulesDir, "open-agents-nexus", "package.json");
11536
+ if (existsSync21(nexusPkg)) {
11537
+ nexusResolved = true;
11538
+ } else {
11539
+ const globalDir = execSync20("npm root -g", { encoding: "utf8", timeout: 5e3 }).trim();
11540
+ if (existsSync21(join28(globalDir, "open-agents-nexus", "package.json"))) {
11541
+ nexusResolved = true;
11542
+ }
11533
11543
  }
11534
11544
  } catch {
11535
11545
  }
11536
- clientInstance = client;
11537
- connectionPeerId = client.peerId;
11538
- await writeFile12(join28(this.nexusDir, "connection.json"), JSON.stringify({
11539
- peerId: connectionPeerId,
11540
- agentName,
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");
11555
- }
11556
- async doDisconnect() {
11557
- if (!clientInstance) {
11558
- return "Not connected to nexus network.";
11559
- }
11560
- for (const [roomId, room] of activeRooms) {
11546
+ if (!nexusResolved) {
11561
11547
  try {
11562
- await room.leave();
11548
+ execSync20("npm install open-agents-nexus@latest 2>&1", {
11549
+ cwd: this.repoRoot,
11550
+ stdio: "pipe",
11551
+ timeout: 12e4
11552
+ });
11563
11553
  } catch {
11554
+ try {
11555
+ execSync20("npm install -g open-agents-nexus@latest 2>&1", { stdio: "pipe", timeout: 12e4 });
11556
+ } catch {
11557
+ throw new Error("Failed to install open-agents-nexus. Run: npm install open-agents-nexus");
11558
+ }
11564
11559
  }
11565
11560
  }
11566
- activeRooms.clear();
11567
- await clientInstance.disconnect();
11568
- clientInstance = null;
11569
- const pid = connectionPeerId;
11570
- connectionPeerId = "";
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
- });
11561
+ const daemonPath = join28(this.nexusDir, "nexus-daemon.mjs");
11562
+ await writeFile12(daemonPath, DAEMON_SCRIPT);
11563
+ const agentName = args.agent_name || "open-agents-node";
11564
+ const agentType = args.agent_type || "general";
11565
+ const nodePaths = [nodeModulesDir];
11566
+ try {
11567
+ const globalDir = execSync20("npm root -g", { encoding: "utf8", timeout: 5e3 }).trim();
11568
+ nodePaths.push(globalDir);
11569
+ } catch {
11576
11570
  }
11577
- return `Disconnected from nexus network. (was: ${pid})`;
11578
- }
11579
- async doStatus() {
11580
- if (!clientInstance) {
11581
- return "Not connected. Use action 'connect' to join the nexus network.";
11571
+ const child = spawn10("node", [daemonPath, this.nexusDir, agentName, agentType], {
11572
+ detached: true,
11573
+ stdio: ["ignore", "pipe", "pipe"],
11574
+ cwd: this.repoRoot,
11575
+ env: { ...process.env, NODE_PATH: nodePaths.join(":") }
11576
+ });
11577
+ child.unref();
11578
+ let earlyOutput = "";
11579
+ let earlyError = "";
11580
+ child.stdout?.on("data", (d) => {
11581
+ earlyOutput += d.toString();
11582
+ });
11583
+ child.stderr?.on("data", (d) => {
11584
+ earlyError += d.toString();
11585
+ });
11586
+ const statusFile = join28(this.nexusDir, "status.json");
11587
+ for (let i = 0; i < 40; i++) {
11588
+ await new Promise((r) => setTimeout(r, 500));
11589
+ if (existsSync21(statusFile)) {
11590
+ try {
11591
+ const status = JSON.parse(await readFile13(statusFile, "utf8"));
11592
+ if (status.error) {
11593
+ return `Nexus daemon failed to connect: ${status.error}`;
11594
+ }
11595
+ if (status.connected && status.peerId) {
11596
+ return [
11597
+ `Connected to nexus P2P network.`,
11598
+ ` Peer ID: ${status.peerId}`,
11599
+ ` Agent: ${agentName} (${agentType})`,
11600
+ ` Daemon PID: ${status.pid}`,
11601
+ ``,
11602
+ `Use join_room to enter a room, then send_message to communicate.`
11603
+ ].join("\n");
11604
+ }
11605
+ } catch {
11606
+ }
11607
+ }
11582
11608
  }
11583
- const stats = clientInstance.getStats();
11584
- const rooms = Array.from(activeRooms.keys());
11585
- let walletInfo = "not configured";
11586
- const walletPath = join28(this.nexusDir, "wallet.enc");
11587
- if (existsSync21(walletPath)) {
11609
+ const pid = this.getDaemonPid();
11610
+ if (pid) {
11611
+ return `Daemon spawned (pid: ${pid}) but still connecting. Check status in a moment.${earlyError ? "\nStderr: " + earlyError.slice(0, 200) : ""}`;
11612
+ }
11613
+ return `Daemon failed to start.${earlyError ? "\n" + earlyError.slice(0, 500) : ""}${earlyOutput ? "\n" + earlyOutput.slice(0, 500) : ""}`;
11614
+ }
11615
+ async doDisconnect() {
11616
+ const pid = this.getDaemonPid();
11617
+ if (!pid)
11618
+ return "Nexus daemon not running.";
11619
+ try {
11620
+ process.kill(pid, "SIGTERM");
11621
+ await new Promise((r) => setTimeout(r, 1e3));
11588
11622
  try {
11589
- const walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11590
- walletInfo = walletData.address;
11623
+ process.kill(pid, 0);
11624
+ process.kill(pid, "SIGKILL");
11591
11625
  } catch {
11592
- walletInfo = "corrupt";
11593
11626
  }
11627
+ } catch {
11594
11628
  }
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(() => {
11629
+ for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
11630
+ const p = join28(this.nexusDir, f);
11631
+ if (existsSync21(p))
11632
+ await unlink(p).catch(() => {
11623
11633
  });
11624
- }).catch(() => {
11625
- });
11626
- });
11627
- return `Joined room: ${roomId}
11628
- Listening for messages. Use send_message to communicate.`;
11634
+ }
11635
+ return `Disconnected from nexus network (killed pid ${pid}).`;
11629
11636
  }
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}`;
11637
+ async doStatus() {
11638
+ const pid = this.getDaemonPid();
11639
+ if (!pid)
11640
+ return "Nexus daemon not running. Use action 'connect' to start.";
11641
+ const statusFile = join28(this.nexusDir, "status.json");
11642
+ if (!existsSync21(statusFile))
11643
+ return `Daemon running (pid: ${pid}) but no status yet.`;
11644
+ try {
11645
+ const status = JSON.parse(await readFile13(statusFile, "utf8"));
11646
+ const lines = [
11647
+ `Nexus Status`,
11648
+ ` Connected: ${status.connected}`,
11649
+ ` Peer ID: ${status.peerId || "n/a"}`,
11650
+ ` Agent: ${status.agentName} (${status.agentType})`,
11651
+ ` Daemon PID: ${status.pid}`,
11652
+ ` Rooms: ${status.rooms?.length || 0} [${(status.rooms || []).join(", ")}]`
11653
+ ];
11654
+ const walletPath = join28(this.nexusDir, "wallet.enc");
11655
+ if (existsSync21(walletPath)) {
11656
+ try {
11657
+ const w = JSON.parse(await readFile13(walletPath, "utf8"));
11658
+ lines.push(` Wallet: ${w.address}`);
11659
+ } catch {
11660
+ lines.push(` Wallet: corrupt`);
11661
+ }
11662
+ } else {
11663
+ lines.push(` Wallet: not configured`);
11664
+ }
11665
+ const inboxDir = join28(this.nexusDir, "inbox");
11666
+ if (existsSync21(inboxDir)) {
11667
+ try {
11668
+ const roomDirs = await readdir3(inboxDir);
11669
+ let totalMsgs = 0;
11670
+ for (const rd of roomDirs) {
11671
+ try {
11672
+ totalMsgs += (await readdir3(join28(inboxDir, rd))).length;
11673
+ } catch {
11674
+ }
11675
+ }
11676
+ lines.push(` Inbox: ${totalMsgs} message(s) across ${roomDirs.length} room(s)`);
11677
+ } catch {
11678
+ }
11679
+ }
11680
+ if (status.error)
11681
+ lines.push(` Error: ${status.error}`);
11682
+ return lines.join("\n");
11683
+ } catch {
11684
+ return `Daemon running (pid: ${pid}) but status file unreadable.`;
11685
+ }
11640
11686
  }
11641
11687
  async doSendMessage(args) {
11642
- if (!clientInstance)
11643
- throw new Error("Not connected. Use 'connect' first.");
11644
- const roomId = args.room_id;
11645
11688
  const message = args.message;
11646
- if (!roomId)
11647
- throw new Error("room_id is required");
11648
11689
  if (!message)
11649
11690
  throw new Error("message is required");
11691
+ if (!args.room_id)
11692
+ throw new Error("room_id is required");
11650
11693
  if (containsKeyMaterial(message)) {
11651
11694
  return [
11652
11695
  "BLOCKED: Message contains potential key material or secrets.",
11653
- "For security, messages containing private keys, wallet secrets,",
11654
- "or sensitive cryptographic material cannot be sent over the network.",
11655
- "Please remove the sensitive content and try again."
11696
+ "Messages containing private keys or sensitive cryptographic material",
11697
+ "cannot be sent over the network. Remove the sensitive content and retry."
11656
11698
  ].join("\n");
11657
11699
  }
11658
- const room = activeRooms.get(roomId);
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})`;
11700
+ return this.sendDaemonCmd("send_message", args);
11663
11701
  }
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
- }
11678
- }
11679
- async doDiscoverPeers() {
11680
- if (!clientInstance)
11681
- throw new Error("Not connected. Use 'connect' first.");
11682
- try {
11683
- const node = clientInstance.network?.node;
11684
- if (!node)
11685
- return "Network node not available yet.";
11686
- const peers = node.getPeers ? node.getPeers() : [];
11687
- if (peers.length === 0) {
11688
- return "No peers discovered yet. The network may still be bootstrapping. Try again in a few seconds.";
11689
- }
11690
- const lines = [`Discovered ${peers.length} peer(s):`];
11691
- for (const peerId of peers.slice(0, 20)) {
11692
- const pid = peerId.toString ? peerId.toString() : String(peerId);
11702
+ async doReadMessages(args) {
11703
+ const roomId = args.room_id;
11704
+ const inboxDir = join28(this.nexusDir, "inbox");
11705
+ if (roomId) {
11706
+ const roomInbox = join28(inboxDir, roomId);
11707
+ if (!existsSync21(roomInbox))
11708
+ return `No messages in room: ${roomId}`;
11709
+ const files = (await readdir3(roomInbox)).sort().slice(-20);
11710
+ if (files.length === 0)
11711
+ return `No messages in room: ${roomId}`;
11712
+ const messages = [`Messages in ${roomId} (last ${files.length}):`];
11713
+ for (const f of files) {
11693
11714
  try {
11694
- const profile = await clientInstance.findAgent(pid);
11695
- if (profile) {
11696
- lines.push(` ${pid.slice(0, 16)}... \u2014 ${profile.name} (${profile.type}) [${profile.capabilities?.length || 0} capabilities]`);
11697
- } else {
11698
- lines.push(` ${pid.slice(0, 16)}... \u2014 (no profile)`);
11699
- }
11715
+ const msg = JSON.parse(await readFile13(join28(roomInbox, f), "utf8"));
11716
+ const sender = (msg.sender || "unknown").slice(0, 12);
11717
+ messages.push(` [${new Date(msg.timestamp).toLocaleTimeString()}] ${sender}...: ${msg.content}`);
11700
11718
  } catch {
11701
- lines.push(` ${pid.slice(0, 16)}... \u2014 (lookup failed)`);
11702
11719
  }
11703
11720
  }
11704
- if (peers.length > 20) {
11705
- lines.push(` ... and ${peers.length - 20} more`);
11706
- }
11707
- return lines.join("\n");
11708
- } catch (err) {
11709
- return `Peer discovery error: ${err.message}`;
11710
- }
11711
- }
11712
- async doFindAgent(args) {
11713
- if (!clientInstance)
11714
- throw new Error("Not connected. Use 'connect' first.");
11715
- const peerId = args.peer_id;
11716
- if (!peerId)
11717
- throw new Error("peer_id is required");
11718
- const profile = await clientInstance.findAgent(peerId);
11719
- if (!profile) {
11720
- return `Agent not found: ${peerId}`;
11721
+ return messages.join("\n");
11721
11722
  }
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)) {
11723
+ if (!existsSync21(inboxDir))
11724
+ return "No messages received yet.";
11725
+ const roomDirs = await readdir3(inboxDir);
11726
+ if (roomDirs.length === 0)
11727
+ return "No messages received yet.";
11728
+ const lines = ["Inbox:"];
11729
+ for (const rd of roomDirs) {
11746
11730
  try {
11747
- const walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11748
- walletAddress = walletData.address;
11731
+ const count = (await readdir3(join28(inboxDir, rd))).length;
11732
+ lines.push(` ${rd}: ${count} message(s)`);
11749
11733
  } catch {
11750
11734
  }
11751
11735
  }
11752
- if (!walletAddress) {
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")}`;
11736
+ return lines.join("\n");
11794
11737
  }
11795
11738
  async doWalletStatus() {
11796
11739
  await this.ensureDir();
11797
11740
  const walletPath = join28(this.nexusDir, "wallet.enc");
11798
11741
  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");
11742
+ return "No wallet configured. Use wallet_create to set one up.";
11804
11743
  }
11805
11744
  try {
11806
- const walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11745
+ const w = JSON.parse(await readFile13(walletPath, "utf8"));
11807
11746
  return [
11808
11747
  `Wallet Status:`,
11809
- ` Address: ${walletData.address}`,
11810
- ` Created: ${walletData.createdAt}`,
11748
+ ` Address: ${w.address}`,
11749
+ ` Created: ${w.createdAt}`,
11811
11750
  ` Encryption: AES-256-GCM + scrypt`,
11812
- ` Key file: ${walletPath} (0600)`,
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.`
11751
+ ` NOTE: Private key is encrypted and NEVER accessible to the agent.`
11817
11752
  ].join("\n");
11818
11753
  } catch {
11819
- return "Wallet file exists but could not be read. It may be corrupted.";
11754
+ return "Wallet file exists but could not be read.";
11820
11755
  }
11821
11756
  }
11822
11757
  async doWalletCreate(args) {
11823
11758
  await this.ensureDir();
11824
11759
  const walletPath = join28(this.nexusDir, "wallet.enc");
11825
- if (existsSync21(walletPath)) {
11826
- return "Wallet already exists. To create a new one, delete .oa/nexus/wallet.enc first.";
11827
- }
11760
+ if (existsSync21(walletPath))
11761
+ return "Wallet already exists.";
11828
11762
  const userAddress = args.wallet_address;
11829
11763
  if (userAddress) {
11830
11764
  if (!/^0x[0-9a-fA-F]{40}$/.test(userAddress)) {
11831
- return "Invalid wallet address format. Expected Ethereum address (0x + 40 hex chars).";
11765
+ return "Invalid address format. Expected 0x + 40 hex chars.";
11832
11766
  }
11833
- const walletData2 = {
11767
+ const w2 = {
11834
11768
  version: 1,
11835
11769
  address: userAddress,
11836
11770
  encryptedKey: "",
11837
- // user-managed key
11838
11771
  iv: "",
11839
11772
  authTag: "",
11840
11773
  salt: "",
11841
11774
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
11842
11775
  };
11843
- await writeFile12(walletPath, JSON.stringify(walletData2, null, 2));
11776
+ await writeFile12(walletPath, JSON.stringify(w2, null, 2));
11844
11777
  await chmod(walletPath, 384);
11845
- return [
11846
- `Wallet configured with user-provided address.`,
11847
- ` Address: ${userAddress}`,
11848
- ` Key management: user-managed (external wallet)`,
11849
- ` File: ${walletPath}`,
11850
- ``,
11851
- `This address will be used for receiving x402 payments.`,
11852
- `Outbound payments require the agent to have signing capability,`,
11853
- `which is not available with an external address.`
11854
- ].join("\n");
11855
- }
11856
- const privateKeyBytes = randomBytes6(32);
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 = {
11778
+ return `Wallet configured: ${userAddress} (user-managed)`;
11779
+ }
11780
+ const privKey = randomBytes6(32);
11781
+ const address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
11782
+ const salt = randomBytes6(32);
11783
+ const key = scryptSync(`${__require("node:os").hostname()}:${__require("node:os").userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
11784
+ const iv = randomBytes6(16);
11785
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
11786
+ let enc = cipher.update(privKey.toString("hex"), "utf8", "hex");
11787
+ enc += cipher.final("hex");
11788
+ privKey.fill(0);
11789
+ const w = {
11870
11790
  version: 1,
11871
11791
  address,
11872
- encryptedKey: encrypted,
11873
- iv,
11874
- authTag,
11875
- salt,
11792
+ encryptedKey: enc,
11793
+ iv: iv.toString("hex"),
11794
+ authTag: cipher.getAuthTag().toString("hex"),
11795
+ salt: salt.toString("hex"),
11876
11796
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
11877
11797
  };
11878
- await writeFile12(walletPath, JSON.stringify(walletData, null, 2));
11798
+ await writeFile12(walletPath, JSON.stringify(w, null, 2));
11879
11799
  await chmod(walletPath, 384);
11880
11800
  return [
11881
- `Wallet created successfully.`,
11882
- ` Address: ${address}`,
11883
- ` Encryption: AES-256-GCM with scrypt key derivation`,
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`
11801
+ `Wallet created: ${address}`,
11802
+ ` Encrypted with AES-256-GCM (key NEVER visible to agent)`,
11803
+ ` File: ${walletPath} (0600)`
11892
11804
  ].join("\n");
11893
11805
  }
11894
11806
  async doInferenceProof() {
11895
- const proof = runInferenceBenchmark(this.repoRoot);
11896
- if (!proof) {
11807
+ try {
11808
+ const psRaw = execSync20("ollama ps 2>/dev/null", { timeout: 1e4, encoding: "utf8" });
11809
+ const lines = psRaw.trim().split("\n").filter((l) => l.trim());
11810
+ if (lines.length < 2)
11811
+ return "No model loaded. Run 'ollama ps' to check.";
11812
+ const parts = lines[1].split(/\s+/);
11813
+ const modelName = parts[0] || "unknown";
11814
+ let gpuName = "none", vramMb = 0;
11815
+ try {
11816
+ const smi = execSync20("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null", {
11817
+ timeout: 5e3,
11818
+ encoding: "utf8"
11819
+ });
11820
+ const gp = smi.trim().split(",");
11821
+ gpuName = gp[0]?.trim() || "unknown";
11822
+ vramMb = parseInt(gp[1]?.trim() || "0", 10);
11823
+ } catch {
11824
+ try {
11825
+ execSync20("rocm-smi 2>/dev/null", { timeout: 5e3 });
11826
+ gpuName = "AMD GPU";
11827
+ } catch {
11828
+ }
11829
+ }
11830
+ const nonce = randomBytes6(16).toString("hex");
11831
+ const hash = createHash("sha256").update(`${modelName}:${nonce}:${Date.now()}`).digest("hex");
11832
+ const bar = (s) => "\u2588".repeat(Math.round(s / 5)) + "\u2591".repeat(20 - Math.round(s / 5));
11833
+ const mem = vramMb > 24e3 ? 95 : vramMb > 16e3 ? 80 : vramMb > 8e3 ? 60 : vramMb > 0 ? 40 : 20;
11834
+ await this.ensureDir();
11835
+ await writeFile12(join28(this.nexusDir, "inference-proof.json"), JSON.stringify({
11836
+ modelName,
11837
+ gpuName,
11838
+ vramMb,
11839
+ hash,
11840
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
11841
+ }, null, 2));
11897
11842
  return [
11898
- "Could not generate inference proof.",
11899
- "Ensure Ollama is running with a loaded model (ollama ps)."
11843
+ `Inference Capability Proof`,
11844
+ ` Model: ${modelName} (${parts[1] || "?"})`,
11845
+ ` GPU: ${gpuName} (${vramMb} MB)`,
11846
+ ` Memory [${bar(mem)}] ${mem}%`,
11847
+ ` Hash: ${hash.slice(0, 16)}...`
11900
11848
  ].join("\n");
11849
+ } catch {
11850
+ return "Could not generate proof. Ensure Ollama is running.";
11901
11851
  }
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
11852
  }
11960
11853
  };
11961
11854
  }
@@ -13215,7 +13108,7 @@ var init_code_retriever = __esm({
13215
13108
  // packages/retrieval/dist/lexicalSearch.js
13216
13109
  import { execFile as execFile5 } from "node:child_process";
13217
13110
  import { promisify as promisify4 } from "node:util";
13218
- import { readFile as readFile14, readdir as readdir3, stat as stat3 } from "node:fs/promises";
13111
+ import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "node:fs/promises";
13219
13112
  import { join as join29, extname as extname7 } from "node:path";
13220
13113
  async function searchByPath(pathPattern, options) {
13221
13114
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
@@ -13349,7 +13242,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
13349
13242
  async function walkForFiles(rootDir, dir, excludeGlobs, results) {
13350
13243
  let entries;
13351
13244
  try {
13352
- entries = await readdir3(dir, { withFileTypes: true, encoding: "utf-8" });
13245
+ entries = await readdir4(dir, { withFileTypes: true, encoding: "utf-8" });
13353
13246
  } catch {
13354
13247
  return;
13355
13248
  }
@@ -17770,7 +17663,7 @@ __export(listen_exports, {
17770
17663
  isVideoPath: () => isVideoPath,
17771
17664
  waitForTranscribeCli: () => waitForTranscribeCli
17772
17665
  });
17773
- import { spawn as spawn10, execSync as execSync21 } from "node:child_process";
17666
+ import { spawn as spawn11, execSync as execSync21 } from "node:child_process";
17774
17667
  import { existsSync as existsSync22, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6 } from "node:fs";
17775
17668
  import { join as join31, dirname as dirname10 } from "node:path";
17776
17669
  import { homedir as homedir8 } from "node:os";
@@ -17980,7 +17873,7 @@ var init_listen = __esm({
17980
17873
  const timeout = setTimeout(() => {
17981
17874
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
17982
17875
  }, 3e5);
17983
- this.process = spawn10("python3", [
17876
+ this.process = spawn11("python3", [
17984
17877
  this.scriptPath,
17985
17878
  "--model",
17986
17879
  this.model,
@@ -18262,7 +18155,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
18262
18155
  return `Failed to start live transcription: ${msg}${tcHint}`;
18263
18156
  }
18264
18157
  }
18265
- this.micProcess = spawn10(micCmd.cmd, micCmd.args, {
18158
+ this.micProcess = spawn11(micCmd.cmd, micCmd.args, {
18266
18159
  stdio: ["pipe", "pipe", "pipe"],
18267
18160
  env: { ...process.env }
18268
18161
  });
@@ -20681,7 +20574,7 @@ var require_websocket = __commonJS({
20681
20574
  var http = __require("http");
20682
20575
  var net = __require("net");
20683
20576
  var tls = __require("tls");
20684
- var { randomBytes: randomBytes10, createHash: createHash4 } = __require("crypto");
20577
+ var { randomBytes: randomBytes10, createHash: createHash5 } = __require("crypto");
20685
20578
  var { Duplex, Readable } = __require("stream");
20686
20579
  var { URL: URL3 } = __require("url");
20687
20580
  var PerMessageDeflate = require_permessage_deflate();
@@ -21341,7 +21234,7 @@ var require_websocket = __commonJS({
21341
21234
  abortHandshake(websocket, socket, "Invalid Upgrade header");
21342
21235
  return;
21343
21236
  }
21344
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
21237
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
21345
21238
  if (res.headers["sec-websocket-accept"] !== digest) {
21346
21239
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
21347
21240
  return;
@@ -21708,7 +21601,7 @@ var require_websocket_server = __commonJS({
21708
21601
  var EventEmitter7 = __require("events");
21709
21602
  var http = __require("http");
21710
21603
  var { Duplex } = __require("stream");
21711
- var { createHash: createHash4 } = __require("crypto");
21604
+ var { createHash: createHash5 } = __require("crypto");
21712
21605
  var extension = require_extension();
21713
21606
  var PerMessageDeflate = require_permessage_deflate();
21714
21607
  var subprotocol = require_subprotocol();
@@ -22009,7 +21902,7 @@ var require_websocket_server = __commonJS({
22009
21902
  );
22010
21903
  }
22011
21904
  if (this._state > RUNNING) return abortHandshake(socket, 503);
22012
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
21905
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
22013
21906
  const headers = [
22014
21907
  "HTTP/1.1 101 Switching Protocols",
22015
21908
  "Upgrade: websocket",
@@ -22998,7 +22891,7 @@ var init_render = __esm({
22998
22891
 
22999
22892
  // packages/cli/dist/tui/voice-session.js
23000
22893
  import { createServer } from "node:http";
23001
- import { spawn as spawn11, execSync as execSync22 } from "node:child_process";
22894
+ import { spawn as spawn12, execSync as execSync22 } from "node:child_process";
23002
22895
  import { EventEmitter as EventEmitter2 } from "node:events";
23003
22896
  function generateFrontendHTML() {
23004
22897
  return `<!DOCTYPE html>
@@ -23652,7 +23545,7 @@ var init_voice_session = __esm({
23652
23545
  const timeout = setTimeout(() => {
23653
23546
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
23654
23547
  }, 3e4);
23655
- this.cloudflaredProcess = spawn11("cloudflared", [
23548
+ this.cloudflaredProcess = spawn12("cloudflared", [
23656
23549
  "tunnel",
23657
23550
  "--url",
23658
23551
  `http://127.0.0.1:${port}`
@@ -23726,7 +23619,7 @@ var init_voice_session = __esm({
23726
23619
 
23727
23620
  // packages/cli/dist/tui/expose.js
23728
23621
  import { createServer as createServer2, request as httpRequest } from "node:http";
23729
- import { spawn as spawn12 } from "node:child_process";
23622
+ import { spawn as spawn13 } from "node:child_process";
23730
23623
  import { EventEmitter as EventEmitter3 } from "node:events";
23731
23624
  import { randomBytes as randomBytes7 } from "node:crypto";
23732
23625
  import { URL as URL2 } from "node:url";
@@ -23902,7 +23795,7 @@ var init_expose = __esm({
23902
23795
  const timeout = setTimeout(() => {
23903
23796
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
23904
23797
  }, 3e4);
23905
- this.cloudflaredProcess = spawn12("cloudflared", [
23798
+ this.cloudflaredProcess = spawn13("cloudflared", [
23906
23799
  "tunnel",
23907
23800
  "--url",
23908
23801
  `http://127.0.0.1:${port}`
@@ -24004,10 +23897,10 @@ var init_types = __esm({
24004
23897
  });
24005
23898
 
24006
23899
  // 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";
23900
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
24008
23901
  import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, existsSync as existsSync23, mkdirSync as mkdirSync7 } from "node:fs";
24009
23902
  import { join as join32, dirname as dirname11 } from "node:path";
24010
- var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN2, SecretVault;
23903
+ var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
24011
23904
  var init_secret_vault = __esm({
24012
23905
  "packages/cli/dist/tui/p2p/secret-vault.js"() {
24013
23906
  "use strict";
@@ -24017,7 +23910,7 @@ var init_secret_vault = __esm({
24017
23910
  CIPHER_ALGO = "aes-256-gcm";
24018
23911
  SALT_LEN = 16;
24019
23912
  IV_LEN = 12;
24020
- KEY_LEN2 = 32;
23913
+ KEY_LEN = 32;
24021
23914
  SecretVault = class {
24022
23915
  storePath;
24023
23916
  secrets = /* @__PURE__ */ new Map();
@@ -24211,7 +24104,7 @@ var init_secret_vault = __esm({
24211
24104
  createdAt: s.createdAt
24212
24105
  })));
24213
24106
  const salt = randomBytes8(SALT_LEN);
24214
- const key = scryptSync2(passphrase, salt, KEY_LEN2);
24107
+ const key = scryptSync2(passphrase, salt, KEY_LEN);
24215
24108
  const iv = randomBytes8(IV_LEN);
24216
24109
  const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
24217
24110
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
@@ -24237,7 +24130,7 @@ var init_secret_vault = __esm({
24237
24130
  const iv = blob.subarray(SALT_LEN, SALT_LEN + IV_LEN);
24238
24131
  const tag = blob.subarray(SALT_LEN + IV_LEN, SALT_LEN + IV_LEN + 16);
24239
24132
  const encrypted = blob.subarray(SALT_LEN + IV_LEN + 16);
24240
- const key = scryptSync2(passphrase, salt, KEY_LEN2);
24133
+ const key = scryptSync2(passphrase, salt, KEY_LEN);
24241
24134
  const decipher = createDecipheriv2(CIPHER_ALGO, key, iv);
24242
24135
  decipher.setAuthTag(tag);
24243
24136
  let data;
@@ -24255,7 +24148,7 @@ var init_secret_vault = __esm({
24255
24148
  /** Generate a deterministic fingerprint of vault contents (for sync verification) */
24256
24149
  fingerprint() {
24257
24150
  const names = Array.from(this.secrets.keys()).sort();
24258
- const hash = createHash("sha256");
24151
+ const hash = createHash2("sha256");
24259
24152
  for (const name of names) {
24260
24153
  hash.update(name + ":");
24261
24154
  hash.update(this.secrets.get(name).value);
@@ -24270,7 +24163,7 @@ var init_secret_vault = __esm({
24270
24163
  // packages/cli/dist/tui/p2p/peer-mesh.js
24271
24164
  import { EventEmitter as EventEmitter4 } from "node:events";
24272
24165
  import { createServer as createServer3 } from "node:http";
24273
- import { randomBytes as randomBytes9, createHash as createHash2, generateKeyPairSync } from "node:crypto";
24166
+ import { randomBytes as randomBytes9, createHash as createHash3, generateKeyPairSync } from "node:crypto";
24274
24167
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
24275
24168
  var init_peer_mesh = __esm({
24276
24169
  "packages/cli/dist/tui/p2p/peer-mesh.js"() {
@@ -24319,7 +24212,7 @@ var init_peer_mesh = __esm({
24319
24212
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
24320
24213
  this.publicKey = publicKey.export({ type: "spki", format: "der" });
24321
24214
  this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
24322
- this.peerId = createHash2("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
24215
+ this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
24323
24216
  this.capabilities = options.capabilities;
24324
24217
  this.displayName = options.displayName;
24325
24218
  this._authKey = options.authKey ?? randomBytes9(24).toString("base64url");
@@ -26037,7 +25930,7 @@ var init_oa_directory = __esm({
26037
25930
 
26038
25931
  // packages/cli/dist/tui/setup.js
26039
25932
  import * as readline from "node:readline";
26040
- import { execSync as execSync23, spawn as spawn13 } from "node:child_process";
25933
+ import { execSync as execSync23, spawn as spawn14 } from "node:child_process";
26041
25934
  import { existsSync as existsSync25, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
26042
25935
  import { join as join35 } from "node:path";
26043
25936
  import { homedir as homedir10, platform } from "node:os";
@@ -26380,7 +26273,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
26380
26273
  process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
26381
26274
  `);
26382
26275
  try {
26383
- const child = spawn13("ollama", ["serve"], { stdio: "ignore", detached: true });
26276
+ const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
26384
26277
  child.unref();
26385
26278
  } catch {
26386
26279
  process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
@@ -26848,7 +26741,7 @@ async function doSetup(config, rl) {
26848
26741
  ${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
26849
26742
  `);
26850
26743
  try {
26851
- const child = spawn13("ollama", ["serve"], { stdio: "ignore", detached: true });
26744
+ const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
26852
26745
  child.unref();
26853
26746
  await new Promise((resolve31) => setTimeout(resolve31, 3e3));
26854
26747
  try {
@@ -26876,7 +26769,7 @@ async function doSetup(config, rl) {
26876
26769
  ${c2.cyan("\u25CF")} Starting ollama serve...
26877
26770
  `);
26878
26771
  try {
26879
- const child = spawn13("ollama", ["serve"], { stdio: "ignore", detached: true });
26772
+ const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
26880
26773
  child.unref();
26881
26774
  await new Promise((resolve31) => setTimeout(resolve31, 3e3));
26882
26775
  try {
@@ -40310,13 +40203,13 @@ NEW TASK: ${fullInput}`;
40310
40203
  writeContent(() => renderError(errMsg));
40311
40204
  if (failureStore) {
40312
40205
  try {
40313
- const { createHash: createHash4 } = await import("node:crypto");
40206
+ const { createHash: createHash5 } = await import("node:crypto");
40314
40207
  failureStore.insert({
40315
40208
  taskId: "",
40316
40209
  sessionId: `${Date.now()}`,
40317
40210
  repoRoot,
40318
40211
  failureType: "runtime-error",
40319
- fingerprint: createHash4("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
40212
+ fingerprint: createHash5("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
40320
40213
  filePath: null,
40321
40214
  errorMessage: errMsg.slice(0, 500),
40322
40215
  context: null,
@@ -40594,7 +40487,7 @@ var init_run = __esm({
40594
40487
  import { glob } from "glob";
40595
40488
  import ignore from "ignore";
40596
40489
  import { readFile as readFile16, stat as stat4 } from "node:fs/promises";
40597
- import { createHash as createHash3 } from "node:crypto";
40490
+ import { createHash as createHash4 } from "node:crypto";
40598
40491
  import { join as join45, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
40599
40492
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
40600
40493
  var init_codebase_indexer = __esm({
@@ -40660,7 +40553,7 @@ var init_codebase_indexer = __esm({
40660
40553
  if (fileStat.size > this.config.maxFileSize)
40661
40554
  continue;
40662
40555
  const content = await readFile16(fullPath);
40663
- const hash = createHash3("sha256").update(content).digest("hex");
40556
+ const hash = createHash4("sha256").update(content).digest("hex");
40664
40557
  const ext = extname10(relativePath);
40665
40558
  indexed.push({
40666
40559
  path: fullPath,
@@ -41200,7 +41093,7 @@ var serve_exports = {};
41200
41093
  __export(serve_exports, {
41201
41094
  serveCommand: () => serveCommand
41202
41095
  });
41203
- import { spawn as spawn14 } from "node:child_process";
41096
+ import { spawn as spawn15 } from "node:child_process";
41204
41097
  async function serveCommand(opts, config) {
41205
41098
  const backendType = config.backendType;
41206
41099
  if (backendType === "ollama") {
@@ -41293,7 +41186,7 @@ async function serveVllm(opts, config) {
41293
41186
  }
41294
41187
  async function runVllmServer(args, verbose) {
41295
41188
  return new Promise((resolve31, reject) => {
41296
- const child = spawn14("python", args, {
41189
+ const child = spawn15("python", args, {
41297
41190
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
41298
41191
  env: { ...process.env }
41299
41192
  });