open-agents-ai 0.71.3 → 0.71.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +492 -616
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -11166,167 +11166,206 @@ ${truncated}`, durationMs: performance.now() - start };
11166
11166
  });
11167
11167
 
11168
11168
  // packages/execution/dist/tools/nexus.js
11169
- import { readFile as readFile13, writeFile as writeFile12, mkdir as mkdir8, chmod } from "node:fs/promises";
11169
+ import { readFile as readFile13, writeFile as writeFile12, mkdir as mkdir8, chmod, unlink, readdir as readdir3 } from "node:fs/promises";
11170
11170
  import { existsSync as existsSync21 } from "node:fs";
11171
11171
  import { resolve as resolve26, join as join28 } from "node:path";
11172
- import { randomBytes as randomBytes6, createCipheriv, createDecipheriv, scryptSync } from "node:crypto";
11173
- import { execSync as execSync20 } from "node:child_process";
11174
- 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 {}
11245
+ }
11246
+
11247
+ function writeResp(id, result) {
11248
+ try { writeFileSync(respFile, JSON.stringify({ id, ...result }, null, 2)); } catch {}
11213
11249
  }
11214
- function runInferenceBenchmark(repoRoot) {
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,484 +11464,367 @@ var init_nexus = __esm({
11471
11464
  case "inference_proof":
11472
11465
  result = await this.doInferenceProof();
11473
11466
  break;
11474
- case "store_content":
11475
- result = await this.doStoreContent(args);
11476
- break;
11477
- case "retrieve_content":
11478
- result = await this.doRetrieveContent(args);
11479
- break;
11480
11467
  default:
11481
- return {
11482
- success: false,
11483
- output: "",
11484
- error: `Unknown nexus action: ${action}`,
11485
- durationMs: Date.now() - start
11486
- };
11468
+ return { success: false, output: "", error: `Unknown nexus action: ${action}`, durationMs: Date.now() - start };
11487
11469
  }
11488
11470
  return { success: true, output: result, durationMs: Date.now() - start };
11489
11471
  } catch (err) {
11490
- return {
11491
- success: false,
11492
- output: "",
11493
- error: err.message || String(err),
11494
- durationMs: Date.now() - start
11495
- };
11472
+ return { success: false, output: "", error: err.message || String(err), durationMs: Date.now() - start };
11496
11473
  }
11497
11474
  }
11498
11475
  // =========================================================================
11499
- // 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();
11529
- clientInstance = client;
11530
- connectionPeerId = client.peerId;
11531
- await writeFile12(join28(this.nexusDir, "connection.json"), JSON.stringify({
11532
- peerId: connectionPeerId,
11533
- agentName,
11534
- agentType,
11535
- connectedAt: (/* @__PURE__ */ new Date()).toISOString(),
11536
- walletAddress: walletAddress || null
11537
- }, null, 2));
11538
- return [
11539
- `Connected to nexus P2P network.`,
11540
- ` Peer ID: ${connectionPeerId}`,
11541
- ` Agent: ${agentName} (${agentType})`,
11542
- ` Role: light`,
11543
- walletAddress ? ` Wallet: ${walletAddress}` : ` Wallet: not configured (use wallet_create)`,
11544
- ` x402 payments: ${walletAddress ? "enabled" : "disabled"}`,
11545
- ``,
11546
- `You can now join rooms, discover peers, and participate in the agent mesh.`
11547
- ].join("\n");
11513
+ return "Daemon did not respond within 15s. It may still be processing.";
11548
11514
  }
11549
- async doDisconnect() {
11550
- if (!clientInstance) {
11551
- return "Not connected to nexus network.";
11515
+ // =========================================================================
11516
+ // Actions
11517
+ // =========================================================================
11518
+ async doConnect(args) {
11519
+ await this.ensureDir();
11520
+ const existingPid = this.getDaemonPid();
11521
+ if (existingPid) {
11522
+ const statusFile2 = join28(this.nexusDir, "status.json");
11523
+ if (existsSync21(statusFile2)) {
11524
+ try {
11525
+ const status = JSON.parse(await readFile13(statusFile2, "utf8"));
11526
+ return `Already connected (pid: ${existingPid}, peerId: ${status.peerId || "starting..."})`;
11527
+ } catch {
11528
+ }
11529
+ }
11530
+ return `Daemon already running (pid: ${existingPid}).`;
11552
11531
  }
11553
- for (const [roomId, room] of activeRooms) {
11532
+ try {
11533
+ execSync20(`node -e "require.resolve('open-agents-nexus')"`, { stdio: "pipe", timeout: 5e3 });
11534
+ } catch {
11554
11535
  try {
11555
- await room.leave();
11536
+ execSync20("npm install -g open-agents-nexus@latest 2>&1 || npm install open-agents-nexus@latest 2>&1", {
11537
+ stdio: "pipe",
11538
+ timeout: 12e4
11539
+ });
11556
11540
  } catch {
11541
+ throw new Error("Failed to install open-agents-nexus. Run: npm install -g open-agents-nexus");
11557
11542
  }
11558
11543
  }
11559
- activeRooms.clear();
11560
- await clientInstance.disconnect();
11561
- clientInstance = null;
11562
- const pid = connectionPeerId;
11563
- connectionPeerId = "";
11564
- const connPath = join28(this.nexusDir, "connection.json");
11565
- if (existsSync21(connPath)) {
11566
- const { unlink } = await import("node:fs/promises");
11567
- await unlink(connPath).catch(() => {
11568
- });
11544
+ const daemonPath = join28(this.nexusDir, "nexus-daemon.mjs");
11545
+ await writeFile12(daemonPath, DAEMON_SCRIPT);
11546
+ const agentName = args.agent_name || "open-agents-node";
11547
+ const agentType = args.agent_type || "general";
11548
+ const child = spawn10("node", [daemonPath, this.nexusDir, agentName, agentType], {
11549
+ detached: true,
11550
+ stdio: ["ignore", "pipe", "pipe"],
11551
+ cwd: this.repoRoot
11552
+ });
11553
+ child.unref();
11554
+ let earlyOutput = "";
11555
+ let earlyError = "";
11556
+ child.stdout?.on("data", (d) => {
11557
+ earlyOutput += d.toString();
11558
+ });
11559
+ child.stderr?.on("data", (d) => {
11560
+ earlyError += d.toString();
11561
+ });
11562
+ const statusFile = join28(this.nexusDir, "status.json");
11563
+ for (let i = 0; i < 40; i++) {
11564
+ await new Promise((r) => setTimeout(r, 500));
11565
+ if (existsSync21(statusFile)) {
11566
+ try {
11567
+ const status = JSON.parse(await readFile13(statusFile, "utf8"));
11568
+ if (status.error) {
11569
+ return `Nexus daemon failed to connect: ${status.error}`;
11570
+ }
11571
+ if (status.connected && status.peerId) {
11572
+ return [
11573
+ `Connected to nexus P2P network.`,
11574
+ ` Peer ID: ${status.peerId}`,
11575
+ ` Agent: ${agentName} (${agentType})`,
11576
+ ` Daemon PID: ${status.pid}`,
11577
+ ``,
11578
+ `Use join_room to enter a room, then send_message to communicate.`
11579
+ ].join("\n");
11580
+ }
11581
+ } catch {
11582
+ }
11583
+ }
11569
11584
  }
11570
- return `Disconnected from nexus network. (was: ${pid})`;
11571
- }
11572
- async doStatus() {
11573
- if (!clientInstance) {
11574
- return "Not connected. Use action 'connect' to join the nexus network.";
11585
+ const pid = this.getDaemonPid();
11586
+ if (pid) {
11587
+ return `Daemon spawned (pid: ${pid}) but still connecting. Check status in a moment.${earlyError ? "\nStderr: " + earlyError.slice(0, 200) : ""}`;
11575
11588
  }
11576
- const stats = clientInstance.getStats();
11577
- const rooms = Array.from(activeRooms.keys());
11578
- let walletInfo = "not configured";
11579
- const walletPath = join28(this.nexusDir, "wallet.enc");
11580
- if (existsSync21(walletPath)) {
11589
+ return `Daemon failed to start.${earlyError ? "\n" + earlyError.slice(0, 500) : ""}${earlyOutput ? "\n" + earlyOutput.slice(0, 500) : ""}`;
11590
+ }
11591
+ async doDisconnect() {
11592
+ const pid = this.getDaemonPid();
11593
+ if (!pid)
11594
+ return "Nexus daemon not running.";
11595
+ try {
11596
+ process.kill(pid, "SIGTERM");
11597
+ await new Promise((r) => setTimeout(r, 1e3));
11581
11598
  try {
11582
- const walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11583
- walletInfo = walletData.address;
11599
+ process.kill(pid, 0);
11600
+ process.kill(pid, "SIGKILL");
11584
11601
  } catch {
11585
- walletInfo = "corrupt";
11586
11602
  }
11603
+ } catch {
11587
11604
  }
11588
- return [
11589
- `Nexus Network Status`,
11590
- ` Connected: true`,
11591
- ` Peer ID: ${connectionPeerId}`,
11592
- ` Rooms joined: ${rooms.length} [${rooms.join(", ")}]`,
11593
- ` Content pinned: ${stats.totalPinned} (${stats.pinnedFromOthers} from others)`,
11594
- ` Tracked CIDs: ${stats.trackedCids}`,
11595
- ` Registered services: ${registeredServices.length}`,
11596
- ` Wallet: ${walletInfo}`,
11597
- ` x402: ${clientInstance.x402?.isEnabled ? "enabled" : "disabled"}`
11598
- ].join("\n");
11599
- }
11600
- async doJoinRoom(args) {
11601
- if (!clientInstance)
11602
- throw new Error("Not connected. Use 'connect' first.");
11603
- const roomId = args.room_id;
11604
- if (!roomId)
11605
- throw new Error("room_id is required");
11606
- if (activeRooms.has(roomId)) {
11607
- return `Already in room: ${roomId}`;
11608
- }
11609
- const room = await clientInstance.joinRoom(roomId);
11610
- activeRooms.set(roomId, room);
11611
- room.on("message", (msg) => {
11612
- const msgDir = join28(this.nexusDir, "messages", roomId);
11613
- mkdir8(msgDir, { recursive: true }).then(() => {
11614
- const filename = `${msg.id || Date.now()}.json`;
11615
- writeFile12(join28(msgDir, filename), JSON.stringify(msg, null, 2)).catch(() => {
11605
+ for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
11606
+ const p = join28(this.nexusDir, f);
11607
+ if (existsSync21(p))
11608
+ await unlink(p).catch(() => {
11616
11609
  });
11617
- }).catch(() => {
11618
- });
11619
- });
11620
- return `Joined room: ${roomId}
11621
- Listening for messages. Use send_message to communicate.`;
11610
+ }
11611
+ return `Disconnected from nexus network (killed pid ${pid}).`;
11622
11612
  }
11623
- async doLeaveRoom(args) {
11624
- const roomId = args.room_id;
11625
- if (!roomId)
11626
- throw new Error("room_id is required");
11627
- const room = activeRooms.get(roomId);
11628
- if (!room)
11629
- return `Not in room: ${roomId}`;
11630
- await room.leave();
11631
- activeRooms.delete(roomId);
11632
- return `Left room: ${roomId}`;
11613
+ async doStatus() {
11614
+ const pid = this.getDaemonPid();
11615
+ if (!pid)
11616
+ return "Nexus daemon not running. Use action 'connect' to start.";
11617
+ const statusFile = join28(this.nexusDir, "status.json");
11618
+ if (!existsSync21(statusFile))
11619
+ return `Daemon running (pid: ${pid}) but no status yet.`;
11620
+ try {
11621
+ const status = JSON.parse(await readFile13(statusFile, "utf8"));
11622
+ const lines = [
11623
+ `Nexus Status`,
11624
+ ` Connected: ${status.connected}`,
11625
+ ` Peer ID: ${status.peerId || "n/a"}`,
11626
+ ` Agent: ${status.agentName} (${status.agentType})`,
11627
+ ` Daemon PID: ${status.pid}`,
11628
+ ` Rooms: ${status.rooms?.length || 0} [${(status.rooms || []).join(", ")}]`
11629
+ ];
11630
+ const walletPath = join28(this.nexusDir, "wallet.enc");
11631
+ if (existsSync21(walletPath)) {
11632
+ try {
11633
+ const w = JSON.parse(await readFile13(walletPath, "utf8"));
11634
+ lines.push(` Wallet: ${w.address}`);
11635
+ } catch {
11636
+ lines.push(` Wallet: corrupt`);
11637
+ }
11638
+ } else {
11639
+ lines.push(` Wallet: not configured`);
11640
+ }
11641
+ const inboxDir = join28(this.nexusDir, "inbox");
11642
+ if (existsSync21(inboxDir)) {
11643
+ try {
11644
+ const roomDirs = await readdir3(inboxDir);
11645
+ let totalMsgs = 0;
11646
+ for (const rd of roomDirs) {
11647
+ try {
11648
+ totalMsgs += (await readdir3(join28(inboxDir, rd))).length;
11649
+ } catch {
11650
+ }
11651
+ }
11652
+ lines.push(` Inbox: ${totalMsgs} message(s) across ${roomDirs.length} room(s)`);
11653
+ } catch {
11654
+ }
11655
+ }
11656
+ if (status.error)
11657
+ lines.push(` Error: ${status.error}`);
11658
+ return lines.join("\n");
11659
+ } catch {
11660
+ return `Daemon running (pid: ${pid}) but status file unreadable.`;
11661
+ }
11633
11662
  }
11634
11663
  async doSendMessage(args) {
11635
- if (!clientInstance)
11636
- throw new Error("Not connected. Use 'connect' first.");
11637
- const roomId = args.room_id;
11638
11664
  const message = args.message;
11639
- if (!roomId)
11640
- throw new Error("room_id is required");
11641
11665
  if (!message)
11642
11666
  throw new Error("message is required");
11667
+ if (!args.room_id)
11668
+ throw new Error("room_id is required");
11643
11669
  if (containsKeyMaterial(message)) {
11644
11670
  return [
11645
11671
  "BLOCKED: Message contains potential key material or secrets.",
11646
- "For security, messages containing private keys, wallet secrets,",
11647
- "or sensitive cryptographic material cannot be sent over the network.",
11648
- "Please remove the sensitive content and try again."
11672
+ "Messages containing private keys or sensitive cryptographic material",
11673
+ "cannot be sent over the network. Remove the sensitive content and retry."
11649
11674
  ].join("\n");
11650
11675
  }
11651
- const room = activeRooms.get(roomId);
11652
- if (!room)
11653
- throw new Error(`Not in room: ${roomId}. Join it first.`);
11654
- const msgId = await room.send(message, { format: "text/plain" });
11655
- return `Message sent to ${roomId} (id: ${msgId})`;
11656
- }
11657
- async doListRooms() {
11658
- if (!clientInstance)
11659
- throw new Error("Not connected. Use 'connect' first.");
11660
- try {
11661
- const rooms = await clientInstance.listRooms();
11662
- if (!rooms || rooms.length === 0) {
11663
- return "No rooms found on the network. Create one by joining a new room ID.";
11664
- }
11665
- const lines = rooms.map((r) => ` ${r.roomId} \u2014 ${r.name || "(unnamed)"} [${r.memberCount || 0} members, ${r.type}]`);
11666
- return `Available rooms:
11667
- ${lines.join("\n")}`;
11668
- } catch {
11669
- return "Could not list rooms (DHT may still be bootstrapping). Try again in a moment.";
11670
- }
11676
+ return this.sendDaemonCmd("send_message", args);
11671
11677
  }
11672
- async doDiscoverPeers() {
11673
- if (!clientInstance)
11674
- throw new Error("Not connected. Use 'connect' first.");
11675
- try {
11676
- const node = clientInstance.network?.node;
11677
- if (!node)
11678
- return "Network node not available yet.";
11679
- const peers = node.getPeers ? node.getPeers() : [];
11680
- if (peers.length === 0) {
11681
- return "No peers discovered yet. The network may still be bootstrapping. Try again in a few seconds.";
11682
- }
11683
- const lines = [`Discovered ${peers.length} peer(s):`];
11684
- for (const peerId of peers.slice(0, 20)) {
11685
- const pid = peerId.toString ? peerId.toString() : String(peerId);
11678
+ async doReadMessages(args) {
11679
+ const roomId = args.room_id;
11680
+ const inboxDir = join28(this.nexusDir, "inbox");
11681
+ if (roomId) {
11682
+ const roomInbox = join28(inboxDir, roomId);
11683
+ if (!existsSync21(roomInbox))
11684
+ return `No messages in room: ${roomId}`;
11685
+ const files = (await readdir3(roomInbox)).sort().slice(-20);
11686
+ if (files.length === 0)
11687
+ return `No messages in room: ${roomId}`;
11688
+ const messages = [`Messages in ${roomId} (last ${files.length}):`];
11689
+ for (const f of files) {
11686
11690
  try {
11687
- const profile = await clientInstance.findAgent(pid);
11688
- if (profile) {
11689
- lines.push(` ${pid.slice(0, 16)}... \u2014 ${profile.name} (${profile.type}) [${profile.capabilities?.length || 0} capabilities]`);
11690
- } else {
11691
- lines.push(` ${pid.slice(0, 16)}... \u2014 (no profile)`);
11692
- }
11691
+ const msg = JSON.parse(await readFile13(join28(roomInbox, f), "utf8"));
11692
+ const sender = (msg.sender || "unknown").slice(0, 12);
11693
+ messages.push(` [${new Date(msg.timestamp).toLocaleTimeString()}] ${sender}...: ${msg.content}`);
11693
11694
  } catch {
11694
- lines.push(` ${pid.slice(0, 16)}... \u2014 (lookup failed)`);
11695
11695
  }
11696
11696
  }
11697
- if (peers.length > 20) {
11698
- lines.push(` ... and ${peers.length - 20} more`);
11699
- }
11700
- return lines.join("\n");
11701
- } catch (err) {
11702
- return `Peer discovery error: ${err.message}`;
11697
+ return messages.join("\n");
11703
11698
  }
11704
- }
11705
- async doFindAgent(args) {
11706
- if (!clientInstance)
11707
- throw new Error("Not connected. Use 'connect' first.");
11708
- const peerId = args.peer_id;
11709
- if (!peerId)
11710
- throw new Error("peer_id is required");
11711
- const profile = await clientInstance.findAgent(peerId);
11712
- if (!profile) {
11713
- return `Agent not found: ${peerId}`;
11714
- }
11715
- const caps = profile.capabilities?.map((c3) => ` - ${c3.name}: ${c3.description} [${c3.pricing}]`) || [];
11716
- return [
11717
- `Agent Profile:`,
11718
- ` Peer ID: ${profile.peerId}`,
11719
- ` Name: ${profile.name}`,
11720
- ` Type: ${profile.type}`,
11721
- ` Role: ${profile.role}`,
11722
- ` Capabilities (${caps.length}):`,
11723
- ...caps,
11724
- ` Created: ${new Date(profile.createdAt).toISOString()}`,
11725
- ` Updated: ${new Date(profile.updatedAt).toISOString()}`
11726
- ].join("\n");
11727
- }
11728
- async doRegisterService(args) {
11729
- if (!clientInstance)
11730
- throw new Error("Not connected. Use 'connect' first.");
11731
- const serviceId = args.service_id || `svc-${randomBytes6(4).toString("hex")}`;
11732
- const name = args.service_name || "inference";
11733
- const description = args.service_description || "AI inference service";
11734
- const priceAmount = args.price_amount || "0.001";
11735
- const rateLimit = args.rate_limit || 60;
11736
- const walletPath = join28(this.nexusDir, "wallet.enc");
11737
- let walletAddress = "";
11738
- if (existsSync21(walletPath)) {
11699
+ if (!existsSync21(inboxDir))
11700
+ return "No messages received yet.";
11701
+ const roomDirs = await readdir3(inboxDir);
11702
+ if (roomDirs.length === 0)
11703
+ return "No messages received yet.";
11704
+ const lines = ["Inbox:"];
11705
+ for (const rd of roomDirs) {
11739
11706
  try {
11740
- const walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11741
- walletAddress = walletData.address;
11707
+ const count = (await readdir3(join28(inboxDir, rd))).length;
11708
+ lines.push(` ${rd}: ${count} message(s)`);
11742
11709
  } catch {
11743
11710
  }
11744
11711
  }
11745
- if (!walletAddress) {
11746
- return "Cannot register paid service without a wallet. Use wallet_create first.";
11747
- }
11748
- const offering = {
11749
- serviceId,
11750
- name,
11751
- description,
11752
- price: {
11753
- amount: priceAmount,
11754
- currency: "USDC",
11755
- network: "base",
11756
- recipient: walletAddress,
11757
- description: `Payment for ${name}`,
11758
- expiresAt: Date.now() + 36e5,
11759
- // 1 hour
11760
- requestId: `req-${randomBytes6(8).toString("hex")}`
11761
- },
11762
- rateLimit,
11763
- sensitive: false
11764
- };
11765
- clientInstance.x402.registerService(offering);
11766
- registeredServices.push(offering);
11767
- await this.ensureDir();
11768
- await writeFile12(join28(this.nexusDir, "services.json"), JSON.stringify(registeredServices, null, 2));
11769
- return [
11770
- `Service registered:`,
11771
- ` ID: ${serviceId}`,
11772
- ` Name: ${name}`,
11773
- ` Description: ${description}`,
11774
- ` Price: ${priceAmount} USDC per request`,
11775
- ` Rate limit: ${rateLimit} req/hour`,
11776
- ` Recipient wallet: ${walletAddress}`
11777
- ].join("\n");
11778
- }
11779
- async doListServices() {
11780
- const services = clientInstance?.x402?.getServices() || registeredServices;
11781
- if (services.length === 0) {
11782
- return "No services registered. Use register_service to offer inference.";
11783
- }
11784
- const lines = services.map((s) => ` ${s.serviceId} \u2014 ${s.name}: ${s.description} [${s.price?.amount || "?"} ${s.price?.currency || "USDC"}, ${s.rateLimit} req/hr]`);
11785
- return `Registered services (${services.length}):
11786
- ${lines.join("\n")}`;
11712
+ return lines.join("\n");
11787
11713
  }
11788
11714
  async doWalletStatus() {
11789
11715
  await this.ensureDir();
11790
11716
  const walletPath = join28(this.nexusDir, "wallet.enc");
11791
11717
  if (!existsSync21(walletPath)) {
11792
- return [
11793
- "No wallet configured.",
11794
- "Use wallet_create to generate a new wallet for x402 micropayments.",
11795
- "Or provide your own wallet address with wallet_create + wallet_address parameter."
11796
- ].join("\n");
11718
+ return "No wallet configured. Use wallet_create to set one up.";
11797
11719
  }
11798
11720
  try {
11799
- const walletData = JSON.parse(await readFile13(walletPath, "utf8"));
11721
+ const w = JSON.parse(await readFile13(walletPath, "utf8"));
11800
11722
  return [
11801
11723
  `Wallet Status:`,
11802
- ` Address: ${walletData.address}`,
11803
- ` Created: ${walletData.createdAt}`,
11724
+ ` Address: ${w.address}`,
11725
+ ` Created: ${w.createdAt}`,
11804
11726
  ` Encryption: AES-256-GCM + scrypt`,
11805
- ` Key file: ${walletPath} (0600)`,
11806
- ``,
11807
- ` NOTE: Private key is encrypted and NEVER accessible to the agent.`,
11808
- ` Only the public address is visible. Payment operations use the`,
11809
- ` encrypted key internally without exposing it.`
11727
+ ` NOTE: Private key is encrypted and NEVER accessible to the agent.`
11810
11728
  ].join("\n");
11811
11729
  } catch {
11812
- return "Wallet file exists but could not be read. It may be corrupted.";
11730
+ return "Wallet file exists but could not be read.";
11813
11731
  }
11814
11732
  }
11815
11733
  async doWalletCreate(args) {
11816
11734
  await this.ensureDir();
11817
11735
  const walletPath = join28(this.nexusDir, "wallet.enc");
11818
- if (existsSync21(walletPath)) {
11819
- return "Wallet already exists. To create a new one, delete .oa/nexus/wallet.enc first.";
11820
- }
11736
+ if (existsSync21(walletPath))
11737
+ return "Wallet already exists.";
11821
11738
  const userAddress = args.wallet_address;
11822
11739
  if (userAddress) {
11823
11740
  if (!/^0x[0-9a-fA-F]{40}$/.test(userAddress)) {
11824
- return "Invalid wallet address format. Expected Ethereum address (0x + 40 hex chars).";
11741
+ return "Invalid address format. Expected 0x + 40 hex chars.";
11825
11742
  }
11826
- const walletData2 = {
11743
+ const w2 = {
11827
11744
  version: 1,
11828
11745
  address: userAddress,
11829
11746
  encryptedKey: "",
11830
- // user-managed key
11831
11747
  iv: "",
11832
11748
  authTag: "",
11833
11749
  salt: "",
11834
11750
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
11835
11751
  };
11836
- await writeFile12(walletPath, JSON.stringify(walletData2, null, 2));
11752
+ await writeFile12(walletPath, JSON.stringify(w2, null, 2));
11837
11753
  await chmod(walletPath, 384);
11838
- return [
11839
- `Wallet configured with user-provided address.`,
11840
- ` Address: ${userAddress}`,
11841
- ` Key management: user-managed (external wallet)`,
11842
- ` File: ${walletPath}`,
11843
- ``,
11844
- `This address will be used for receiving x402 payments.`,
11845
- `Outbound payments require the agent to have signing capability,`,
11846
- `which is not available with an external address.`
11847
- ].join("\n");
11848
- }
11849
- const privateKeyBytes = randomBytes6(32);
11850
- const privateKeyHex = privateKeyBytes.toString("hex");
11851
- let address;
11852
- try {
11853
- const { createHash: createHash4 } = await import("node:crypto");
11854
- const pubHash = createHash4("sha256").update(privateKeyBytes).digest("hex");
11855
- address = "0x" + pubHash.slice(0, 40);
11856
- } catch {
11857
- address = "0x" + randomBytes6(20).toString("hex");
11858
- }
11859
- const machineId = `${__require("node:os").hostname()}:${__require("node:os").userInfo().username}:nexus-wallet`;
11860
- const { encrypted, iv, authTag, salt } = encryptKey(privateKeyHex, machineId);
11861
- privateKeyBytes.fill(0);
11862
- const walletData = {
11754
+ return `Wallet configured: ${userAddress} (user-managed)`;
11755
+ }
11756
+ const privKey = randomBytes6(32);
11757
+ const address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
11758
+ const salt = randomBytes6(32);
11759
+ const key = scryptSync(`${__require("node:os").hostname()}:${__require("node:os").userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
11760
+ const iv = randomBytes6(16);
11761
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
11762
+ let enc = cipher.update(privKey.toString("hex"), "utf8", "hex");
11763
+ enc += cipher.final("hex");
11764
+ privKey.fill(0);
11765
+ const w = {
11863
11766
  version: 1,
11864
11767
  address,
11865
- encryptedKey: encrypted,
11866
- iv,
11867
- authTag,
11868
- salt,
11768
+ encryptedKey: enc,
11769
+ iv: iv.toString("hex"),
11770
+ authTag: cipher.getAuthTag().toString("hex"),
11771
+ salt: salt.toString("hex"),
11869
11772
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
11870
11773
  };
11871
- await writeFile12(walletPath, JSON.stringify(walletData, null, 2));
11774
+ await writeFile12(walletPath, JSON.stringify(w, null, 2));
11872
11775
  await chmod(walletPath, 384);
11873
11776
  return [
11874
- `Wallet created successfully.`,
11875
- ` Address: ${address}`,
11876
- ` Encryption: AES-256-GCM with scrypt key derivation`,
11877
- ` Key file: ${walletPath} (permissions: 0600)`,
11878
- ``,
11879
- ` SECURITY NOTES:`,
11880
- ` - Private key is encrypted at rest and NEVER visible to the agent`,
11881
- ` - Key material is cleared from memory after encryption`,
11882
- ` - The encryption password is derived from machine identity`,
11883
- ` - Only payment operations can use the key (internally)`,
11884
- ` - The key CANNOT be extracted via tool calls or messages`
11777
+ `Wallet created: ${address}`,
11778
+ ` Encrypted with AES-256-GCM (key NEVER visible to agent)`,
11779
+ ` File: ${walletPath} (0600)`
11885
11780
  ].join("\n");
11886
11781
  }
11887
11782
  async doInferenceProof() {
11888
- const proof = runInferenceBenchmark(this.repoRoot);
11889
- if (!proof) {
11783
+ try {
11784
+ const psRaw = execSync20("ollama ps 2>/dev/null", { timeout: 1e4, encoding: "utf8" });
11785
+ const lines = psRaw.trim().split("\n").filter((l) => l.trim());
11786
+ if (lines.length < 2)
11787
+ return "No model loaded. Run 'ollama ps' to check.";
11788
+ const parts = lines[1].split(/\s+/);
11789
+ const modelName = parts[0] || "unknown";
11790
+ let gpuName = "none", vramMb = 0;
11791
+ try {
11792
+ const smi = execSync20("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null", {
11793
+ timeout: 5e3,
11794
+ encoding: "utf8"
11795
+ });
11796
+ const gp = smi.trim().split(",");
11797
+ gpuName = gp[0]?.trim() || "unknown";
11798
+ vramMb = parseInt(gp[1]?.trim() || "0", 10);
11799
+ } catch {
11800
+ try {
11801
+ execSync20("rocm-smi 2>/dev/null", { timeout: 5e3 });
11802
+ gpuName = "AMD GPU";
11803
+ } catch {
11804
+ }
11805
+ }
11806
+ const nonce = randomBytes6(16).toString("hex");
11807
+ const hash = createHash("sha256").update(`${modelName}:${nonce}:${Date.now()}`).digest("hex");
11808
+ const bar = (s) => "\u2588".repeat(Math.round(s / 5)) + "\u2591".repeat(20 - Math.round(s / 5));
11809
+ const mem = vramMb > 24e3 ? 95 : vramMb > 16e3 ? 80 : vramMb > 8e3 ? 60 : vramMb > 0 ? 40 : 20;
11810
+ await this.ensureDir();
11811
+ await writeFile12(join28(this.nexusDir, "inference-proof.json"), JSON.stringify({
11812
+ modelName,
11813
+ gpuName,
11814
+ vramMb,
11815
+ hash,
11816
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
11817
+ }, null, 2));
11890
11818
  return [
11891
- "Could not generate inference proof.",
11892
- "Ensure Ollama is running with a loaded model (ollama ps)."
11819
+ `Inference Capability Proof`,
11820
+ ` Model: ${modelName} (${parts[1] || "?"})`,
11821
+ ` GPU: ${gpuName} (${vramMb} MB)`,
11822
+ ` Memory [${bar(mem)}] ${mem}%`,
11823
+ ` Hash: ${hash.slice(0, 16)}...`
11893
11824
  ].join("\n");
11825
+ } catch {
11826
+ return "Could not generate proof. Ensure Ollama is running.";
11894
11827
  }
11895
- await this.ensureDir();
11896
- const proofPath = join28(this.nexusDir, "inference-proof.json");
11897
- await writeFile12(proofPath, JSON.stringify(proof, null, 2));
11898
- const memScore = proof.vramMb > 24e3 ? 95 : proof.vramMb > 16e3 ? 80 : proof.vramMb > 8e3 ? 60 : proof.vramMb > 0 ? 40 : 20;
11899
- const speedScore = proof.tokensPerSecond > 50 ? 95 : proof.tokensPerSecond > 30 ? 80 : proof.tokensPerSecond > 15 ? 60 : proof.tokensPerSecond > 5 ? 40 : 20;
11900
- const overall = Math.round((memScore + speedScore) / 2);
11901
- const bar = (score) => {
11902
- const filled = Math.round(score / 5);
11903
- const empty = 20 - filled;
11904
- return "\u2588".repeat(filled) + "\u2591".repeat(empty);
11905
- };
11906
- return [
11907
- `Inference Capability Proof`,
11908
- `\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
11909
- ` Model: ${proof.modelName} (${proof.modelSize})`,
11910
- ` GPU: ${proof.gpuName} (${proof.vramMb} MB VRAM)`,
11911
- ` Speed: ${proof.tokensPerSecond} tok/s`,
11912
- ` Context: ${proof.contextLength} tokens`,
11913
- ``,
11914
- ` Memory [${bar(memScore)}] ${memScore}%`,
11915
- ` Speed [${bar(speedScore)}] ${speedScore}%`,
11916
- ` Overall [${bar(overall)}] ${overall}%`,
11917
- ``,
11918
- ` Benchmark hash: ${proof.benchmarkHash.slice(0, 16)}...`,
11919
- ` Timestamp: ${proof.timestamp}`,
11920
- ` Proof saved: ${proofPath}`,
11921
- ``,
11922
- ` Anti-spoofing: SHA-256 hash of model+timing+nonce`,
11923
- ` Verification: peers can request live re-benchmark`
11924
- ].join("\n");
11925
- }
11926
- async doStoreContent(args) {
11927
- if (!clientInstance)
11928
- throw new Error("Not connected. Use 'connect' first.");
11929
- const content = args.content;
11930
- if (!content)
11931
- throw new Error("content is required");
11932
- if (containsKeyMaterial(content)) {
11933
- return "BLOCKED: Content contains potential key material. Cannot store secrets on IPFS.";
11934
- }
11935
- const cid = await clientInstance.store(content);
11936
- return `Content stored on IPFS.
11937
- CID: ${cid}
11938
- Retrieve with: retrieve_content + cid="${cid}"`;
11939
- }
11940
- async doRetrieveContent(args) {
11941
- if (!clientInstance)
11942
- throw new Error("Not connected. Use 'connect' first.");
11943
- const cid = args.cid;
11944
- if (!cid)
11945
- throw new Error("cid is required");
11946
- const data = await clientInstance.retrieve(cid);
11947
- if (typeof data === "string")
11948
- return data;
11949
- if (typeof data === "object")
11950
- return JSON.stringify(data, null, 2);
11951
- return String(data);
11952
11828
  }
11953
11829
  };
11954
11830
  }
@@ -13208,7 +13084,7 @@ var init_code_retriever = __esm({
13208
13084
  // packages/retrieval/dist/lexicalSearch.js
13209
13085
  import { execFile as execFile5 } from "node:child_process";
13210
13086
  import { promisify as promisify4 } from "node:util";
13211
- import { readFile as readFile14, readdir as readdir3, stat as stat3 } from "node:fs/promises";
13087
+ import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "node:fs/promises";
13212
13088
  import { join as join29, extname as extname7 } from "node:path";
13213
13089
  async function searchByPath(pathPattern, options) {
13214
13090
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
@@ -13342,7 +13218,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
13342
13218
  async function walkForFiles(rootDir, dir, excludeGlobs, results) {
13343
13219
  let entries;
13344
13220
  try {
13345
- entries = await readdir3(dir, { withFileTypes: true, encoding: "utf-8" });
13221
+ entries = await readdir4(dir, { withFileTypes: true, encoding: "utf-8" });
13346
13222
  } catch {
13347
13223
  return;
13348
13224
  }
@@ -17763,7 +17639,7 @@ __export(listen_exports, {
17763
17639
  isVideoPath: () => isVideoPath,
17764
17640
  waitForTranscribeCli: () => waitForTranscribeCli
17765
17641
  });
17766
- import { spawn as spawn10, execSync as execSync21 } from "node:child_process";
17642
+ import { spawn as spawn11, execSync as execSync21 } from "node:child_process";
17767
17643
  import { existsSync as existsSync22, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6, readdirSync as readdirSync6 } from "node:fs";
17768
17644
  import { join as join31, dirname as dirname10 } from "node:path";
17769
17645
  import { homedir as homedir8 } from "node:os";
@@ -17973,7 +17849,7 @@ var init_listen = __esm({
17973
17849
  const timeout = setTimeout(() => {
17974
17850
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
17975
17851
  }, 3e5);
17976
- this.process = spawn10("python3", [
17852
+ this.process = spawn11("python3", [
17977
17853
  this.scriptPath,
17978
17854
  "--model",
17979
17855
  this.model,
@@ -18255,7 +18131,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
18255
18131
  return `Failed to start live transcription: ${msg}${tcHint}`;
18256
18132
  }
18257
18133
  }
18258
- this.micProcess = spawn10(micCmd.cmd, micCmd.args, {
18134
+ this.micProcess = spawn11(micCmd.cmd, micCmd.args, {
18259
18135
  stdio: ["pipe", "pipe", "pipe"],
18260
18136
  env: { ...process.env }
18261
18137
  });
@@ -20674,7 +20550,7 @@ var require_websocket = __commonJS({
20674
20550
  var http = __require("http");
20675
20551
  var net = __require("net");
20676
20552
  var tls = __require("tls");
20677
- var { randomBytes: randomBytes10, createHash: createHash4 } = __require("crypto");
20553
+ var { randomBytes: randomBytes10, createHash: createHash5 } = __require("crypto");
20678
20554
  var { Duplex, Readable } = __require("stream");
20679
20555
  var { URL: URL3 } = __require("url");
20680
20556
  var PerMessageDeflate = require_permessage_deflate();
@@ -21334,7 +21210,7 @@ var require_websocket = __commonJS({
21334
21210
  abortHandshake(websocket, socket, "Invalid Upgrade header");
21335
21211
  return;
21336
21212
  }
21337
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
21213
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
21338
21214
  if (res.headers["sec-websocket-accept"] !== digest) {
21339
21215
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
21340
21216
  return;
@@ -21701,7 +21577,7 @@ var require_websocket_server = __commonJS({
21701
21577
  var EventEmitter7 = __require("events");
21702
21578
  var http = __require("http");
21703
21579
  var { Duplex } = __require("stream");
21704
- var { createHash: createHash4 } = __require("crypto");
21580
+ var { createHash: createHash5 } = __require("crypto");
21705
21581
  var extension = require_extension();
21706
21582
  var PerMessageDeflate = require_permessage_deflate();
21707
21583
  var subprotocol = require_subprotocol();
@@ -22002,7 +21878,7 @@ var require_websocket_server = __commonJS({
22002
21878
  );
22003
21879
  }
22004
21880
  if (this._state > RUNNING) return abortHandshake(socket, 503);
22005
- const digest = createHash4("sha1").update(key + GUID).digest("base64");
21881
+ const digest = createHash5("sha1").update(key + GUID).digest("base64");
22006
21882
  const headers = [
22007
21883
  "HTTP/1.1 101 Switching Protocols",
22008
21884
  "Upgrade: websocket",
@@ -22991,7 +22867,7 @@ var init_render = __esm({
22991
22867
 
22992
22868
  // packages/cli/dist/tui/voice-session.js
22993
22869
  import { createServer } from "node:http";
22994
- import { spawn as spawn11, execSync as execSync22 } from "node:child_process";
22870
+ import { spawn as spawn12, execSync as execSync22 } from "node:child_process";
22995
22871
  import { EventEmitter as EventEmitter2 } from "node:events";
22996
22872
  function generateFrontendHTML() {
22997
22873
  return `<!DOCTYPE html>
@@ -23645,7 +23521,7 @@ var init_voice_session = __esm({
23645
23521
  const timeout = setTimeout(() => {
23646
23522
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
23647
23523
  }, 3e4);
23648
- this.cloudflaredProcess = spawn11("cloudflared", [
23524
+ this.cloudflaredProcess = spawn12("cloudflared", [
23649
23525
  "tunnel",
23650
23526
  "--url",
23651
23527
  `http://127.0.0.1:${port}`
@@ -23719,7 +23595,7 @@ var init_voice_session = __esm({
23719
23595
 
23720
23596
  // packages/cli/dist/tui/expose.js
23721
23597
  import { createServer as createServer2, request as httpRequest } from "node:http";
23722
- import { spawn as spawn12 } from "node:child_process";
23598
+ import { spawn as spawn13 } from "node:child_process";
23723
23599
  import { EventEmitter as EventEmitter3 } from "node:events";
23724
23600
  import { randomBytes as randomBytes7 } from "node:crypto";
23725
23601
  import { URL as URL2 } from "node:url";
@@ -23895,7 +23771,7 @@ var init_expose = __esm({
23895
23771
  const timeout = setTimeout(() => {
23896
23772
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
23897
23773
  }, 3e4);
23898
- this.cloudflaredProcess = spawn12("cloudflared", [
23774
+ this.cloudflaredProcess = spawn13("cloudflared", [
23899
23775
  "tunnel",
23900
23776
  "--url",
23901
23777
  `http://127.0.0.1:${port}`
@@ -23997,10 +23873,10 @@ var init_types = __esm({
23997
23873
  });
23998
23874
 
23999
23875
  // packages/cli/dist/tui/p2p/secret-vault.js
24000
- import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8, scryptSync as scryptSync2, createHash } from "node:crypto";
23876
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes8, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
24001
23877
  import { readFileSync as readFileSync15, writeFileSync as writeFileSync7, existsSync as existsSync23, mkdirSync as mkdirSync7 } from "node:fs";
24002
23878
  import { join as join32, dirname as dirname11 } from "node:path";
24003
- var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN2, SecretVault;
23879
+ var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
24004
23880
  var init_secret_vault = __esm({
24005
23881
  "packages/cli/dist/tui/p2p/secret-vault.js"() {
24006
23882
  "use strict";
@@ -24010,7 +23886,7 @@ var init_secret_vault = __esm({
24010
23886
  CIPHER_ALGO = "aes-256-gcm";
24011
23887
  SALT_LEN = 16;
24012
23888
  IV_LEN = 12;
24013
- KEY_LEN2 = 32;
23889
+ KEY_LEN = 32;
24014
23890
  SecretVault = class {
24015
23891
  storePath;
24016
23892
  secrets = /* @__PURE__ */ new Map();
@@ -24204,7 +24080,7 @@ var init_secret_vault = __esm({
24204
24080
  createdAt: s.createdAt
24205
24081
  })));
24206
24082
  const salt = randomBytes8(SALT_LEN);
24207
- const key = scryptSync2(passphrase, salt, KEY_LEN2);
24083
+ const key = scryptSync2(passphrase, salt, KEY_LEN);
24208
24084
  const iv = randomBytes8(IV_LEN);
24209
24085
  const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
24210
24086
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
@@ -24230,7 +24106,7 @@ var init_secret_vault = __esm({
24230
24106
  const iv = blob.subarray(SALT_LEN, SALT_LEN + IV_LEN);
24231
24107
  const tag = blob.subarray(SALT_LEN + IV_LEN, SALT_LEN + IV_LEN + 16);
24232
24108
  const encrypted = blob.subarray(SALT_LEN + IV_LEN + 16);
24233
- const key = scryptSync2(passphrase, salt, KEY_LEN2);
24109
+ const key = scryptSync2(passphrase, salt, KEY_LEN);
24234
24110
  const decipher = createDecipheriv2(CIPHER_ALGO, key, iv);
24235
24111
  decipher.setAuthTag(tag);
24236
24112
  let data;
@@ -24248,7 +24124,7 @@ var init_secret_vault = __esm({
24248
24124
  /** Generate a deterministic fingerprint of vault contents (for sync verification) */
24249
24125
  fingerprint() {
24250
24126
  const names = Array.from(this.secrets.keys()).sort();
24251
- const hash = createHash("sha256");
24127
+ const hash = createHash2("sha256");
24252
24128
  for (const name of names) {
24253
24129
  hash.update(name + ":");
24254
24130
  hash.update(this.secrets.get(name).value);
@@ -24263,7 +24139,7 @@ var init_secret_vault = __esm({
24263
24139
  // packages/cli/dist/tui/p2p/peer-mesh.js
24264
24140
  import { EventEmitter as EventEmitter4 } from "node:events";
24265
24141
  import { createServer as createServer3 } from "node:http";
24266
- import { randomBytes as randomBytes9, createHash as createHash2, generateKeyPairSync } from "node:crypto";
24142
+ import { randomBytes as randomBytes9, createHash as createHash3, generateKeyPairSync } from "node:crypto";
24267
24143
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
24268
24144
  var init_peer_mesh = __esm({
24269
24145
  "packages/cli/dist/tui/p2p/peer-mesh.js"() {
@@ -24312,7 +24188,7 @@ var init_peer_mesh = __esm({
24312
24188
  const { publicKey, privateKey } = generateKeyPairSync("ed25519");
24313
24189
  this.publicKey = publicKey.export({ type: "spki", format: "der" });
24314
24190
  this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
24315
- this.peerId = createHash2("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
24191
+ this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
24316
24192
  this.capabilities = options.capabilities;
24317
24193
  this.displayName = options.displayName;
24318
24194
  this._authKey = options.authKey ?? randomBytes9(24).toString("base64url");
@@ -26030,7 +25906,7 @@ var init_oa_directory = __esm({
26030
25906
 
26031
25907
  // packages/cli/dist/tui/setup.js
26032
25908
  import * as readline from "node:readline";
26033
- import { execSync as execSync23, spawn as spawn13 } from "node:child_process";
25909
+ import { execSync as execSync23, spawn as spawn14 } from "node:child_process";
26034
25910
  import { existsSync as existsSync25, writeFileSync as writeFileSync9, mkdirSync as mkdirSync9 } from "node:fs";
26035
25911
  import { join as join35 } from "node:path";
26036
25912
  import { homedir as homedir10, platform } from "node:os";
@@ -26373,7 +26249,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
26373
26249
  process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
26374
26250
  `);
26375
26251
  try {
26376
- const child = spawn13("ollama", ["serve"], { stdio: "ignore", detached: true });
26252
+ const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
26377
26253
  child.unref();
26378
26254
  } catch {
26379
26255
  process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
@@ -26841,7 +26717,7 @@ async function doSetup(config, rl) {
26841
26717
  ${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
26842
26718
  `);
26843
26719
  try {
26844
- const child = spawn13("ollama", ["serve"], { stdio: "ignore", detached: true });
26720
+ const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
26845
26721
  child.unref();
26846
26722
  await new Promise((resolve31) => setTimeout(resolve31, 3e3));
26847
26723
  try {
@@ -26869,7 +26745,7 @@ async function doSetup(config, rl) {
26869
26745
  ${c2.cyan("\u25CF")} Starting ollama serve...
26870
26746
  `);
26871
26747
  try {
26872
- const child = spawn13("ollama", ["serve"], { stdio: "ignore", detached: true });
26748
+ const child = spawn14("ollama", ["serve"], { stdio: "ignore", detached: true });
26873
26749
  child.unref();
26874
26750
  await new Promise((resolve31) => setTimeout(resolve31, 3e3));
26875
26751
  try {
@@ -40303,13 +40179,13 @@ NEW TASK: ${fullInput}`;
40303
40179
  writeContent(() => renderError(errMsg));
40304
40180
  if (failureStore) {
40305
40181
  try {
40306
- const { createHash: createHash4 } = await import("node:crypto");
40182
+ const { createHash: createHash5 } = await import("node:crypto");
40307
40183
  failureStore.insert({
40308
40184
  taskId: "",
40309
40185
  sessionId: `${Date.now()}`,
40310
40186
  repoRoot,
40311
40187
  failureType: "runtime-error",
40312
- fingerprint: createHash4("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
40188
+ fingerprint: createHash5("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
40313
40189
  filePath: null,
40314
40190
  errorMessage: errMsg.slice(0, 500),
40315
40191
  context: null,
@@ -40587,7 +40463,7 @@ var init_run = __esm({
40587
40463
  import { glob } from "glob";
40588
40464
  import ignore from "ignore";
40589
40465
  import { readFile as readFile16, stat as stat4 } from "node:fs/promises";
40590
- import { createHash as createHash3 } from "node:crypto";
40466
+ import { createHash as createHash4 } from "node:crypto";
40591
40467
  import { join as join45, relative as relative3, extname as extname10, basename as basename15 } from "node:path";
40592
40468
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
40593
40469
  var init_codebase_indexer = __esm({
@@ -40653,7 +40529,7 @@ var init_codebase_indexer = __esm({
40653
40529
  if (fileStat.size > this.config.maxFileSize)
40654
40530
  continue;
40655
40531
  const content = await readFile16(fullPath);
40656
- const hash = createHash3("sha256").update(content).digest("hex");
40532
+ const hash = createHash4("sha256").update(content).digest("hex");
40657
40533
  const ext = extname10(relativePath);
40658
40534
  indexed.push({
40659
40535
  path: fullPath,
@@ -41193,7 +41069,7 @@ var serve_exports = {};
41193
41069
  __export(serve_exports, {
41194
41070
  serveCommand: () => serveCommand
41195
41071
  });
41196
- import { spawn as spawn14 } from "node:child_process";
41072
+ import { spawn as spawn15 } from "node:child_process";
41197
41073
  async function serveCommand(opts, config) {
41198
41074
  const backendType = config.backendType;
41199
41075
  if (backendType === "ollama") {
@@ -41286,7 +41162,7 @@ async function serveVllm(opts, config) {
41286
41162
  }
41287
41163
  async function runVllmServer(args, verbose) {
41288
41164
  return new Promise((resolve31, reject) => {
41289
- const child = spawn14("python", args, {
41165
+ const child = spawn15("python", args, {
41290
41166
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
41291
41167
  env: { ...process.env }
41292
41168
  });