open-agents-ai 0.105.5 → 0.105.7

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 +217 -118
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14438,6 +14438,15 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14438
14438
  const nodeModulesDir = resolve26(this.repoRoot, "node_modules");
14439
14439
  let nexusResolved = false;
14440
14440
  let installedVersion = "";
14441
+ const execAsync2 = (cmd, opts = {}) => new Promise((res, rej) => {
14442
+ const { exec: ex } = __require("node:child_process");
14443
+ ex(cmd, { encoding: "utf8", timeout: opts.timeout ?? 3e4, cwd: opts.cwd, maxBuffer: 10 * 1024 * 1024 }, (err, stdout) => {
14444
+ if (err)
14445
+ rej(err);
14446
+ else
14447
+ res((stdout || "").trim());
14448
+ });
14449
+ });
14441
14450
  try {
14442
14451
  const nexusPkg = join30(nodeModulesDir, "open-agents-nexus", "package.json");
14443
14452
  if (existsSync23(nexusPkg)) {
@@ -14448,30 +14457,29 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14448
14457
  } catch {
14449
14458
  }
14450
14459
  } else {
14451
- const globalDir = execSync22("npm root -g", { encoding: "utf8", timeout: 5e3 }).trim();
14452
- const globalPkg = join30(globalDir, "open-agents-nexus", "package.json");
14453
- if (existsSync23(globalPkg)) {
14454
- nexusResolved = true;
14455
- try {
14456
- const pkg = JSON.parse(readFileSync16(globalPkg, "utf8"));
14457
- installedVersion = pkg.version || "";
14458
- } catch {
14460
+ try {
14461
+ const globalDir = await execAsync2("npm root -g", { timeout: 5e3 });
14462
+ const globalPkg = join30(globalDir, "open-agents-nexus", "package.json");
14463
+ if (existsSync23(globalPkg)) {
14464
+ nexusResolved = true;
14465
+ try {
14466
+ const pkg = JSON.parse(readFileSync16(globalPkg, "utf8"));
14467
+ installedVersion = pkg.version || "";
14468
+ } catch {
14469
+ }
14459
14470
  }
14471
+ } catch {
14460
14472
  }
14461
14473
  }
14462
14474
  } catch {
14463
14475
  }
14464
14476
  if (nexusResolved && installedVersion) {
14465
14477
  try {
14466
- const latestRaw = execSync22("npm view open-agents-nexus version 2>/dev/null", {
14467
- encoding: "utf8",
14468
- timeout: 8e3
14469
- }).trim();
14478
+ const latestRaw = await execAsync2("npm view open-agents-nexus version 2>/dev/null", { timeout: 8e3 });
14470
14479
  if (latestRaw && latestRaw !== installedVersion) {
14471
14480
  try {
14472
- execSync22(`npm install open-agents-nexus@${latestRaw} --save 2>&1`, {
14481
+ await execAsync2(`npm install open-agents-nexus@${latestRaw} --save 2>&1`, {
14473
14482
  cwd: this.repoRoot,
14474
- stdio: "pipe",
14475
14483
  timeout: 6e4
14476
14484
  });
14477
14485
  installedVersion = latestRaw;
@@ -14483,14 +14491,13 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14483
14491
  }
14484
14492
  if (!nexusResolved) {
14485
14493
  try {
14486
- execSync22("npm install open-agents-nexus@latest 2>&1", {
14494
+ await execAsync2("npm install open-agents-nexus@latest 2>&1", {
14487
14495
  cwd: this.repoRoot,
14488
- stdio: "pipe",
14489
14496
  timeout: 12e4
14490
14497
  });
14491
14498
  } catch {
14492
14499
  try {
14493
- execSync22("npm install -g open-agents-nexus@latest 2>&1", { stdio: "pipe", timeout: 12e4 });
14500
+ await execAsync2("npm install -g open-agents-nexus@latest 2>&1", { timeout: 12e4 });
14494
14501
  } catch {
14495
14502
  throw new Error("Failed to install open-agents-nexus. Run: npm install open-agents-nexus");
14496
14503
  }
@@ -14503,7 +14510,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14503
14510
  const agentType = args.agent_type || "general";
14504
14511
  const nodePaths = [nodeModulesDir];
14505
14512
  try {
14506
- const globalDir = execSync22("npm root -g", { encoding: "utf8", timeout: 5e3 }).trim();
14513
+ const globalDir = await execAsync2("npm root -g", { timeout: 5e3 });
14507
14514
  nodePaths.push(globalDir);
14508
14515
  } catch {
14509
14516
  }
@@ -29312,8 +29319,10 @@ var init_expose = __esm({
29312
29319
  if (responseTail.length > 2048) {
29313
29320
  responseTail = responseTail.slice(-2048);
29314
29321
  }
29315
- if (isStreaming)
29322
+ if (isStreaming) {
29316
29323
  this.emit("token_flash");
29324
+ this.emit("stream_data", { content: text, model: requestModel, peer: userIp });
29325
+ }
29317
29326
  });
29318
29327
  if (isStreaming) {
29319
29328
  if (proxyRes.statusCode !== 200) {
@@ -40257,9 +40266,10 @@ async function handleUpdate(subcommand, ctx) {
40257
40266
  }
40258
40267
  const info = await checkForUpdate(currentVersion, true);
40259
40268
  const { exec: exec4, execSync: es2 } = await import("node:child_process");
40269
+ const execA = (cmd, opts) => new Promise((res, rej) => exec4(cmd, { encoding: "utf8", timeout: opts?.timeout ?? 3e4, cwd: opts?.cwd }, (err, stdout) => err ? rej(err) : res((stdout || "").trim())));
40260
40270
  let needsSudo = false;
40261
40271
  try {
40262
- const prefix = es2("npm prefix -g", { encoding: "utf8", timeout: 5e3 }).trim();
40272
+ const prefix = await execA("npm prefix -g", { timeout: 5e3 });
40263
40273
  const { accessSync, constants } = await import("node:fs");
40264
40274
  try {
40265
40275
  accessSync(prefix, constants.W_OK);
@@ -40363,10 +40373,10 @@ async function handleUpdate(subcommand, ctx) {
40363
40373
  if (!installOk && /ENOTEMPTY|errno -39/i.test(installError)) {
40364
40374
  installSpinner.stop("Cleaning stale npm temp files...");
40365
40375
  try {
40366
- const prefix = es2("npm prefix -g", { encoding: "utf8", timeout: 5e3 }).trim();
40376
+ const prefix = await execA("npm prefix -g", { timeout: 5e3 });
40367
40377
  const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
40368
- es2(`${sudoPrefix}find "${globalModules}" -maxdepth 1 -name ".open-agents-ai-*" -type d -exec rm -rf {} + 2>/dev/null || true`, { timeout: 15e3 });
40369
- es2(`${sudoPrefix}rm -rf "${globalModules}/open-agents-ai" 2>/dev/null || true`, { timeout: 15e3 });
40378
+ await execA(`${sudoPrefix}find "${globalModules}" -maxdepth 1 -name ".open-agents-ai-*" -type d -exec rm -rf {} + 2>/dev/null || true`, { timeout: 15e3 });
40379
+ await execA(`${sudoPrefix}rm -rf "${globalModules}/open-agents-ai" 2>/dev/null || true`, { timeout: 15e3 });
40370
40380
  } catch {
40371
40381
  }
40372
40382
  const retrySpinner = startInlineSpinner("Retrying install");
@@ -40390,7 +40400,7 @@ async function handleUpdate(subcommand, ctx) {
40390
40400
  if (doDeps) {
40391
40401
  const depsSpinner = startInlineSpinner("Updating subordinate dependencies");
40392
40402
  try {
40393
- const prefix = es2("npm prefix -g", { encoding: "utf8", timeout: 5e3 }).trim();
40403
+ const prefix = await execA("npm prefix -g", { timeout: 5e3 });
40394
40404
  const globalModules = prefix.endsWith("/lib") ? prefix + "/node_modules" : prefix + "/lib/node_modules";
40395
40405
  const { existsSync: fe, readFileSync: rf } = await import("node:fs");
40396
40406
  const { join: pj } = await import("node:path");
@@ -40653,28 +40663,78 @@ async function showExposeDashboard(gateway, rl, ctx) {
40653
40663
  }
40654
40664
  return;
40655
40665
  }
40666
+ const cols = () => process.stdout.columns ?? 80;
40667
+ const rows = () => process.stdout.rows ?? 24;
40656
40668
  const peerLedColor = (peerIdx) => {
40657
40669
  const stops = [51, 81, 111, 141, 171, 201];
40658
40670
  const code = stops[Math.min(peerIdx, stops.length - 1)] ?? 51;
40659
40671
  return `\x1B[38;5;${code}m\u25CF\x1B[0m`;
40660
40672
  };
40661
- while (true) {
40673
+ const streamLog = [];
40674
+ const MAX_STREAM_ENTRIES = 200;
40675
+ function extractStreamContent(raw) {
40676
+ let result = "";
40677
+ const lines = raw.split("\n");
40678
+ for (const line of lines) {
40679
+ if (!line.startsWith("data: "))
40680
+ continue;
40681
+ const json = line.slice(6).trim();
40682
+ if (json === "[DONE]")
40683
+ continue;
40684
+ try {
40685
+ const obj = JSON.parse(json);
40686
+ if (obj.response)
40687
+ result += obj.response;
40688
+ else if (obj.message?.content)
40689
+ result += obj.message.content;
40690
+ else if (obj.choices?.[0]?.delta?.content)
40691
+ result += obj.choices[0].delta.content;
40692
+ } catch {
40693
+ }
40694
+ }
40695
+ return result;
40696
+ }
40697
+ const onStreamData = (data) => {
40698
+ const tokens = extractStreamContent(data.content);
40699
+ if (!tokens)
40700
+ return;
40701
+ streamLog.push({ time: Date.now(), model: data.model, peer: data.peer, content: tokens });
40702
+ if (streamLog.length > MAX_STREAM_ENTRIES)
40703
+ streamLog.splice(0, streamLog.length - MAX_STREAM_ENTRIES);
40704
+ scheduleRender();
40705
+ };
40706
+ let renderTimer = null;
40707
+ let refreshTimer = null;
40708
+ let stopped = false;
40709
+ function scheduleRender() {
40710
+ if (stopped)
40711
+ return;
40712
+ if (renderTimer)
40713
+ return;
40714
+ renderTimer = setTimeout(() => {
40715
+ renderTimer = null;
40716
+ renderDashboard();
40717
+ }, 50);
40718
+ }
40719
+ function renderDashboard() {
40720
+ if (stopped)
40721
+ return;
40662
40722
  const s = gateway.stats ?? gateway._stats;
40663
40723
  const now = Date.now();
40724
+ const w = cols();
40725
+ const h = rows();
40664
40726
  const uptime = s ? fmtUptime(now - (s.startedAt || now)) : "0s";
40665
- const statusColor = !s ? c2.dim : s.status === "active" ? c2.green : s.status === "error" ? c2.red : c2.yellow;
40727
+ const lines = [];
40728
+ const statusDot = !s ? c2.dim("\u25CF") : s.status === "active" ? c2.green("\u25CF") : s.status === "error" ? c2.red("\u25CF") : c2.yellow("\u25CF");
40666
40729
  const statusLabel = s?.status || "unknown";
40667
- const items = [];
40668
- const skipKeys = [];
40669
- items.push({ key: "hdr_status", label: selectColors.dim(`\u2500\u2500\u2500 ${statusColor("\u25CF")} ${statusLabel} uptime ${uptime} \u2500\u2500\u2500`), kind: "header" });
40670
- skipKeys.push("hdr_status");
40730
+ lines.push("");
40731
+ lines.push(` ${c2.bold("Expose Dashboard")} ${statusDot} ${statusLabel} ${c2.dim("uptime")} ${uptime} ${c2.dim((/* @__PURE__ */ new Date()).toLocaleTimeString())}`);
40671
40732
  const isTunnel = !!gateway.tunnelUrl;
40672
40733
  const isP2P = !!gateway.peerId;
40673
40734
  const endpointId = isTunnel ? gateway.tunnelUrl : isP2P ? gateway.peerId : null;
40674
40735
  const authKey = gateway.authKey ?? "";
40675
40736
  if (endpointId) {
40676
- const endpointCmd = `/endpoint ${endpointId} --auth ${authKey}`;
40677
- items.push({ key: "endpoint", label: "\u{1F517} Endpoint", detail: endpointCmd, kind: "action" });
40737
+ lines.push(` ${c2.dim("Endpoint:")} ${c2.cyan(`/endpoint ${endpointId} --auth ${authKey}`)}`);
40678
40738
  }
40679
40739
  if (s) {
40680
40740
  const totalReqs = s.totalRequests || 0;
@@ -40682,23 +40742,22 @@ async function showExposeDashboard(gateway, rl, ctx) {
40682
40742
  const tokIn = s.totalTokensIn || 0;
40683
40743
  const tokOut = s.totalTokensOut || 0;
40684
40744
  const errors = s.errors || 0;
40685
- const statsLine = `Req: ${totalReqs} Active: ${activeConns} Err: ${errors} Tok \u2191${fmtDashTokens(tokIn)} \u2193${fmtDashTokens(tokOut)}`;
40686
- items.push({ key: "info_stats", label: c2.dim(statsLine), kind: "info" });
40687
- skipKeys.push("info_stats");
40745
+ const activeDot = activeConns > 0 ? c2.green(`\u25CF ${activeConns}`) : c2.dim("0");
40746
+ lines.push("");
40747
+ lines.push(` ${c2.dim("Req")} ${c2.bold(String(totalReqs))} ${c2.dim("Active")} ${activeDot} ${c2.dim("Err")} ${errors > 0 ? c2.red(String(errors)) : c2.dim("0")} ${c2.dim("Tok")} \u2191${c2.cyan(fmtDashTokens(tokIn))} \u2193${c2.cyan(fmtDashTokens(tokOut))}`);
40688
40748
  if (s.budgetTokensTotal > 0) {
40689
40749
  const pct = Math.round(s.budgetTokensRemaining / s.budgetTokensTotal * 100);
40690
40750
  const budgetColor = pct > 50 ? c2.green : pct > 20 ? c2.yellow : c2.red;
40691
40751
  const barLen = 20;
40692
40752
  const filledLen = Math.round(pct / 100 * barLen);
40693
40753
  const bar = budgetColor("\u2588".repeat(filledLen)) + c2.dim("\u2591".repeat(barLen - filledLen));
40694
- items.push({ key: "info_budget", label: ` Budget ${bar} ${budgetColor(`${pct}%`)}`, kind: "info" });
40695
- skipKeys.push("info_budget");
40754
+ lines.push(` ${c2.dim("Budget")} ${bar} ${budgetColor(`${pct}%`)}`);
40696
40755
  }
40697
40756
  }
40698
40757
  const modelEntries = s?.modelUsage ? Array.from(s.modelUsage.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40699
40758
  if (modelEntries.length > 0) {
40700
- items.push({ key: "hdr_models", label: selectColors.dim(`\u2500\u2500\u2500 Models (${modelEntries.length}) \u2500\u2500\u2500`), kind: "header" });
40701
- skipKeys.push("hdr_models");
40759
+ lines.push("");
40760
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Models (" + modelEntries.length + ") \u2500\u2500\u2500")}`);
40702
40761
  for (const [model, count] of modelEntries) {
40703
40762
  let mIn = 0, mOut = 0;
40704
40763
  if (s?.users) {
@@ -40710,19 +40769,14 @@ async function showExposeDashboard(gateway, rl, ctx) {
40710
40769
  }
40711
40770
  }
40712
40771
  }
40713
- const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 10))) : "";
40714
- items.push({
40715
- key: `model_${model}`,
40716
- label: `${model}`,
40717
- detail: `${count} req \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`,
40718
- kind: "model"
40719
- });
40772
+ const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 20))) : "";
40773
+ lines.push(` ${c2.cyan(model)} ${c2.dim(`${count}req`)} \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`);
40720
40774
  }
40721
40775
  }
40722
40776
  const users = s?.users ? Array.from(s.users.values()) : [];
40723
40777
  if (users.length > 0) {
40724
- items.push({ key: "hdr_peers", label: selectColors.dim(`\u2500\u2500\u2500 Peers (${users.length}) \u2500\u2500\u2500`), kind: "header" });
40725
- skipKeys.push("hdr_peers");
40778
+ lines.push("");
40779
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Peers (" + users.length + ") \u2500\u2500\u2500")}`);
40726
40780
  for (let i = 0; i < users.length; i++) {
40727
40781
  const user = users[i];
40728
40782
  const ageSec = Math.floor((now - (user.firstSeen || now)) / 1e3);
@@ -40732,90 +40786,134 @@ async function showExposeDashboard(gateway, rl, ctx) {
40732
40786
  const activeFlag = (user.activeRequests || 0) > 0 ? ` ${c2.green(`\u25CF ${user.activeRequests} active`)}` : "";
40733
40787
  const led = peerLedColor(i);
40734
40788
  const peerTok = `\u2191${fmtDashTokens(user.tokensIn || 0)} \u2193${fmtDashTokens(user.tokensOut || 0)}`;
40735
- items.push({
40736
- key: `peer_${user.ip || i}`,
40737
- label: `${led} ${user.ip || "unknown"}${activeFlag}`,
40738
- detail: `${user.requests || 0}req ${peerTok} ${c2.dim(ageStr)} last: ${lastStr}`,
40739
- kind: "peer"
40740
- });
40789
+ lines.push(` ${led} ${user.ip || "unknown"}${activeFlag} ${c2.dim(`${user.requests || 0}req`)} ${peerTok} ${c2.dim(ageStr)} ${c2.dim("last:")} ${lastStr}`);
40741
40790
  }
40742
40791
  }
40743
40792
  const sys = getLocalSystemMetrics();
40744
- items.push({ key: "hdr_system", label: selectColors.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500"), kind: "header" });
40745
- skipKeys.push("hdr_system");
40793
+ lines.push("");
40794
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500")}`);
40746
40795
  const cpuColor = sys.cpuUtil > 80 ? c2.red : sys.cpuUtil > 50 ? c2.yellow : c2.green;
40747
40796
  const memColor = sys.memUtil > 80 ? c2.red : sys.memUtil > 50 ? c2.yellow : c2.green;
40748
- let sysLine = `CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
40797
+ let sysLine = ` CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
40749
40798
  if (sys.gpuAvailable) {
40750
40799
  const gpuColor = sys.gpuUtil > 80 ? c2.red : sys.gpuUtil > 50 ? c2.yellow : c2.green;
40751
40800
  const vramColor = sys.vramUtil > 80 ? c2.red : sys.vramUtil > 50 ? c2.yellow : c2.green;
40752
40801
  sysLine += ` GPU ${gpuColor(sys.gpuUtil + "%")} VRAM ${vramColor(sys.vramUtil + "%")} (${sys.vramUsedMB}/${sys.vramTotalMB}MB)`;
40753
40802
  }
40754
- items.push({ key: "info_system", label: c2.dim(sysLine), kind: "info" });
40755
- skipKeys.push("info_system");
40756
- items.push({ key: "hdr_actions", label: selectColors.dim("\u2500\u2500\u2500 Actions \u2500\u2500\u2500"), kind: "header" });
40757
- skipKeys.push("hdr_actions");
40758
- items.push({ key: "refresh", label: "\u{1F504} Refresh", detail: "Rebuild dashboard with latest data", kind: "action" });
40759
- items.push({ key: "stop", label: "\u{1F6D1} Stop Gateway", detail: "Shut down the expose gateway", kind: "action" });
40760
- const result = await tuiSelect({
40761
- items,
40762
- title: "Expose Dashboard",
40763
- rl,
40764
- skipKeys,
40765
- availableRows: ctx?.availableContentRows?.()
40766
- });
40767
- if (!result.confirmed || !result.key)
40768
- break;
40769
- switch (result.key) {
40770
- case "endpoint": {
40771
- const id = isTunnel ? gateway.tunnelUrl : gateway.peerId;
40772
- const cmd = `/endpoint ${id} --auth ${authKey}`;
40773
- if (process.stdout.isTTY && id) {
40774
- const b64 = Buffer.from(cmd).toString("base64");
40775
- process.stdout.write(`\x1B]52;c;${b64}\x07`);
40776
- }
40777
- process.stdout.write(`
40778
- ${c2.bold("Endpoint command")} ${c2.dim("(copied to clipboard)")}
40779
- ${c2.cyan(cmd)}
40780
-
40781
- `);
40782
- await new Promise((resolve32) => {
40783
- const onData = () => {
40784
- process.stdin.removeListener("data", onData);
40785
- resolve32();
40786
- };
40787
- process.stdin.once("data", onData);
40788
- });
40789
- continue;
40803
+ lines.push(` ${c2.dim(sysLine)}`);
40804
+ const metricsLines = lines.length;
40805
+ const streamAreaHeight = Math.max(3, h - metricsLines - 3);
40806
+ lines.push("");
40807
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Live Token Stream \u2500\u2500\u2500")}`);
40808
+ if (streamLog.length === 0) {
40809
+ lines.push(` ${c2.dim("Waiting for streaming requests...")}`);
40810
+ for (let i = 1; i < streamAreaHeight - 1; i++)
40811
+ lines.push("");
40812
+ } else {
40813
+ const maxContentW = Math.max(20, w - 6);
40814
+ const recentEntries = [];
40815
+ for (let i = streamLog.length - 1; i >= 0 && recentEntries.length < streamAreaHeight - 1; i--) {
40816
+ const entry = streamLog[i];
40817
+ const clean = entry.content.replace(/\n/g, "\u23CE").replace(/[\x00-\x1F\x7F]/g, "");
40818
+ if (!clean)
40819
+ continue;
40820
+ const truncated = clean.length > maxContentW ? clean.slice(0, maxContentW - 1) + "\u2026" : clean;
40821
+ recentEntries.unshift(` \x1B[38;5;245m${truncated}\x1B[0m`);
40822
+ }
40823
+ while (recentEntries.length < streamAreaHeight - 1)
40824
+ recentEntries.unshift("");
40825
+ const visible = recentEntries.slice(-(streamAreaHeight - 1));
40826
+ lines.push(...visible);
40827
+ }
40828
+ const footerLine = ` ${c2.dim("q")} exit ${c2.dim("s")} stop gateway ${c2.dim("c")} copy endpoint ${c2.dim("auto-refresh 1s")}`;
40829
+ lines.push(footerLine);
40830
+ const frame = "\x1B[H\x1B[2J" + lines.join("\n") + "\n";
40831
+ overlayWrite(frame);
40832
+ }
40833
+ const onStats = () => scheduleRender();
40834
+ gateway.on("stats", onStats);
40835
+ gateway.on("stream_data", onStreamData);
40836
+ const savedRlListeners = [];
40837
+ if (rl) {
40838
+ rl.pause();
40839
+ for (const event of ["keypress", "data"]) {
40840
+ const listeners = process.stdin.listeners(event);
40841
+ for (const fn of listeners) {
40842
+ savedRlListeners.push({ event, fn });
40843
+ process.stdin.removeListener(event, fn);
40844
+ }
40845
+ }
40846
+ }
40847
+ const hadRawMode = process.stdin.isRaw;
40848
+ if (typeof process.stdin.setRawMode === "function") {
40849
+ process.stdin.setRawMode(true);
40850
+ }
40851
+ process.stdin.resume();
40852
+ enterOverlay();
40853
+ overlayWrite("\x1B[?1049h\x1B[?25l");
40854
+ renderDashboard();
40855
+ refreshTimer = setInterval(() => {
40856
+ renderDashboard();
40857
+ }, 1e3);
40858
+ let stopGateway = false;
40859
+ await new Promise((resolve32) => {
40860
+ const onData = (data) => {
40861
+ const key = data.toString();
40862
+ if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
40863
+ resolve32();
40864
+ return;
40790
40865
  }
40791
- case "refresh":
40792
- continue;
40793
- // Loop rebuilds items with fresh data
40794
- case "stop":
40795
- await ctx?.exposeStop?.();
40796
- renderInfo("Expose gateway stopped.");
40866
+ if (key === "s" || key === "S") {
40867
+ stopGateway = true;
40868
+ resolve32();
40797
40869
  return;
40798
- default:
40799
- if (result.key.startsWith("peer_")) {
40800
- const peerId = result.key.slice(5);
40801
- const user = users.find((u) => (u.ip || String(users.indexOf(u))) === peerId);
40802
- if (user) {
40803
- const userModels = user.models ? Array.from(user.models.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40804
- if (userModels.length > 0) {
40805
- process.stdout.write(`
40806
- ${c2.bold(user.ip || "unknown")} \u2014 model usage:
40807
- `);
40808
- for (const [m, mm] of userModels) {
40809
- process.stdout.write(` ${c2.cyan(m)} ${c2.dim(`${mm.requests}req \u2191${fmtDashTokens(mm.tokensIn)} \u2193${fmtDashTokens(mm.tokensOut)}`)}
40810
- `);
40811
- }
40812
- process.stdout.write("\n");
40813
- }
40814
- }
40815
- continue;
40870
+ }
40871
+ if (key === "c" || key === "C") {
40872
+ const id = gateway.tunnelUrl ?? gateway.peerId ?? null;
40873
+ if (id) {
40874
+ const cmd = `/endpoint ${id} --auth ${gateway.authKey ?? ""}`;
40875
+ const b64 = Buffer.from(cmd).toString("base64");
40876
+ overlayWrite(`\x1B]52;c;${b64}\x07`);
40877
+ overlayWrite(`\x1B[${rows()}H\x1B[2K ${c2.green("\u2713 Copied to clipboard")}`);
40878
+ setTimeout(() => scheduleRender(), 1500);
40816
40879
  }
40817
- continue;
40880
+ }
40881
+ };
40882
+ process.stdin.on("data", onData);
40883
+ const cleanup = () => {
40884
+ stopped = true;
40885
+ process.stdin.removeListener("data", onData);
40886
+ };
40887
+ const origResolve = resolve32;
40888
+ resolve32 = (() => {
40889
+ cleanup();
40890
+ origResolve();
40891
+ });
40892
+ });
40893
+ if (renderTimer) {
40894
+ clearTimeout(renderTimer);
40895
+ renderTimer = null;
40896
+ }
40897
+ if (refreshTimer) {
40898
+ clearInterval(refreshTimer);
40899
+ refreshTimer = null;
40900
+ }
40901
+ gateway.removeListener("stats", onStats);
40902
+ gateway.removeListener("stream_data", onStreamData);
40903
+ overlayWrite("\x1B[?25h\x1B[?1049l");
40904
+ leaveOverlay();
40905
+ if (typeof process.stdin.setRawMode === "function") {
40906
+ process.stdin.setRawMode(hadRawMode ?? false);
40907
+ }
40908
+ if (rl) {
40909
+ for (const { event, fn } of savedRlListeners) {
40910
+ process.stdin.on(event, fn);
40818
40911
  }
40912
+ rl.resume();
40913
+ }
40914
+ if (stopGateway) {
40915
+ await ctx?.exposeStop?.();
40916
+ renderInfo("Expose gateway stopped.");
40819
40917
  }
40820
40918
  }
40821
40919
  var DASH_INTERNAL;
@@ -40834,6 +40932,7 @@ var init_commands = __esm({
40834
40932
  init_listen();
40835
40933
  init_dist();
40836
40934
  init_tui_select();
40935
+ init_overlay_lock();
40837
40936
  init_drop_panel();
40838
40937
  init_neovim_mode();
40839
40938
  DASH_INTERNAL = /* @__PURE__ */ new Set(["system_metrics", "__list_capabilities"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.105.5",
3
+ "version": "0.105.7",
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",