open-agents-ai 0.186.18 → 0.186.20

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 +113 -22
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5343,12 +5343,50 @@ var init_nexus = __esm({
5343
5343
  * Usage: node nexus-daemon.mjs <nexus-dir> <agent-name> [agent-type]
5344
5344
  */
5345
5345
 
5346
- import { NexusClient, buildNknEnvelope, parseNknEnvelope, deriveNknSeed } from 'open-agents-nexus';
5346
+ import { NexusClient } from 'open-agents-nexus';
5347
5347
  import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync, appendFileSync, watch as fsWatch } from 'node:fs';
5348
5348
  import { join } from 'node:path';
5349
5349
  import { homedir, hostname } from 'node:os';
5350
5350
  import { createHash, createHmac } from 'node:crypto';
5351
5351
 
5352
+ // NKN utilities \u2014 imported dynamically to avoid crash on older open-agents-nexus versions.
5353
+ // Falls back to inline implementations if the package doesn't export them yet.
5354
+ var buildNknEnvelope, parseNknEnvelope, deriveNknSeed;
5355
+ try {
5356
+ var _nknMod = await import('open-agents-nexus');
5357
+ buildNknEnvelope = _nknMod.buildNknEnvelope;
5358
+ parseNknEnvelope = _nknMod.parseNknEnvelope;
5359
+ deriveNknSeed = _nknMod.deriveNknSeed;
5360
+ } catch {}
5361
+ if (!deriveNknSeed) {
5362
+ deriveNknSeed = function(keyData) { return createHash('sha256').update(keyData).update('nkn-seed-v1').digest('hex'); };
5363
+ }
5364
+ if (!buildNknEnvelope) {
5365
+ buildNknEnvelope = function(senderAddr, receiverAddr, agentName, content, libp2pPeerId) {
5366
+ var ts = Date.now();
5367
+ var secret = createHash('sha256').update(senderAddr).update(receiverAddr).update('oa-nkn-v1').digest('hex');
5368
+ var hmac = createHmac('sha256', secret).update(agentName + content + String(ts)).digest('hex').slice(0, 16);
5369
+ return JSON.stringify({ _agentName: agentName, content: content, timestamp: ts, libp2pPeerId: libp2pPeerId || null, _hmac: hmac });
5370
+ };
5371
+ }
5372
+ if (!parseNknEnvelope) {
5373
+ parseNknEnvelope = function(senderAddr, receiverAddr, raw) {
5374
+ var entry = { sender: senderAddr, raw: raw, receivedAt: Date.now(), verified: false };
5375
+ try {
5376
+ var parsed = JSON.parse(raw);
5377
+ if (parsed._hmac && parsed._agentName && parsed.content) {
5378
+ var secret = createHash('sha256').update(senderAddr).update(receiverAddr).update('oa-nkn-v1').digest('hex');
5379
+ var expected = createHmac('sha256', secret).update(parsed._agentName + parsed.content + String(parsed.timestamp || 0)).digest('hex').slice(0, 16);
5380
+ entry.verified = (parsed._hmac === expected);
5381
+ entry.agentName = parsed._agentName;
5382
+ entry.content = parsed.content;
5383
+ entry.timestamp = parsed.timestamp;
5384
+ }
5385
+ } catch {}
5386
+ return entry;
5387
+ };
5388
+ }
5389
+
5352
5390
  const nexusDir = process.argv[2];
5353
5391
  const agentName = process.argv[3] || ('oa-node-' + process.pid);
5354
5392
  const agentType = process.argv[4] || 'general';
@@ -38028,6 +38066,7 @@ Type /expose tunnel to retry manually, or /expose libp2p as alternative.`);
38028
38066
  this.emitStats();
38029
38067
  this.options.onInfo?.(`Tunnel restarted with new URL \u2014 share with consumers:
38030
38068
  ${this.formatConnectionInfo()}`);
38069
+ this.options.onTunnelRestart?.(this._tunnelUrl);
38031
38070
  if (this._stateDir) {
38032
38071
  writeExposeState(this._stateDir, {
38033
38072
  pid: this._cloudflaredPid,
@@ -46489,11 +46528,25 @@ async function runSponsorWizard(ctx) {
46489
46528
  }
46490
46529
  config.status = "active";
46491
46530
  saveSponsorConfig(ctx.projectDir, config);
46531
+ let goLiveSuccess = true;
46492
46532
  if (ctx.onGoLive) {
46493
- await ctx.onGoLive(config);
46533
+ try {
46534
+ const result = await ctx.onGoLive(config);
46535
+ if (result === false || result === "failed")
46536
+ goLiveSuccess = false;
46537
+ } catch {
46538
+ goLiveSuccess = false;
46539
+ }
46540
+ }
46541
+ if (goLiveSuccess) {
46542
+ renderInfo("\u2726 Sponsorship active!");
46543
+ renderInfo("Toggle: /sponsor status | Pause: /sponsor pause | Remove: /sponsor remove");
46544
+ } else {
46545
+ config.status = "inactive";
46546
+ saveSponsorConfig(ctx.projectDir, config);
46547
+ renderWarning("Sponsorship could not go live \u2014 no public endpoint available.");
46548
+ renderInfo("Fix the tunnel/P2P issue and run /sponsor again.");
46494
46549
  }
46495
- renderInfo("\u2726 Sponsorship active!");
46496
- renderInfo("Toggle: /sponsor status | Pause: /sponsor pause | Remove: /sponsor remove");
46497
46550
  return config;
46498
46551
  }
46499
46552
  var COLOR_PRESETS, GRADIENT_PRESETS, ANIM_PRESETS2;
@@ -49310,10 +49363,34 @@ import * as nodeOs from "node:os";
49310
49363
  import { execSync as nodeExecSync } from "node:child_process";
49311
49364
  import { existsSync as existsSync44, readFileSync as readFileSync33, writeFileSync as writeFileSync21, mkdirSync as mkdirSync20, readdirSync as readdirSync13, statSync as statSync15, rmSync } from "node:fs";
49312
49365
  import { join as join60 } from "node:path";
49366
+ async function _immediateReregister(newUrl) {
49367
+ if (!_lastRegisteredSponsorPayload)
49368
+ return;
49369
+ _lastRegisteredSponsorPayload.tunnelUrl = newUrl;
49370
+ _lastRegisteredSponsorPayload.status = "active";
49371
+ try {
49372
+ await fetch("https://openagents.nexus/api/v1/sponsors", {
49373
+ method: "POST",
49374
+ headers: { "Content-Type": "application/json" },
49375
+ body: JSON.stringify(_lastRegisteredSponsorPayload),
49376
+ signal: AbortSignal.timeout(1e4)
49377
+ });
49378
+ } catch {
49379
+ }
49380
+ }
49313
49381
  function startSponsorHeartbeat(payload, getExposeGateway) {
49314
49382
  stopSponsorHeartbeat();
49315
49383
  _lastRegisteredSponsorPayload = { ...payload };
49316
49384
  const _stableGetGateway = getExposeGateway;
49385
+ try {
49386
+ const gw = _stableGetGateway?.();
49387
+ if (gw && !gw._sponsorRestartWired) {
49388
+ gw._sponsorRestartWired = true;
49389
+ if (gw.options)
49390
+ gw.options.onTunnelRestart = _immediateReregister;
49391
+ }
49392
+ } catch {
49393
+ }
49317
49394
  const HEARTBEAT_MS = 5 * 60 * 1e3;
49318
49395
  _sponsorHeartbeatTimer = setInterval(async () => {
49319
49396
  if (!_lastRegisteredSponsorPayload)
@@ -51281,27 +51358,42 @@ Clone a new voice: /voice clone <wav-file> [name]`);
51281
51358
  let daemonReady = false;
51282
51359
  try {
51283
51360
  const nexus = new NexusTool(projectDir);
51284
- try {
51285
- await nexus.execute({ action: "disconnect" });
51286
- await new Promise((r) => setTimeout(r, 500));
51287
- } catch {
51288
- }
51289
- renderInfo("Starting nexus daemon...");
51290
- await nexus.execute({ action: "connect" });
51291
- for (let wait = 0; wait < 15; wait++) {
51292
- await new Promise((r) => setTimeout(r, 1e3));
51293
- try {
51294
- const status = await nexus.execute({ action: "status" });
51295
- if (typeof status === "string" && status.includes("connected")) {
51361
+ const curStatus = String(await nexus.execute({ action: "status" }) ?? "");
51362
+ if (/Connected:\s*true/i.test(curStatus)) {
51363
+ daemonReady = true;
51364
+ renderInfo("Using existing nexus daemon connection.");
51365
+ } else if (curStatus.includes("not running")) {
51366
+ renderInfo("Starting nexus daemon...");
51367
+ await nexus.execute({ action: "connect" });
51368
+ for (let wait = 0; wait < 25; wait++) {
51369
+ await new Promise((r) => setTimeout(r, 1e3));
51370
+ try {
51371
+ const status = String(await nexus.execute({ action: "status" }) ?? "");
51372
+ if (/Connected:\s*true/i.test(status)) {
51373
+ daemonReady = true;
51374
+ renderInfo("Nexus daemon ready.");
51375
+ break;
51376
+ }
51377
+ } catch {
51378
+ }
51379
+ }
51380
+ if (!daemonReady)
51381
+ renderWarning("Nexus daemon did not become ready in 25s. P2P may fail.");
51382
+ } else {
51383
+ renderInfo("Waiting for nexus daemon to finish connecting...");
51384
+ for (let wait = 0; wait < 15; wait++) {
51385
+ await new Promise((r) => setTimeout(r, 1e3));
51386
+ const s = String(await nexus.execute({ action: "status" }) ?? "");
51387
+ if (/Connected:\s*true/i.test(s)) {
51296
51388
  daemonReady = true;
51297
- renderInfo("Nexus daemon ready.");
51298
51389
  break;
51299
51390
  }
51300
- } catch {
51301
51391
  }
51392
+ if (daemonReady)
51393
+ renderInfo("Nexus daemon ready.");
51394
+ else
51395
+ renderWarning("Nexus daemon still connecting \u2014 P2P may be delayed.");
51302
51396
  }
51303
- if (!daemonReady)
51304
- renderWarning("Nexus daemon did not become ready in 15s. P2P may fail.");
51305
51397
  } catch (err) {
51306
51398
  renderWarning(`Nexus connect: ${err instanceof Error ? err.message : String(err)}`);
51307
51399
  }
@@ -51327,8 +51419,7 @@ Clone a new voice: /voice clone <wav-file> [name]`);
51327
51419
  const sponsorUrl = tunnelGw?.tunnelUrl || "";
51328
51420
  if (!sponsorUrl) {
51329
51421
  renderWarning("No tunnel URL available \u2014 sponsor not registered in directory. Start with cloudflared or libp2p first.");
51330
- renderInfo("Sponsor wizard completed (offline mode \u2014 no public endpoint).");
51331
- return;
51422
+ return false;
51332
51423
  }
51333
51424
  let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
51334
51425
  if (!sponsorName || sponsorName.length < 2) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.186.18",
3
+ "version": "0.186.20",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",