open-agents-ai 0.187.548 → 0.187.550

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.
package/dist/index.js CHANGED
@@ -7809,15 +7809,12 @@ async function handleCmd(cmd) {
7809
7809
  writeResp(id, { ok: true, output: JSON.stringify({ streaming: true, stream_file: icStreamFile }) });
7810
7810
  try {
7811
7811
  for await (var icEvt of icStreamGen) {
7812
- appendFileSync(icStreamFile, JSON.stringify({ type: 'event', event: icEvt.event || '', seq: icEvt.seq || 0, data: icEvt.data }) + '
7813
- ');
7812
+ appendFileSync(icStreamFile, JSON.stringify({ type: 'event', event: icEvt.event || '', seq: icEvt.seq || 0, data: icEvt.data }) + '\\n');
7814
7813
  }
7815
- appendFileSync(icStreamFile, JSON.stringify({ type: 'done' }) + '
7816
- ');
7814
+ appendFileSync(icStreamFile, JSON.stringify({ type: 'done' }) + '\\n');
7817
7815
  dlog('invoke_capability: stream complete');
7818
7816
  } catch (icStreamErr) {
7819
- appendFileSync(icStreamFile, JSON.stringify({ type: 'error', error: String(icStreamErr.message || icStreamErr) }) + '
7820
- ');
7817
+ appendFileSync(icStreamFile, JSON.stringify({ type: 'error', error: String(icStreamErr.message || icStreamErr) }) + '\\n');
7821
7818
  dlog('invoke_capability: stream error: ' + (icStreamErr.message || icStreamErr));
7822
7819
  }
7823
7820
  break;
@@ -539890,8 +539887,8 @@ async function transcribeFileViaWhisper(filePath, model) {
539890
539887
  child.stderr?.on("data", (d2) => {
539891
539888
  err += d2.toString("utf-8");
539892
539889
  });
539893
- child.on?.("error", () => stop2(null));
539894
- child.on?.("close", () => {
539890
+ child.once("error", () => stop2(null));
539891
+ child.once("close", () => {
539895
539892
  if (out.trim()) resolve43(parse3(out));
539896
539893
  else {
539897
539894
  void err;
@@ -587704,7 +587701,20 @@ async function handleGenerateShare(ctx3) {
587704
587701
  return true;
587705
587702
  }
587706
587703
  const directOnly = body["direct"] === true;
587707
- const peerInfo = directOnly ? null : resolveLocalPeerId();
587704
+ let peerInfo = directOnly ? null : resolveLocalPeerId();
587705
+ if (!directOnly && !peerInfo) {
587706
+ try {
587707
+ const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
587708
+ const repoRoot = process.env["OA_NEXUS_DIR"] ? String(process.env["OA_NEXUS_DIR"]).replace(/[\\/]\.oa[\\/]nexus$/, "") : process.cwd();
587709
+ const tool = new NexusTool2(repoRoot);
587710
+ await Promise.race([
587711
+ tool.execute({ action: "connect" }),
587712
+ new Promise((_r, rej) => setTimeout(() => rej(new Error("nexus connect 8s budget")), 8e3))
587713
+ ]).catch(() => null);
587714
+ peerInfo = resolveLocalPeerId();
587715
+ } catch {
587716
+ }
587717
+ }
587708
587718
  const scheme = String(req2.headers["x-forwarded-proto"] || (req2.socket?.encrypted ? "https" : "http"));
587709
587719
  const { getLocalOnion: getLocalOnion2 } = await Promise.resolve().then(() => (init_tor_fallback(), tor_fallback_exports));
587710
587720
  const onion = getLocalOnion2();
@@ -592427,11 +592437,13 @@ function installRemoteFetchProxy() {
592427
592437
  });
592428
592438
  if (wantsStream) {
592429
592439
  // Pass through as-is — receiver returns text/event-stream.
592430
- return _origFetch('/v1/remote-proxy', {
592440
+ const sResp = await _origFetch('/v1/remote-proxy', {
592431
592441
  method: 'POST',
592432
592442
  headers: { 'content-type': 'application/json', 'accept': 'text/event-stream' },
592433
592443
  body: proxyBody,
592434
592444
  });
592445
+ _handleRemoteProxyFailure(sResp);
592446
+ return sResp;
592435
592447
  }
592436
592448
  // Non-stream: receiver returns a JSON envelope { status, headers, body }.
592437
592449
  // Synthesize a Response that mimics the original remote response.
@@ -592440,7 +592452,10 @@ function installRemoteFetchProxy() {
592440
592452
  headers: { 'content-type': 'application/json' },
592441
592453
  body: proxyBody,
592442
592454
  });
592443
- if (!proxyResp.ok) return proxyResp;
592455
+ if (!proxyResp.ok) {
592456
+ _handleRemoteProxyFailure(proxyResp.clone());
592457
+ return proxyResp;
592458
+ }
592444
592459
  let env = null;
592445
592460
  try { env = await proxyResp.json(); } catch {}
592446
592461
  if (!env || typeof env !== 'object') {
@@ -592467,6 +592482,43 @@ function installRemoteFetchProxy() {
592467
592482
  return new Response(bodyText, { status, headers: headersOut });
592468
592483
  };
592469
592484
  }
592485
+ // ─── Remote-proxy failure recovery ──────────────────────────────────────
592486
+ // When /v1/remote-proxy returns 502/503 repeatedly, the remote peer is
592487
+ // unreachable (nexus dead, key revoked, target offline). Clear the
592488
+ // activeRemoteShare flag so the GUI exits the trapped state where every
592489
+ // fetch loops through a broken proxy. Surface a one-line banner so the
592490
+ // user knows what happened.
592491
+ let _remoteProxy502Count = 0;
592492
+ async function _handleRemoteProxyFailure(resp) {
592493
+ if (!resp || (resp.status !== 502 && resp.status !== 503)) {
592494
+ _remoteProxy502Count = 0;
592495
+ return;
592496
+ }
592497
+ _remoteProxy502Count++;
592498
+ // After 3 consecutive transport failures, give up and clear state.
592499
+ if (_remoteProxy502Count >= 3) {
592500
+ let detail = '';
592501
+ try { const j = await resp.json(); detail = j && (j.detail || j.message) ? String(j.detail || j.message) : ''; } catch {}
592502
+ try { localStorage.removeItem('oa.activeRemoteShare'); } catch {}
592503
+ _showRemoteRecoveryBanner(detail);
592504
+ _remoteProxy502Count = 0;
592505
+ // Reload after a beat so the freshly-cleared state propagates and
592506
+ // the original (non-proxied) fetch can succeed.
592507
+ setTimeout(() => { try { location.reload(); } catch {} }, 2500);
592508
+ }
592509
+ }
592510
+ function _showRemoteRecoveryBanner(detail) {
592511
+ if (document.getElementById('remote-recovery-banner')) return;
592512
+ const div = document.createElement('div');
592513
+ div.id = 'remote-recovery-banner';
592514
+ div.style.cssText = 'position:fixed;top:0;left:0;right:0;z-index:9999;background:var(--color-error);color:#fff;padding:8px 14px;font-size:0.78rem;font-family:inherit;display:flex;align-items:center;gap:10px';
592515
+ div.innerHTML =
592516
+ '<span>⚠ Remote share unreachable — disconnected. ' + (detail ? '(' + (String(detail).slice(0, 120).replace(/[<>&]/g, '')) + ') ' : '') + '</span>' +
592517
+ '<span style="flex:1"></span>' +
592518
+ '<button onclick="document.getElementById(\\'remote-recovery-banner\\').remove()" style="background:#fff2;color:#fff;border:1px solid #fff5;padding:2px 8px;border-radius:3px;cursor:pointer;font-size:0.74rem">dismiss</button>';
592519
+ document.body.appendChild(div);
592520
+ }
592521
+
592470
592522
  // Auto-install on every load if a remote share is active.
592471
592523
  try {
592472
592524
  if (getActiveRemoteShare()) installRemoteFetchProxy();
@@ -592661,13 +592713,30 @@ async function generateShareUrl() {
592661
592713
  const out = document.getElementById('share-result');
592662
592714
  if (!out) return;
592663
592715
  out.style.display = 'block';
592664
- out.innerHTML = '<div style="color:var(--color-fg-muted)">generating…</div>';
592716
+ // The first call after a daemon restart can take ~5-8s while the
592717
+ // backend wakes nexus. Show a visible progress hint so the user
592718
+ // knows nothing is hung.
592719
+ out.innerHTML =
592720
+ '<div style="color:var(--color-fg-muted)" id="share-progress">' +
592721
+ ' generating share key' +
592722
+ ' <span id="share-dots">…</span>' +
592723
+ ' <div style="font-size:0.68rem;margin-top:4px">waking nexus for global reach (up to 8s) — falls back to direct-HTTP if unavailable</div>' +
592724
+ '</div>';
592725
+ // Animated dots so the user sees it's alive.
592726
+ let _shareDotN = 1;
592727
+ const _shareDotsTimer = setInterval(() => {
592728
+ const el = document.getElementById('share-dots');
592729
+ if (!el) { clearInterval(_shareDotsTimer); return; }
592730
+ _shareDotN = (_shareDotN % 3) + 1;
592731
+ el.textContent = '.'.repeat(_shareDotN);
592732
+ }, 400);
592665
592733
  try {
592666
592734
  const r = await fetch('/v1/share/generate', {
592667
592735
  method: 'POST',
592668
592736
  headers: { ...headers(), 'Content-Type': 'application/json' },
592669
592737
  body: JSON.stringify({ scope: 'run' }),
592670
592738
  });
592739
+ clearInterval(_shareDotsTimer);
592671
592740
  if (r.status === 403) {
592672
592741
  out.innerHTML = '<div style="color:var(--color-error)">✗ admin scope required — your current key does not have permission to mint share URLs. Set an admin-scope key first.</div>';
592673
592742
  return;
@@ -592719,6 +592788,7 @@ async function generateShareUrl() {
592719
592788
  window.__oaLastTorUrl = j.torShareUrl || null;
592720
592789
  saveRecentKey({ key: j.key, host: j.host + ':' + j.port, label: j.label || ('shared ' + j.host) });
592721
592790
  } catch (e) {
592791
+ clearInterval(_shareDotsTimer);
592722
592792
  out.innerHTML = '<div style="color:var(--color-error)">✗ ' + escapeHtml(e && e.message ? e.message : String(e)) + '</div>';
592723
592793
  }
592724
592794
  }
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.548",
3
+ "version": "0.187.550",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.548",
9
+ "version": "0.187.550",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
@@ -4930,9 +4930,9 @@
4930
4930
  }
4931
4931
  },
4932
4932
  "node_modules/node-abi": {
4933
- "version": "3.91.0",
4934
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.91.0.tgz",
4935
- "integrity": "sha512-B+S7X/GS3Un6wMICtnsNjQD7oSpVBQrZftHE6GZ1Fe9/k3XOOoqbM5DZZ0GO4x3YiSCQfrM28yj1ppplwgIsfg==",
4933
+ "version": "3.92.0",
4934
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz",
4935
+ "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==",
4936
4936
  "license": "MIT",
4937
4937
  "dependencies": {
4938
4938
  "semver": "^7.3.5"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.548",
3
+ "version": "0.187.550",
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",