open-agents-ai 0.187.303 → 0.187.305

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 +122 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -288212,7 +288212,8 @@ function matchRow(item, focused, isActive) {
288212
288212
  return ` ${marker} ${label}${detail}`;
288213
288213
  }
288214
288214
  function tuiSelect(opts) {
288215
- const { items, title, rl } = opts;
288215
+ const { items, rl } = opts;
288216
+ let currentTitle = opts.title;
288216
288217
  const renderRow = opts.renderRow ?? defaultRenderRow;
288217
288218
  const activeKey = opts.activeKey ?? null;
288218
288219
  const skipSet = new Set(opts.skipKeys ?? []);
@@ -288309,9 +288310,9 @@ function tuiSelect(opts) {
288309
288310
  lines.push(`
288310
288311
  ${selectColors.cyan("←")} ${trail}`);
288311
288312
  }
288312
- if (title) {
288313
+ if (currentTitle) {
288313
288314
  if (!hasBreadcrumbs) lines.push("");
288314
- lines.push(` ${selectColors.bold(title)}`);
288315
+ lines.push(` ${selectColors.bold(currentTitle)}`);
288315
288316
  }
288316
288317
  if (filter2) {
288317
288318
  const count = matchSet.size;
@@ -288383,7 +288384,12 @@ ${tuiBgSeq()}`);
288383
288384
  overlayWrite(tuiBgSeq() + output + "\x1B[K");
288384
288385
  lastRenderedLines = lines.length;
288385
288386
  }
288387
+ let externalCleanup = null;
288386
288388
  function cleanup() {
288389
+ try {
288390
+ externalCleanup?.();
288391
+ } catch {
288392
+ }
288387
288393
  stdin.removeListener("data", onData);
288388
288394
  process.stdout.removeListener("resize", onResize);
288389
288395
  overlayWrite("\x1B[?1003l\x1B[?1002l\x1B[?1000l\x1B[?1006l\x1B[?1049l\x1B[?25h");
@@ -288399,6 +288405,16 @@ ${tuiBgSeq()}`);
288399
288405
  rl.prompt?.(false);
288400
288406
  }
288401
288407
  }
288408
+ const updateItem = (index, updates) => {
288409
+ if (index >= 0 && index < items.length) {
288410
+ Object.assign(items[index], updates);
288411
+ render2();
288412
+ }
288413
+ };
288414
+ const setTitle = (title) => {
288415
+ currentTitle = title;
288416
+ render2();
288417
+ };
288402
288418
  function onData(chunk) {
288403
288419
  let seq = chunk.toString("utf8");
288404
288420
  const mouseRe = /\x1B\[<(\d+);(\d+);(\d+)([Mm])/g;
@@ -288626,10 +288642,7 @@ ${tuiBgSeq()}`);
288626
288642
  },
288627
288643
  getInput: (prompt, prefill) => getInputFromUser(prompt, prefill),
288628
288644
  render: () => render2(),
288629
- updateItem: (index, updates) => {
288630
- Object.assign(items[index], updates);
288631
- render2();
288632
- }
288645
+ updateItem
288633
288646
  });
288634
288647
  if (consumed) return;
288635
288648
  }
@@ -288765,6 +288778,20 @@ ${tuiBgSeq()}`);
288765
288778
  process.stdout.on("resize", onResize);
288766
288779
  stdin.on("data", onData);
288767
288780
  render2();
288781
+ if (opts.onInit) {
288782
+ const maybeCleanup = opts.onInit({
288783
+ render: () => render2(),
288784
+ updateItem,
288785
+ setTitle,
288786
+ resolve: (result) => {
288787
+ cleanup();
288788
+ resolve40(result);
288789
+ }
288790
+ });
288791
+ if (typeof maybeCleanup === "function") {
288792
+ externalCleanup = maybeCleanup;
288793
+ }
288794
+ }
288768
288795
  });
288769
288796
  }
288770
288797
  var isTTY2, selectColors;
@@ -320447,13 +320474,24 @@ function headers() {
320447
320474
  return h;
320448
320475
  }
320449
320476
 
320477
+ let seenVersion = '';
320478
+
320450
320479
  // Health check
320451
320480
  async function checkHealth() {
320452
320481
  try {
320453
- const r = await fetch('/health');
320482
+ const r = await fetch('/health', { cache: 'no-store' });
320454
320483
  const d = await r.json();
320455
320484
  statusEl.textContent = 'connected (' + d.version + ')';
320456
320485
  statusEl.className = 'status live';
320486
+ // Detect daemon version bump and refresh UI to new frontend bundle/state
320487
+ if (!seenVersion) {
320488
+ seenVersion = d.version || '';
320489
+ } else if (d.version && seenVersion && d.version !== seenVersion) {
320490
+ // Force a hard reload to pick up any UI changes
320491
+ try { localStorage.setItem('oa-last-version', d.version); } catch {}
320492
+ location.reload();
320493
+ return;
320494
+ }
320457
320495
  } catch {
320458
320496
  statusEl.textContent = 'disconnected';
320459
320497
  statusEl.className = 'status';
@@ -322566,6 +322604,7 @@ async function doUpdate() {
322566
322604
  btn.style.background = '#1a3a1a';
322567
322605
  btn.style.borderColor = '#4ec94e';
322568
322606
  btn.style.color = '#4ec94e';
322607
+ try { seenVersion = newVersion || seenVersion; } catch {}
322569
322608
 
322570
322609
  // Flash status bar
322571
322610
  const statusEl = document.getElementById('status');
@@ -322587,6 +322626,20 @@ async function doUpdate() {
322587
322626
  }, 6000);
322588
322627
  }
322589
322628
 
322629
+ // Poll for version bumps even if the update was triggered elsewhere (CLI)
322630
+ async function pollVersionBump() {
322631
+ try {
322632
+ const r = await fetch('/version', { cache: 'no-store' });
322633
+ const j = await r.json();
322634
+ const v = j.version || '';
322635
+ if (!seenVersion) seenVersion = v;
322636
+ if (v && seenVersion && v !== seenVersion) {
322637
+ try { localStorage.setItem('oa-last-version', v); } catch {}
322638
+ location.reload();
322639
+ }
322640
+ } catch {}
322641
+ }
322642
+
322590
322643
  // ═══════════════════════════════════════════════════════════════════
322591
322644
  // Live process dots — SSE subscription to /v1/events
322592
322645
  // ═══════════════════════════════════════════════════════════════════
@@ -323179,6 +323232,7 @@ updateAgentRunSelect(); // WO-TASK-02 — populate agent runs dropdown
323179
323232
  restoreChatSession(); // WO-CHAT-RESUME — rehydrate from server state
323180
323233
  setInterval(checkHealth, 30000);
323181
323234
  setInterval(pollMetrics, 10000);
323235
+ setInterval(pollVersionBump, 5000);
323182
323236
  input.focus();
323183
323237
  </script>
323184
323238
  </body>
@@ -326247,6 +326301,7 @@ async function handleV1Update(req2, res, requestId) {
326247
326301
  const fs4 = __require("node:fs");
326248
326302
  const nodeBin = process.execPath;
326249
326303
  const nodeDir = dirname29(nodeBin);
326304
+ const { execSync: es } = __require("node:child_process");
326250
326305
  const isWin2 = process.platform === "win32";
326251
326306
  let npmBin = "";
326252
326307
  for (const candidate of isWin2 ? [join99(nodeDir, "npm.cmd"), join99(nodeDir, "npm")] : [join99(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
@@ -326261,12 +326316,40 @@ async function handleV1Update(req2, res, requestId) {
326261
326316
  fs4.mkdirSync(dir, { recursive: true });
326262
326317
  const logFd = fs4.openSync(logPath2, "w");
326263
326318
  const npmPrefix = dirname29(nodeDir);
326319
+ let globalBinDir = "";
326320
+ try {
326321
+ if (isWin2) {
326322
+ globalBinDir = es(`${npmBin} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
326323
+ } else {
326324
+ const npmCliCandidates = [
326325
+ join99(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
326326
+ join99(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
326327
+ ];
326328
+ let npmCli = "";
326329
+ for (const c7 of npmCliCandidates) {
326330
+ try {
326331
+ if (existsSync83(c7)) {
326332
+ npmCli = c7;
326333
+ break;
326334
+ }
326335
+ } catch {
326336
+ }
326337
+ }
326338
+ if (npmCli) {
326339
+ globalBinDir = es(`${JSON.stringify(nodeBin)} ${JSON.stringify(npmCli)} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
326340
+ } else {
326341
+ globalBinDir = es(`${npmBin} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
326342
+ }
326343
+ }
326344
+ } catch {
326345
+ }
326264
326346
  const cleanEnv = {};
326265
326347
  for (const [k, v] of Object.entries(process.env)) {
326266
326348
  if (k === "OA_DAEMON" || k === "OA_PORT") continue;
326267
326349
  if (typeof v === "string") cleanEnv[k] = v;
326268
326350
  }
326269
- cleanEnv.PATH = `${nodeDir}:${cleanEnv.PATH || ""}`;
326351
+ const pathParts = [globalBinDir, nodeDir, cleanEnv.PATH || ""].filter(Boolean);
326352
+ cleanEnv.PATH = pathParts.join(":");
326270
326353
  let child;
326271
326354
  if (isWin2) {
326272
326355
  child = spawn25(npmBin, ["install", "-g", pkgSpec, "--no-audit", "--no-fund", "--no-progress"], {
@@ -326313,13 +326396,22 @@ async function handleV1Update(req2, res, requestId) {
326313
326396
  stdio: "ignore"
326314
326397
  });
326315
326398
  follower.unref();
326399
+ let hasSystemdUnit = false;
326400
+ try {
326401
+ const out = es("systemctl --user is-active open-agents-daemon.service 2>/dev/null", { encoding: "utf8", timeout: 2e3, stdio: "pipe" }).trim();
326402
+ hasSystemdUnit = out === "active" || out === "activating";
326403
+ } catch {
326404
+ }
326405
+ let oaAbs = "oa";
326406
+ try {
326407
+ const which = es("command -v oa 2>/dev/null || which oa 2>/dev/null", { encoding: "utf8", timeout: 2e3, stdio: "pipe", env: cleanEnv }).trim();
326408
+ if (which) oaAbs = which;
326409
+ } catch {
326410
+ }
326316
326411
  const relaunchScript = [
326317
326412
  `while kill -0 ${installPid} 2>/dev/null; do sleep 1; done`,
326318
- // Short grace period before restart
326319
326413
  `sleep 1`,
326320
- // Use PATH to pick up the freshly installed oa; background and disown
326321
- `oa serve --quiet --daemon >/dev/null 2>&1 & disown`,
326322
- // Terminate current daemon so the new one can bind the port
326414
+ hasSystemdUnit ? `systemctl --user restart open-agents-daemon.service >/dev/null 2>&1 || true` : `${JSON.stringify(oaAbs)} serve --quiet --daemon >/dev/null 2>&1 & disown`,
326323
326415
  `kill -TERM ${process.pid} >/dev/null 2>&1 || true`
326324
326416
  ].join("; ");
326325
326417
  const relauncher = spawn25("bash", ["-c", relaunchScript], {
@@ -334526,19 +334618,6 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
334526
334618
  renderInfo2(`Last task: ${lastTask}${lastEntry.task && lastEntry.task.length > 80 ? "..." : ""}`);
334527
334619
  });
334528
334620
  let countdown = 10;
334529
- let selectDone = false;
334530
- const autoTimer = setInterval(() => {
334531
- if (selectDone) return;
334532
- countdown--;
334533
- if (countdown <= 0) {
334534
- selectDone = true;
334535
- clearInterval(autoTimer);
334536
- try {
334537
- rl.feed("\x1B");
334538
- } catch {
334539
- }
334540
- }
334541
- }, 1e3);
334542
334621
  const selectResult = await tuiSelect({
334543
334622
  items: [
334544
334623
  { key: "restore", label: `Restore previous context (auto in ${countdown}s)` },
@@ -334547,18 +334626,30 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
334547
334626
  activeKey: "restore",
334548
334627
  title: `Restore previous session?`,
334549
334628
  rl,
334550
- availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0
334629
+ availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0,
334630
+ onInit: ({ updateItem, resolve: resolve40 }) => {
334631
+ const timer = setInterval(() => {
334632
+ countdown -= 1;
334633
+ if (countdown >= 0) {
334634
+ updateItem(0, { label: `Restore previous context (auto in ${countdown}s)` });
334635
+ }
334636
+ if (countdown <= 0) {
334637
+ clearInterval(timer);
334638
+ resolve40({ confirmed: true, key: "restore", index: 0 });
334639
+ }
334640
+ }, 1e3);
334641
+ return () => clearInterval(timer);
334642
+ }
334551
334643
  });
334552
- clearInterval(autoTimer);
334553
- selectDone = true;
334554
- const doRestore = selectResult.confirmed ? selectResult.key === "restore" : countdown <= 0;
334644
+ const auto = countdown <= 0;
334645
+ const doRestore = selectResult.confirmed && selectResult.key === "restore";
334555
334646
  if (doRestore) {
334556
334647
  const prompt = buildContextRestorePrompt(repoRoot);
334557
334648
  if (prompt) {
334558
334649
  restoredSessionContext = prompt;
334559
334650
  const info = loadSessionContext(repoRoot);
334560
334651
  writeContent(() => renderInfo2(
334561
- countdown <= 0 ? `Context auto-restored from ${info?.entries.length ?? 0} session(s).` : `Context restored from ${info?.entries.length ?? 0} session(s).`
334652
+ auto ? `Context auto-restored from ${info?.entries.length ?? 0} session(s).` : `Context restored from ${info?.entries.length ?? 0} session(s).`
334562
334653
  ));
334563
334654
  } else {
334564
334655
  writeContent(() => renderInfo2("No context to restore. Starting fresh."));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.303",
3
+ "version": "0.187.305",
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",