open-agents-ai 0.104.25 → 0.104.27

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 +172 -175
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -365,7 +365,7 @@ var init_updater = __esm({
365
365
  "packages/cli/dist/updater.js"() {
366
366
  "use strict";
367
367
  PACKAGE_NAME = "open-agents-ai";
368
- CHECK_INTERVAL_MS = 60 * 60 * 1e3;
368
+ CHECK_INTERVAL_MS = 60 * 1e3;
369
369
  CACHE_DIR = join2(homedir2(), ".open-agents");
370
370
  CACHE_FILE = join2(CACHE_DIR, "update-check.json");
371
371
  }
@@ -38243,7 +38243,7 @@ async function handleSlashCommand(input, ctx) {
38243
38243
  renderWarning("No active expose gateway.");
38244
38244
  return "handled";
38245
38245
  }
38246
- await showExposeDashboard(gateway, ctx.rl);
38246
+ await showExposeDashboard(gateway, ctx.rl, ctx);
38247
38247
  return "handled";
38248
38248
  }
38249
38249
  if (arg === "config") {
@@ -38304,9 +38304,13 @@ async function handleSlashCommand(input, ctx) {
38304
38304
  try {
38305
38305
  const tunnelUrl = await ctx.exposeStart(kindOrUrl, exposeAuthKey, exposeTransport, exposeFullAccess);
38306
38306
  if (tunnelUrl) {
38307
- const info = ctx.getExposeInfo?.();
38308
- if (info) {
38309
- process.stdout.write("\n" + info.stats + "\n\n");
38307
+ const gw = ctx.getExposeGateway?.();
38308
+ if (gw) {
38309
+ await showExposeDashboard(gw, ctx.rl, ctx);
38310
+ } else {
38311
+ const info = ctx.getExposeInfo?.();
38312
+ if (info)
38313
+ process.stdout.write("\n" + info.stats + "\n\n");
38310
38314
  }
38311
38315
  } else {
38312
38316
  renderError("Failed to start expose gateway.");
@@ -39889,7 +39893,12 @@ async function handleUpdate(subcommand, ctx) {
39889
39893
  }
39890
39894
  };
39891
39895
  }
39892
- safeWrite("\n");
39896
+ process.stdout.write("\x1B[?1049h\x1B[H\x1B[2J");
39897
+ process.stdout.write(`
39898
+ ${c2.bold("Open Agents Update")}
39899
+ ${c2.dim("\u2500".repeat(40))}
39900
+
39901
+ `);
39893
39902
  const checkSpinner = startInlineSpinner(`Checking for updates ${c2.dim(`(current: v${currentVersion})`)}`);
39894
39903
  const info = await checkForUpdate(currentVersion, true);
39895
39904
  const { exec: exec4, execSync: es2 } = await import("node:child_process");
@@ -39914,6 +39923,7 @@ async function handleUpdate(subcommand, ctx) {
39914
39923
  child.stdout?.resume();
39915
39924
  });
39916
39925
  if (needsSudo) {
39926
+ process.stdout.write("\x1B[?1049l");
39917
39927
  renderInfo("Global npm directory requires elevated permissions.");
39918
39928
  renderInfo("You'll be asked for your password once \u2014 it covers all update steps.");
39919
39929
  safeWrite("\n");
@@ -39923,6 +39933,12 @@ async function handleUpdate(subcommand, ctx) {
39923
39933
  renderWarning("Could not acquire sudo credentials. Try: sudo npm i -g open-agents-ai");
39924
39934
  return;
39925
39935
  }
39936
+ process.stdout.write("\x1B[?1049h\x1B[H\x1B[2J");
39937
+ process.stdout.write(`
39938
+ ${c2.bold("Open Agents Update")}
39939
+ ${c2.dim("\u2500".repeat(40))}
39940
+
39941
+ `);
39926
39942
  }
39927
39943
  const sudoPrefix = needsSudo ? "sudo " : "";
39928
39944
  let primaryUpdated = false;
@@ -39959,6 +39975,7 @@ async function handleUpdate(subcommand, ctx) {
39959
39975
  renderWarning(`Error:
39960
39976
  ${errPreview}`);
39961
39977
  renderWarning(`Try manually: ${sudoPrefix}npm i -g open-agents-ai`);
39978
+ process.stdout.write("\x1B[?1049l");
39962
39979
  return;
39963
39980
  }
39964
39981
  installSpinner.stop(`Update installed (v${info.latestVersion}).`);
@@ -39989,6 +40006,8 @@ async function handleUpdate(subcommand, ctx) {
39989
40006
  if (!primaryUpdated && !depsUpdated) {
39990
40007
  renderInfo("Everything is up to date \u2014 no changes needed.");
39991
40008
  safeWrite("\n");
40009
+ await new Promise((r) => setTimeout(r, 1e3));
40010
+ process.stdout.write("\x1B[?1049l");
39992
40011
  return;
39993
40012
  }
39994
40013
  const rebuildSpinner = startInlineSpinner("Rebuilding native modules");
@@ -40061,6 +40080,7 @@ async function handleUpdate(subcommand, ctx) {
40061
40080
  const hadActiveTask = ctx.savePendingTaskState?.() ?? false;
40062
40081
  const resumeFlag = hadActiveTask ? "1" : "update-only";
40063
40082
  reloadSpinner.stop("Reloading\u2026");
40083
+ process.stdout.write("\x1B[?1049l");
40064
40084
  const { execPath, argv } = process;
40065
40085
  try {
40066
40086
  const { execFileSync } = await import("node:child_process");
@@ -40070,7 +40090,6 @@ async function handleUpdate(subcommand, ctx) {
40070
40090
  env: { ...process.env, __OA_RESUMED: resumeFlag }
40071
40091
  });
40072
40092
  } catch {
40073
- reloadSpinner.stop("Reload failed.");
40074
40093
  renderWarning("Restart oa manually to use the new version.");
40075
40094
  }
40076
40095
  }
@@ -40207,74 +40226,62 @@ function getLocalSystemMetrics() {
40207
40226
  }
40208
40227
  return result;
40209
40228
  }
40210
- async function showExposeDashboard(gateway, rl) {
40211
- const stdin = process.stdin;
40212
- const stdout = process.stdout;
40213
- if (!stdin.isTTY) {
40229
+ async function showExposeDashboard(gateway, rl, ctx) {
40230
+ if (!process.stdin.isTTY) {
40214
40231
  if (typeof gateway.formatStats === "function") {
40215
- stdout.write("\n" + gateway.formatStats() + "\n\n");
40232
+ process.stdout.write("\n" + gateway.formatStats() + "\n\n");
40216
40233
  }
40217
40234
  return;
40218
40235
  }
40219
- let lastRenderedLines = 0;
40220
- let refreshTimer = null;
40221
- const hadRawMode = stdin.isRaw;
40222
- let sysMetrics = getLocalSystemMetrics();
40223
- const savedListeners = rl ? stdin.listeners("data").slice() : [];
40224
- if (rl) {
40225
- rl.pause();
40226
- for (const fn of savedListeners)
40227
- stdin.removeListener("data", fn);
40228
- }
40229
- stdin.setRawMode(true);
40230
- stdin.resume();
40231
- stdout.write("\x1B[?25l");
40232
- function buildDashboard() {
40236
+ const peerLedColor = (peerIdx) => {
40237
+ const stops = [51, 81, 111, 141, 171, 201];
40238
+ const code = stops[Math.min(peerIdx, stops.length - 1)] ?? 51;
40239
+ return `\x1B[38;5;${code}m\u25CF\x1B[0m`;
40240
+ };
40241
+ while (true) {
40233
40242
  const s = gateway.stats ?? gateway._stats;
40234
- if (!s)
40235
- return [" No stats available.", "", " Press Escape or 'q' to close."];
40236
- const lines = [];
40237
40243
  const now = Date.now();
40238
- const uptime = fmtUptime(now - (s.startedAt || now));
40239
- const statusColor = s.status === "active" ? c2.green : s.status === "error" ? c2.red : c2.yellow;
40240
- lines.push("");
40241
- lines.push(` ${c2.bold("Expose Dashboard")} ${statusColor("\u25CF")} ${statusColor(s.status || "unknown")} ${c2.dim(`uptime ${uptime}`)}`);
40242
- lines.push(` ${c2.dim("\u2500".repeat(60))}`);
40243
- const activeConns = s.activeConnections || 0;
40244
- const totalReqs = s.totalRequests || 0;
40245
- const errors = s.errors || 0;
40246
- const tokIn = s.totalTokensIn || 0;
40247
- const tokOut = s.totalTokensOut || 0;
40248
- lines.push(` ${c2.cyan("Requests")} ${c2.bold(String(totalReqs))} ${c2.dim("|")} ${c2.cyan("Active")} ${activeConns > 0 ? c2.green(c2.bold(String(activeConns))) : c2.dim("0")} ${c2.dim("|")} ${c2.cyan("Errors")} ${errors > 0 ? c2.red(String(errors)) : c2.dim("0")}`);
40249
- lines.push(` ${c2.cyan("Tokens")} ${c2.dim("in:")}${c2.bold(fmtDashTokens(tokIn))} ${c2.dim("out:")}${c2.bold(fmtDashTokens(tokOut))} ${c2.dim("total:")}${fmtDashTokens(tokIn + tokOut)}`);
40250
- if (s.budgetTokensTotal > 0) {
40251
- const pct = Math.round(s.budgetTokensRemaining / s.budgetTokensTotal * 100);
40252
- const budgetColor = pct > 50 ? c2.green : pct > 20 ? c2.yellow : c2.red;
40253
- const barLen = 20;
40254
- const filledLen = Math.round(pct / 100 * barLen);
40255
- const bar = budgetColor("\u2588".repeat(filledLen)) + c2.dim("\u2591".repeat(barLen - filledLen));
40256
- lines.push(` ${c2.cyan("Budget")} ${bar} ${budgetColor(`${pct}%`)} ${c2.dim(`(${fmtDashTokens(s.budgetTokensRemaining)}/${fmtDashTokens(s.budgetTokensTotal)})`)}`);
40257
- }
40258
- const sys = sysMetrics;
40259
- lines.push("");
40260
- lines.push(` ${c2.bold("System")}`);
40261
- const cpuColor = sys.cpuUtil > 80 ? c2.red : sys.cpuUtil > 50 ? c2.yellow : c2.green;
40262
- const memColor = sys.memUtil > 80 ? c2.red : sys.memUtil > 50 ? c2.yellow : c2.green;
40263
- lines.push(` ${c2.cyan("CPU")} ${cpuColor(sys.cpuUtil + "%")} ${c2.dim(`(${sys.cpuCores} cores, ${sys.cpuModel.slice(0, 40)})`)}`);
40264
- lines.push(` ${c2.cyan("RAM")} ${memColor(sys.memUtil + "%")} ${c2.dim(`(${sys.memUsedGB}/${sys.memTotalGB} GB)`)}`);
40265
- if (sys.gpuAvailable) {
40266
- const gpuColor = sys.gpuUtil > 80 ? c2.red : sys.gpuUtil > 50 ? c2.yellow : c2.green;
40267
- const vramColor = sys.vramUtil > 80 ? c2.red : sys.vramUtil > 50 ? c2.yellow : c2.green;
40268
- lines.push(` ${c2.cyan("GPU")} ${gpuColor(sys.gpuUtil + "%")} ${c2.dim(`(${sys.gpuName.trim()})`)}`);
40269
- lines.push(` ${c2.cyan("VRAM")} ${vramColor(sys.vramUtil + "%")} ${c2.dim(`(${sys.vramUsedMB}/${sys.vramTotalMB} MB)`)}`);
40270
- }
40271
- const modelEntries = s.modelUsage ? Array.from(s.modelUsage.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40244
+ const uptime = s ? fmtUptime(now - (s.startedAt || now)) : "0s";
40245
+ const statusColor = !s ? c2.dim : s.status === "active" ? c2.green : s.status === "error" ? c2.red : c2.yellow;
40246
+ const statusLabel = s?.status || "unknown";
40247
+ const items = [];
40248
+ const skipKeys = [];
40249
+ items.push({ key: "hdr_status", label: selectColors.dim(`\u2500\u2500\u2500 ${statusColor("\u25CF")} ${statusLabel} uptime ${uptime} \u2500\u2500\u2500`), kind: "header" });
40250
+ skipKeys.push("hdr_status");
40251
+ const isTunnel = !!gateway.tunnelUrl;
40252
+ const isP2P = !!gateway.peerId;
40253
+ const endpointId = isTunnel ? gateway.tunnelUrl : isP2P ? gateway.peerId : null;
40254
+ const authKey = gateway.authKey ?? "";
40255
+ if (endpointId) {
40256
+ const endpointCmd = `/endpoint ${endpointId} --auth ${authKey}`;
40257
+ items.push({ key: "endpoint", label: "\u{1F517} Endpoint", detail: endpointCmd, kind: "action" });
40258
+ }
40259
+ if (s) {
40260
+ const totalReqs = s.totalRequests || 0;
40261
+ const activeConns = s.activeConnections || 0;
40262
+ const tokIn = s.totalTokensIn || 0;
40263
+ const tokOut = s.totalTokensOut || 0;
40264
+ const errors = s.errors || 0;
40265
+ const statsLine = `Req: ${totalReqs} Active: ${activeConns} Err: ${errors} Tok \u2191${fmtDashTokens(tokIn)} \u2193${fmtDashTokens(tokOut)}`;
40266
+ items.push({ key: "info_stats", label: c2.dim(statsLine), kind: "info" });
40267
+ skipKeys.push("info_stats");
40268
+ if (s.budgetTokensTotal > 0) {
40269
+ const pct = Math.round(s.budgetTokensRemaining / s.budgetTokensTotal * 100);
40270
+ const budgetColor = pct > 50 ? c2.green : pct > 20 ? c2.yellow : c2.red;
40271
+ const barLen = 20;
40272
+ const filledLen = Math.round(pct / 100 * barLen);
40273
+ const bar = budgetColor("\u2588".repeat(filledLen)) + c2.dim("\u2591".repeat(barLen - filledLen));
40274
+ items.push({ key: "info_budget", label: ` Budget ${bar} ${budgetColor(`${pct}%`)}`, kind: "info" });
40275
+ skipKeys.push("info_budget");
40276
+ }
40277
+ }
40278
+ const modelEntries = s?.modelUsage ? Array.from(s.modelUsage.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40272
40279
  if (modelEntries.length > 0) {
40273
- lines.push("");
40274
- lines.push(` ${c2.bold("Models")}`);
40280
+ items.push({ key: "hdr_models", label: selectColors.dim(`\u2500\u2500\u2500 Models (${modelEntries.length}) \u2500\u2500\u2500`), kind: "header" });
40281
+ skipKeys.push("hdr_models");
40275
40282
  for (const [model, count] of modelEntries) {
40276
40283
  let mIn = 0, mOut = 0;
40277
- if (s.users) {
40284
+ if (s?.users) {
40278
40285
  for (const user of s.users.values()) {
40279
40286
  const mm = user.models?.get?.(model);
40280
40287
  if (mm) {
@@ -40283,123 +40290,113 @@ async function showExposeDashboard(gateway, rl) {
40283
40290
  }
40284
40291
  }
40285
40292
  }
40286
- const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 20))) : "";
40287
- lines.push(` ${c2.cyan(model.padEnd(35))} ${c2.bold(String(count).padStart(4))} req ${c2.dim(`in:${fmtDashTokens(mIn).padStart(6)} out:${fmtDashTokens(mOut).padStart(6)}`)} ${bar}`);
40293
+ const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 10))) : "";
40294
+ items.push({
40295
+ key: `model_${model}`,
40296
+ label: `${model}`,
40297
+ detail: `${count} req \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`,
40298
+ kind: "model"
40299
+ });
40288
40300
  }
40289
40301
  }
40290
- const users = s.users ? Array.from(s.users.values()) : [];
40302
+ const users = s?.users ? Array.from(s.users.values()) : [];
40291
40303
  if (users.length > 0) {
40292
- lines.push("");
40293
- lines.push(` ${c2.bold("Connected Peers")} (${users.length})`);
40294
- for (const user of users) {
40304
+ items.push({ key: "hdr_peers", label: selectColors.dim(`\u2500\u2500\u2500 Peers (${users.length}) \u2500\u2500\u2500`), kind: "header" });
40305
+ skipKeys.push("hdr_peers");
40306
+ for (let i = 0; i < users.length; i++) {
40307
+ const user = users[i];
40295
40308
  const ageSec = Math.floor((now - (user.firstSeen || now)) / 1e3);
40296
- const ageStr = ageSec < 60 ? `${ageSec}s` : ageSec < 3600 ? `${Math.floor(ageSec / 60)}m` : `${Math.floor(ageSec / 3600)}h${Math.floor(ageSec % 3600 / 60)}m`;
40309
+ const ageStr = ageSec < 60 ? `${ageSec}s` : ageSec < 3600 ? `${Math.floor(ageSec / 60)}m` : `${Math.floor(ageSec / 3600)}h`;
40297
40310
  const lastSec = Math.floor((now - (user.lastSeen || now)) / 1e3);
40298
40311
  const lastStr = lastSec < 5 ? c2.green("now") : lastSec < 60 ? `${lastSec}s ago` : `${Math.floor(lastSec / 60)}m ago`;
40299
- const activeStr = (user.activeRequests || 0) > 0 ? c2.green(` \u25CF ${user.activeRequests} active`) : "";
40300
- lines.push(` ${c2.bold(user.ip || "unknown")}${activeStr}`);
40301
- lines.push(` ${c2.dim("session")} ${ageStr} ${c2.dim("last")} ${lastStr} ${c2.dim("reqs")} ${user.requests || 0} ${c2.dim("tok")} ${c2.cyan("in:")}${fmtDashTokens(user.tokensIn || 0)} ${c2.cyan("out:")}${fmtDashTokens(user.tokensOut || 0)}`);
40302
- const userModels = user.models ? Array.from(user.models.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40303
- for (const [m, mm] of userModels) {
40304
- lines.push(` ${c2.dim("\u2514")} ${c2.cyan(m)} ${c2.dim(`${mm.requests || 0}req ${fmtDashTokens((mm.tokensIn || 0) + (mm.tokensOut || 0))}tok`)}`);
40305
- }
40306
- }
40307
- }
40308
- lines.push("");
40309
- lines.push(` ${c2.dim("Press Escape or 'q' to close \u2502 Live \u25CF updates every 2s")}`);
40310
- lines.push("");
40311
- return lines;
40312
- }
40313
- function render() {
40314
- sysMetrics = getLocalSystemMetrics();
40315
- const lines = buildDashboard();
40316
- if (lastRenderedLines > 0) {
40317
- stdout.write(`\x1B[${lastRenderedLines}A`);
40318
- for (let i = 0; i < lastRenderedLines; i++) {
40319
- stdout.write("\x1B[2K\n");
40320
- }
40321
- stdout.write(`\x1B[${lastRenderedLines}A`);
40322
- }
40323
- stdout.write(lines.join("\n") + "\n");
40324
- lastRenderedLines = lines.length;
40325
- }
40326
- function cleanup() {
40327
- if (refreshTimer) {
40328
- clearInterval(refreshTimer);
40329
- refreshTimer = null;
40330
- }
40331
- gateway.removeListener?.("stats", onStats);
40332
- if (lastRenderedLines > 0) {
40333
- stdout.write(`\x1B[${lastRenderedLines}A`);
40334
- for (let i = 0; i < lastRenderedLines; i++) {
40335
- stdout.write("\x1B[2K\n");
40312
+ const activeFlag = (user.activeRequests || 0) > 0 ? ` ${c2.green(`\u25CF ${user.activeRequests} active`)}` : "";
40313
+ const led = peerLedColor(i);
40314
+ const peerTok = `\u2191${fmtDashTokens(user.tokensIn || 0)} \u2193${fmtDashTokens(user.tokensOut || 0)}`;
40315
+ items.push({
40316
+ key: `peer_${user.ip || i}`,
40317
+ label: `${led} ${user.ip || "unknown"}${activeFlag}`,
40318
+ detail: `${user.requests || 0}req ${peerTok} ${c2.dim(ageStr)} last: ${lastStr}`,
40319
+ kind: "peer"
40320
+ });
40336
40321
  }
40337
- stdout.write(`\x1B[${lastRenderedLines}A`);
40338
- }
40339
- stdout.write("\x1B[?25h");
40340
- stdin.setRawMode(hadRawMode ?? false);
40341
- stdin.removeListener("data", onKey);
40342
- if (rl) {
40343
- for (const fn of savedListeners)
40344
- stdin.on("data", fn);
40345
- rl.resume();
40346
- }
40347
- }
40348
- function onStats() {
40349
- render();
40350
- }
40351
- function onKey(chunk) {
40352
- const key = chunk.toString();
40353
- if (key === "\x1B" || key === "q" || key === "Q") {
40354
- cleanup();
40355
- return;
40356
- }
40357
- if (key === "") {
40358
- cleanup();
40359
- return;
40360
- }
40361
- }
40362
- if (typeof gateway.on === "function") {
40363
- gateway.on("stats", onStats);
40364
- }
40365
- refreshTimer = setInterval(render, 2e3);
40366
- render();
40367
- stdin.on("data", onKey);
40368
- return new Promise((resolve32) => {
40369
- const origCleanup = cleanup;
40370
- function wrappedCleanup() {
40371
- origCleanup();
40372
- resolve32();
40373
40322
  }
40374
- stdin.removeListener("data", onKey);
40375
- function onKeyWrapped(chunk) {
40376
- const key = chunk.toString();
40377
- if (key === "\x1B" || key === "q" || key === "Q" || key === "") {
40378
- if (refreshTimer) {
40379
- clearInterval(refreshTimer);
40380
- refreshTimer = null;
40323
+ const sys = getLocalSystemMetrics();
40324
+ items.push({ key: "hdr_system", label: selectColors.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500"), kind: "header" });
40325
+ skipKeys.push("hdr_system");
40326
+ const cpuColor = sys.cpuUtil > 80 ? c2.red : sys.cpuUtil > 50 ? c2.yellow : c2.green;
40327
+ const memColor = sys.memUtil > 80 ? c2.red : sys.memUtil > 50 ? c2.yellow : c2.green;
40328
+ let sysLine = `CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
40329
+ if (sys.gpuAvailable) {
40330
+ const gpuColor = sys.gpuUtil > 80 ? c2.red : sys.gpuUtil > 50 ? c2.yellow : c2.green;
40331
+ const vramColor = sys.vramUtil > 80 ? c2.red : sys.vramUtil > 50 ? c2.yellow : c2.green;
40332
+ sysLine += ` GPU ${gpuColor(sys.gpuUtil + "%")} VRAM ${vramColor(sys.vramUtil + "%")} (${sys.vramUsedMB}/${sys.vramTotalMB}MB)`;
40333
+ }
40334
+ items.push({ key: "info_system", label: c2.dim(sysLine), kind: "info" });
40335
+ skipKeys.push("info_system");
40336
+ items.push({ key: "hdr_actions", label: selectColors.dim("\u2500\u2500\u2500 Actions \u2500\u2500\u2500"), kind: "header" });
40337
+ skipKeys.push("hdr_actions");
40338
+ items.push({ key: "refresh", label: "\u{1F504} Refresh", detail: "Rebuild dashboard with latest data", kind: "action" });
40339
+ items.push({ key: "stop", label: "\u{1F6D1} Stop Gateway", detail: "Shut down the expose gateway", kind: "action" });
40340
+ const result = await tuiSelect({
40341
+ items,
40342
+ title: "Expose Dashboard",
40343
+ rl,
40344
+ skipKeys,
40345
+ availableRows: ctx?.availableContentRows?.()
40346
+ });
40347
+ if (!result.confirmed || !result.key)
40348
+ break;
40349
+ switch (result.key) {
40350
+ case "endpoint": {
40351
+ const id = isTunnel ? gateway.tunnelUrl : gateway.peerId;
40352
+ const cmd = `/endpoint ${id} --auth ${authKey}`;
40353
+ if (process.stdout.isTTY && id) {
40354
+ const b64 = Buffer.from(cmd).toString("base64");
40355
+ process.stdout.write(`\x1B]52;c;${b64}\x07`);
40381
40356
  }
40382
- gateway.removeListener?.("stats", onStats);
40383
- if (lastRenderedLines > 0) {
40384
- stdout.write(`\x1B[${lastRenderedLines}A`);
40385
- for (let i = 0; i < lastRenderedLines; i++) {
40386
- stdout.write("\x1B[2K\n");
40357
+ process.stdout.write(`
40358
+ ${c2.bold("Endpoint command")} ${c2.dim("(copied to clipboard)")}
40359
+ ${c2.cyan(cmd)}
40360
+
40361
+ `);
40362
+ await new Promise((resolve32) => {
40363
+ const onData = () => {
40364
+ process.stdin.removeListener("data", onData);
40365
+ resolve32();
40366
+ };
40367
+ process.stdin.once("data", onData);
40368
+ });
40369
+ continue;
40370
+ }
40371
+ case "refresh":
40372
+ continue;
40373
+ // Loop rebuilds items with fresh data
40374
+ case "stop":
40375
+ await ctx?.exposeStop?.();
40376
+ renderInfo("Expose gateway stopped.");
40377
+ return;
40378
+ default:
40379
+ if (result.key.startsWith("peer_")) {
40380
+ const peerId = result.key.slice(5);
40381
+ const user = users.find((u) => (u.ip || String(users.indexOf(u))) === peerId);
40382
+ if (user) {
40383
+ const userModels = user.models ? Array.from(user.models.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40384
+ if (userModels.length > 0) {
40385
+ process.stdout.write(`
40386
+ ${c2.bold(user.ip || "unknown")} \u2014 model usage:
40387
+ `);
40388
+ for (const [m, mm] of userModels) {
40389
+ process.stdout.write(` ${c2.cyan(m)} ${c2.dim(`${mm.requests}req \u2191${fmtDashTokens(mm.tokensIn)} \u2193${fmtDashTokens(mm.tokensOut)}`)}
40390
+ `);
40391
+ }
40392
+ process.stdout.write("\n");
40393
+ }
40387
40394
  }
40388
- stdout.write(`\x1B[${lastRenderedLines}A`);
40389
- }
40390
- stdout.write("\x1B[?25h");
40391
- stdin.setRawMode(hadRawMode ?? false);
40392
- stdin.removeListener("data", onKeyWrapped);
40393
- if (rl) {
40394
- for (const fn of savedListeners)
40395
- stdin.on("data", fn);
40396
- rl.resume();
40395
+ continue;
40397
40396
  }
40398
- resolve32();
40399
- }
40397
+ continue;
40400
40398
  }
40401
- stdin.on("data", onKeyWrapped);
40402
- });
40399
+ }
40403
40400
  }
40404
40401
  var DASH_INTERNAL;
40405
40402
  var init_commands = __esm({
@@ -48380,9 +48377,9 @@ var init_status_bar = __esm({
48380
48377
  const compactOrder = [];
48381
48378
  let modelSectionIdx = -1;
48382
48379
  let versionSectionIdx = -1;
48383
- if (this._exposeFlashOn) {
48384
- const ledColor = this._aliveLedColor();
48385
- const dot = `\x1B[38;5;${ledColor}m\u2B24\x1B[0m`;
48380
+ if (this._expose) {
48381
+ const ledColor = this._exposeFlashOn ? this._aliveLedColor() : 240;
48382
+ const dot = `\x1B[38;5;${ledColor}m\u25CF\x1B[0m`;
48386
48383
  sections.push({ expanded: dot, compact: dot, expandedW: 1, compactW: 1, empty: false });
48387
48384
  }
48388
48385
  const tokInRaw = m.promptTokens > 0 ? m.promptTokens : Math.max(m.estimatedContextTokens, 0);
@@ -50138,7 +50135,7 @@ async function startInteractive(config, repoPath) {
50138
50135
  }).catch(() => {
50139
50136
  });
50140
50137
  }
50141
- const AUTO_UPDATE_INTERVAL_MS = 30 * 60 * 1e3;
50138
+ const AUTO_UPDATE_INTERVAL_MS = 60 * 1e3;
50142
50139
  const autoUpdateTimer = setInterval(() => {
50143
50140
  const updateMode = savedSettings.updateMode ?? "auto";
50144
50141
  if (updateMode === "manual")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.104.25",
3
+ "version": "0.104.27",
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",