open-agents-ai 0.71.4 → 0.71.5

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