open-agents-ai 0.187.534 → 0.187.536

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
@@ -7783,11 +7783,41 @@ async function handleCmd(cmd) {
7783
7783
  const capability = args.capability || 'text-generation';
7784
7784
  const input = args.input || {};
7785
7785
  if (!peerId) { writeResp(id, { ok: false, output: 'target_peer is required' }); return; }
7786
- dlog('invoke_capability: peer=' + peerId.slice(0, 20) + ' cap=' + capability);
7786
+ // Streaming mode: when stream_file is supplied, tee invoke events
7787
+ // to the file as JSONL so the caller can tail them in real time.
7788
+ const icStreamFile = typeof args.stream_file === 'string' ? args.stream_file : '';
7789
+ const icUseStream = !!icStreamFile;
7790
+ dlog('invoke_capability: peer=' + peerId.slice(0, 20) + ' cap=' + capability + (icUseStream ? ' [stream]' : ''));
7787
7791
  try {
7788
- // Race libp2p + NATS in parallel — whichever route works first wins
7789
7792
  const INVOKE_TIMEOUT = 300_000;
7790
7793
  const invokeInput = typeof input === 'string' ? { prompt: input } : input;
7794
+ if (icUseStream) {
7795
+ // Stream-mode: get an AsyncGenerator and tee each event to the file.
7796
+ var icStreamGen;
7797
+ try {
7798
+ icStreamGen = await nexus.invokeCapability(peerId, capability, invokeInput, { stream: true, maxDurationMs: 240000 });
7799
+ } catch (invokeStartErr) {
7800
+ writeResp(id, { ok: false, output: 'Invoke start failed: ' + (invokeStartErr.message || invokeStartErr) });
7801
+ break;
7802
+ }
7803
+ // Signal the caller that streaming has begun.
7804
+ writeResp(id, { ok: true, output: JSON.stringify({ streaming: true, stream_file: icStreamFile }) });
7805
+ try {
7806
+ for await (var icEvt of icStreamGen) {
7807
+ appendFileSync(icStreamFile, JSON.stringify({ type: 'event', event: icEvt.event || '', seq: icEvt.seq || 0, data: icEvt.data }) + '
7808
+ ');
7809
+ }
7810
+ appendFileSync(icStreamFile, JSON.stringify({ type: 'done' }) + '
7811
+ ');
7812
+ dlog('invoke_capability: stream complete');
7813
+ } catch (icStreamErr) {
7814
+ appendFileSync(icStreamFile, JSON.stringify({ type: 'error', error: String(icStreamErr.message || icStreamErr) }) + '
7815
+ ');
7816
+ dlog('invoke_capability: stream error: ' + (icStreamErr.message || icStreamErr));
7817
+ }
7818
+ break;
7819
+ }
7820
+ // Non-stream mode: race libp2p + NATS in parallel.
7791
7821
  const invokePromise = nexus.invokeCapability(peerId, capability, invokeInput, { stream: false, maxDurationMs: 240000 });
7792
7822
  const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('invoke_capability timed out after ' + (INVOKE_TIMEOUT / 1000) + 's')), INVOKE_TIMEOUT));
7793
7823
 
@@ -9427,6 +9457,158 @@ process.on('unhandledRejection', (reason) => {
9427
9457
  }
9428
9458
  connected = true;
9429
9459
 
9460
+ // Register this nexus dir in the global registry so the API daemon
9461
+ // (and any other consumer) can discover us regardless of cwd.
9462
+ try {
9463
+ var nodePath_reg = require('node:path');
9464
+ var nodeFs_reg = require('node:fs');
9465
+ var nodeOs_reg = require('node:os');
9466
+ var regDir = nodePath_reg.join(nodeOs_reg.homedir(), '.open-agents');
9467
+ if (!nodeFs_reg.existsSync(regDir)) nodeFs_reg.mkdirSync(regDir, { recursive: true });
9468
+ var regFile = nodePath_reg.join(regDir, 'nexus-registry.json');
9469
+ var existing = { dirs: [] };
9470
+ try {
9471
+ if (nodeFs_reg.existsSync(regFile)) existing = JSON.parse(nodeFs_reg.readFileSync(regFile, 'utf-8')) || { dirs: [] };
9472
+ if (!Array.isArray(existing.dirs)) existing.dirs = [];
9473
+ } catch { existing = { dirs: [] }; }
9474
+ // Drop entries that no longer exist on disk
9475
+ existing.dirs = existing.dirs.filter(function(e) {
9476
+ var d = typeof e === 'string' ? e : (e && e.dir);
9477
+ return d && nodeFs_reg.existsSync(nodePath_reg.join(d, 'status.json'));
9478
+ });
9479
+ // De-dup + prepend ourselves
9480
+ var meDir = nexusDir;
9481
+ existing.dirs = existing.dirs.filter(function(e) {
9482
+ var d = typeof e === 'string' ? e : (e && e.dir);
9483
+ return d !== meDir;
9484
+ });
9485
+ existing.dirs.unshift({
9486
+ dir: meDir,
9487
+ peerId: nexus.peerId || '',
9488
+ pid: process.pid,
9489
+ startedAt: new Date().toISOString(),
9490
+ });
9491
+ // Cap at 16 entries
9492
+ if (existing.dirs.length > 16) existing.dirs = existing.dirs.slice(0, 16);
9493
+ nodeFs_reg.writeFileSync(regFile, JSON.stringify(existing, null, 2));
9494
+ dlog('nexus-registry: registered ' + meDir);
9495
+ } catch (regErr) {
9496
+ dlog('nexus-registry write failed: ' + (regErr.message || regErr));
9497
+ }
9498
+
9499
+ // http_tunnel capability — proxies HTTP requests from remote peers
9500
+ // to the local OA API daemon. Auth is delegated to the API key store
9501
+ // (remote sends share key in Authorization header). SSE streams are
9502
+ // forwarded chunk-by-chunk over libp2p invoke. The local API port is
9503
+ // read from nexusDir/api-port.json which oa serve writes on startup.
9504
+ if (typeof nexus.registerCapability === 'function') {
9505
+ var nodePathMod = require('node:path');
9506
+ var apiPortHintPath = nodePathMod.join(nexusDir, 'api-port.json');
9507
+ nexus.registerCapability('http_tunnel', async (request, stream) => {
9508
+ var htClosed = false;
9509
+ async function htWrite(msg) {
9510
+ if (htClosed) return;
9511
+ try { await stream.write(msg); } catch { htClosed = true; }
9512
+ }
9513
+ var htChunks = [];
9514
+ var htInputDone = false;
9515
+ stream.onData(function(msg) {
9516
+ if (msg.type === 'invoke.chunk') {
9517
+ htChunks.push(typeof msg.data === 'string' ? msg.data : JSON.stringify(msg.data));
9518
+ }
9519
+ if (msg.type === 'invoke.done' || msg.type === 'invoke.end') htInputDone = true;
9520
+ });
9521
+ await htWrite({ type: 'invoke.accept', version: 1, requestId: request.requestId, accepted: true });
9522
+ var htWait = 0;
9523
+ while (!htInputDone && htWait < 5000) {
9524
+ await new Promise(function(r) { setTimeout(r, 20); });
9525
+ htWait += 20;
9526
+ }
9527
+ var htReq;
9528
+ try {
9529
+ htReq = JSON.parse(htChunks.join(''));
9530
+ } catch (parseErr) {
9531
+ await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'http.error', data: 'Bad request JSON: ' + (parseErr.message || parseErr) });
9532
+ await htWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
9533
+ try { stream.close(); } catch {}
9534
+ return;
9535
+ }
9536
+ // Resolve API endpoint from sibling api-port.json
9537
+ var htApiHost = '127.0.0.1';
9538
+ var htApiPort = 11435;
9539
+ var htApiScheme = 'http';
9540
+ try {
9541
+ if (existsSync(apiPortHintPath)) {
9542
+ var apiCfg = JSON.parse(readFileSync(apiPortHintPath, 'utf-8'));
9543
+ if (typeof apiCfg.port === 'number' && apiCfg.port > 0) htApiPort = apiCfg.port;
9544
+ if (typeof apiCfg.scheme === 'string') htApiScheme = apiCfg.scheme;
9545
+ if (typeof apiCfg.host === 'string' && apiCfg.host) htApiHost = apiCfg.host;
9546
+ } else {
9547
+ dlog('http_tunnel: api-port.json missing — using defaults 127.0.0.1:11435');
9548
+ }
9549
+ } catch (cfgErr) {
9550
+ dlog('http_tunnel: api-port.json parse failed: ' + (cfgErr.message || cfgErr));
9551
+ }
9552
+ var htPath = typeof htReq.path === 'string' ? htReq.path : '/';
9553
+ if (!htPath.startsWith('/')) htPath = '/' + htPath;
9554
+ var htUrl = htApiScheme + '://' + htApiHost + ':' + htApiPort + htPath;
9555
+ var htMethod = (htReq.method || 'GET').toUpperCase();
9556
+ var htHeaders = (htReq.headers && typeof htReq.headers === 'object') ? Object.assign({}, htReq.headers) : {};
9557
+ // Inject auth — share key from req.key overrides any incoming auth
9558
+ if (typeof htReq.key === 'string' && htReq.key) {
9559
+ htHeaders['authorization'] = 'Bearer ' + htReq.key;
9560
+ }
9561
+ // Strip hop-by-hop headers that don't translate
9562
+ delete htHeaders['host'];
9563
+ delete htHeaders['connection'];
9564
+ delete htHeaders['content-length'];
9565
+ var htBodyInit;
9566
+ if (htMethod !== 'GET' && htMethod !== 'HEAD' && htReq.body !== undefined && htReq.body !== null) {
9567
+ if (typeof htReq.body === 'string') htBodyInit = htReq.body;
9568
+ else htBodyInit = JSON.stringify(htReq.body);
9569
+ if (!htHeaders['content-type']) htHeaders['content-type'] = 'application/json';
9570
+ }
9571
+ dlog('http_tunnel: ' + htMethod + ' ' + htPath + ' from ' + (request.from || '?').slice(0, 16));
9572
+ try {
9573
+ var htResp = await fetch(htUrl, {
9574
+ method: htMethod, headers: htHeaders, body: htBodyInit,
9575
+ });
9576
+ var htRespHeaders = {};
9577
+ htResp.headers.forEach(function(v, k) { htRespHeaders[k] = v; });
9578
+ var htCT = (htRespHeaders['content-type'] || '').toLowerCase();
9579
+ var htIsStream = htCT.includes('text/event-stream') || htCT.includes('application/x-ndjson');
9580
+ await htWrite({
9581
+ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0,
9582
+ event: 'http.head',
9583
+ data: JSON.stringify({ status: htResp.status, headers: htRespHeaders, streaming: htIsStream }),
9584
+ });
9585
+ var htSeq = 1;
9586
+ if (htIsStream && htResp.body) {
9587
+ var htReader = htResp.body.getReader();
9588
+ var htDecoder = new TextDecoder();
9589
+ while (true) {
9590
+ var htChunk = await htReader.read();
9591
+ if (htChunk.done) break;
9592
+ var htText = htDecoder.decode(htChunk.value, { stream: true });
9593
+ if (htText) {
9594
+ await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: htSeq++, event: 'http.chunk', data: htText });
9595
+ }
9596
+ }
9597
+ } else {
9598
+ var htBodyText = await htResp.text();
9599
+ await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: htSeq++, event: 'http.body', data: htBodyText });
9600
+ }
9601
+ await htWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
9602
+ } catch (htErr) {
9603
+ dlog('http_tunnel: fetch failed: ' + (htErr.message || htErr));
9604
+ await htWrite({ type: 'invoke.event', version: 1, requestId: request.requestId, seq: 0, event: 'http.error', data: String(htErr.message || htErr) });
9605
+ await htWrite({ type: 'invoke.done', version: 1, requestId: request.requestId, usage: { inputBytes: 0, outputBytes: 0 } });
9606
+ }
9607
+ try { stream.close(); } catch {}
9608
+ });
9609
+ dlog('http_tunnel capability registered (api hint: ' + apiPortHintPath + ')');
9610
+ }
9611
+
9430
9612
  // Monkey-patch node.dialProtocol AND node.dial to convert string multiaddrs
9431
9613
  // to proper Multiaddr objects. libp2p v3 transports call .getComponents()
9432
9614
  // on multiaddr objects, which fails on plain strings. open-agents-nexus
@@ -247683,11 +247865,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
247683
247865
  * what was previously computed. */
247684
247866
  async loadSessionInfo() {
247685
247867
  try {
247686
- const { readFileSync: readFileSync88, existsSync: existsSync109 } = await import("node:fs");
247868
+ const { readFileSync: readFileSync89, existsSync: existsSync110 } = await import("node:fs");
247687
247869
  const sessionPath2 = join28(this.cwd, ".oa", "rlm", "session.json");
247688
- if (!existsSync109(sessionPath2))
247870
+ if (!existsSync110(sessionPath2))
247689
247871
  return null;
247690
- return JSON.parse(readFileSync88(sessionPath2, "utf8"));
247872
+ return JSON.parse(readFileSync89(sessionPath2, "utf8"));
247691
247873
  } catch {
247692
247874
  return null;
247693
247875
  }
@@ -247864,10 +248046,10 @@ var init_memory_metabolism = __esm({
247864
248046
  const trajDir = join29(this.cwd, ".oa", "rlm-trajectories");
247865
248047
  let lessons = [];
247866
248048
  try {
247867
- const { readdirSync: readdirSync39, readFileSync: readFileSync88 } = await import("node:fs");
248049
+ const { readdirSync: readdirSync39, readFileSync: readFileSync89 } = await import("node:fs");
247868
248050
  const files = readdirSync39(trajDir).filter((f2) => f2.endsWith(".jsonl")).sort().reverse().slice(0, 3);
247869
248051
  for (const file of files) {
247870
- const lines = readFileSync88(join29(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
248052
+ const lines = readFileSync89(join29(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
247871
248053
  for (const line of lines) {
247872
248054
  try {
247873
248055
  const entry = JSON.parse(line);
@@ -248251,14 +248433,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
248251
248433
  * Optionally filter by task type for phase-aware context (FSM paper insight).
248252
248434
  */
248253
248435
  getTopMemoriesSync(k = 5, taskType) {
248254
- const { readFileSync: readFileSync88, existsSync: existsSync109 } = __require("node:fs");
248436
+ const { readFileSync: readFileSync89, existsSync: existsSync110 } = __require("node:fs");
248255
248437
  const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
248256
248438
  const storeFile = join29(metaDir, "store.json");
248257
- if (!existsSync109(storeFile))
248439
+ if (!existsSync110(storeFile))
248258
248440
  return "";
248259
248441
  let store2 = [];
248260
248442
  try {
248261
- store2 = JSON.parse(readFileSync88(storeFile, "utf8"));
248443
+ store2 = JSON.parse(readFileSync89(storeFile, "utf8"));
248262
248444
  } catch {
248263
248445
  return "";
248264
248446
  }
@@ -248280,14 +248462,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
248280
248462
  /** Update memory scores based on task outcome. Called after task completion.
248281
248463
  * Memories used in successful tasks get boosted. Memories present during failures get decayed. */
248282
248464
  updateFromOutcomeSync(surfacedMemoryText, succeeded) {
248283
- const { readFileSync: readFileSync88, writeFileSync: writeFileSync59, existsSync: existsSync109, mkdirSync: mkdirSync67 } = __require("node:fs");
248465
+ const { readFileSync: readFileSync89, writeFileSync: writeFileSync59, existsSync: existsSync110, mkdirSync: mkdirSync67 } = __require("node:fs");
248284
248466
  const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
248285
248467
  const storeFile = join29(metaDir, "store.json");
248286
- if (!existsSync109(storeFile))
248468
+ if (!existsSync110(storeFile))
248287
248469
  return;
248288
248470
  let store2 = [];
248289
248471
  try {
248290
- store2 = JSON.parse(readFileSync88(storeFile, "utf8"));
248472
+ store2 = JSON.parse(readFileSync89(storeFile, "utf8"));
248291
248473
  } catch {
248292
248474
  return;
248293
248475
  }
@@ -248734,13 +248916,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
248734
248916
  // Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
248735
248917
  /** Retrieve top-K strategies for context injection. Returns "" if none. */
248736
248918
  getRelevantStrategiesSync(k = 3, taskType) {
248737
- const { readFileSync: readFileSync88, existsSync: existsSync109 } = __require("node:fs");
248919
+ const { readFileSync: readFileSync89, existsSync: existsSync110 } = __require("node:fs");
248738
248920
  const archiveFile = join31(this.cwd, ".oa", "arche", "variants.json");
248739
- if (!existsSync109(archiveFile))
248921
+ if (!existsSync110(archiveFile))
248740
248922
  return "";
248741
248923
  let variants = [];
248742
248924
  try {
248743
- variants = JSON.parse(readFileSync88(archiveFile, "utf8"));
248925
+ variants = JSON.parse(readFileSync89(archiveFile, "utf8"));
248744
248926
  } catch {
248745
248927
  return "";
248746
248928
  }
@@ -248758,13 +248940,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
248758
248940
  }
248759
248941
  /** Archive a strategy variant synchronously (for task completion path) */
248760
248942
  archiveVariantSync(strategy, outcome, tags = []) {
248761
- const { readFileSync: readFileSync88, writeFileSync: writeFileSync59, existsSync: existsSync109, mkdirSync: mkdirSync67 } = __require("node:fs");
248943
+ const { readFileSync: readFileSync89, writeFileSync: writeFileSync59, existsSync: existsSync110, mkdirSync: mkdirSync67 } = __require("node:fs");
248762
248944
  const dir = join31(this.cwd, ".oa", "arche");
248763
248945
  const archiveFile = join31(dir, "variants.json");
248764
248946
  let variants = [];
248765
248947
  try {
248766
- if (existsSync109(archiveFile))
248767
- variants = JSON.parse(readFileSync88(archiveFile, "utf8"));
248948
+ if (existsSync110(archiveFile))
248949
+ variants = JSON.parse(readFileSync89(archiveFile, "utf8"));
248768
248950
  } catch {
248769
248951
  }
248770
248952
  variants.push({
@@ -257044,7 +257226,7 @@ var require_util9 = __commonJS({
257044
257226
  return path8;
257045
257227
  }
257046
257228
  exports.normalize = normalize2;
257047
- function join127(aRoot, aPath) {
257229
+ function join128(aRoot, aPath) {
257048
257230
  if (aRoot === "") {
257049
257231
  aRoot = ".";
257050
257232
  }
@@ -257076,7 +257258,7 @@ var require_util9 = __commonJS({
257076
257258
  }
257077
257259
  return joined;
257078
257260
  }
257079
- exports.join = join127;
257261
+ exports.join = join128;
257080
257262
  exports.isAbsolute = function(aPath) {
257081
257263
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
257082
257264
  };
@@ -257249,7 +257431,7 @@ var require_util9 = __commonJS({
257249
257431
  parsed.path = parsed.path.substring(0, index + 1);
257250
257432
  }
257251
257433
  }
257252
- sourceURL = join127(urlGenerate(parsed), sourceURL);
257434
+ sourceURL = join128(urlGenerate(parsed), sourceURL);
257253
257435
  }
257254
257436
  return normalize2(sourceURL);
257255
257437
  }
@@ -472669,7 +472851,7 @@ var require_path_browserify = __commonJS({
472669
472851
  assertPath(path8);
472670
472852
  return path8.length > 0 && path8.charCodeAt(0) === 47;
472671
472853
  },
472672
- join: function join127() {
472854
+ join: function join128() {
472673
472855
  if (arguments.length === 0)
472674
472856
  return ".";
472675
472857
  var joined;
@@ -522783,9 +522965,9 @@ var init_reflectionBuffer = __esm({
522783
522965
  this.persistPath = persistPath ?? null;
522784
522966
  if (this.persistPath) {
522785
522967
  try {
522786
- const { readFileSync: readFileSync88, existsSync: existsSync109 } = __require("node:fs");
522787
- if (existsSync109(this.persistPath)) {
522788
- this.state = JSON.parse(readFileSync88(this.persistPath, "utf-8"));
522968
+ const { readFileSync: readFileSync89, existsSync: existsSync110 } = __require("node:fs");
522969
+ if (existsSync110(this.persistPath)) {
522970
+ this.state = JSON.parse(readFileSync89(this.persistPath, "utf-8"));
522789
522971
  return;
522790
522972
  }
522791
522973
  } catch {
@@ -523018,10 +523200,10 @@ var init_reflectionBuffer = __esm({
523018
523200
  if (!this.persistPath)
523019
523201
  return;
523020
523202
  try {
523021
- const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: existsSync109 } = __require("node:fs");
523022
- const { join: join127 } = __require("node:path");
523023
- const dir = join127(this.persistPath, "..");
523024
- if (!existsSync109(dir))
523203
+ const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: existsSync110 } = __require("node:fs");
523204
+ const { join: join128 } = __require("node:path");
523205
+ const dir = join128(this.persistPath, "..");
523206
+ if (!existsSync110(dir))
523025
523207
  mkdirSync67(dir, { recursive: true });
523026
523208
  writeFileSync59(this.persistPath, JSON.stringify(this.state, null, 2));
523027
523209
  } catch {
@@ -533564,8 +533746,8 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
533564
533746
  this.emit({ type: "status", content: `Knowledge graph: ${nodes} nodes, ${edges} active edges`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
533565
533747
  try {
533566
533748
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
533567
- const { join: join127 } = __require("node:path");
533568
- const contextDir = join127(this._workingDirectory || process.cwd(), ".oa", "context");
533749
+ const { join: join128 } = __require("node:path");
533750
+ const contextDir = join128(this._workingDirectory || process.cwd(), ".oa", "context");
533569
533751
  mkdirSync67(contextDir, { recursive: true });
533570
533752
  const topEntities = this._temporalGraph.nodesByType("entity", 3);
533571
533753
  const topFiles = this._temporalGraph.nodesByType("file", 3);
@@ -533606,9 +533788,9 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
533606
533788
  section("Top Files", topFiles);
533607
533789
  section("Top Concepts", topConcepts);
533608
533790
  lines.push("(Use file_read on this file for quick recall. See provenance JSON for full edge detail.)");
533609
- const outPath = join127(contextDir, `kg-summary-${this._sessionId}.md`);
533791
+ const outPath = join128(contextDir, `kg-summary-${this._sessionId}.md`);
533610
533792
  writeFileSync59(outPath, lines.join("\n"), "utf-8");
533611
- writeFileSync59(join127(contextDir, `kg-summary-latest.md`), lines.join("\n"), "utf-8");
533793
+ writeFileSync59(join128(contextDir, `kg-summary-latest.md`), lines.join("\n"), "utf-8");
533612
533794
  } catch {
533613
533795
  }
533614
533796
  }
@@ -533777,10 +533959,10 @@ ${errOutput}`;
533777
533959
  });
533778
533960
  try {
533779
533961
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
533780
- const { join: join127 } = __require("node:path");
533781
- const resultsDir = join127(process.cwd(), ".oa", "tool-results");
533962
+ const { join: join128 } = __require("node:path");
533963
+ const resultsDir = join128(process.cwd(), ".oa", "tool-results");
533782
533964
  mkdirSync67(resultsDir, { recursive: true });
533783
- writeFileSync59(join127(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
533965
+ writeFileSync59(join128(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
533784
533966
  # Turn: ${turn}
533785
533967
  # Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
533786
533968
  # Size: ${result.output.length} chars, ${lineCount} lines
@@ -533997,8 +534179,8 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
533997
534179
  return;
533998
534180
  try {
533999
534181
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
534000
- const { join: join127 } = __require("node:path");
534001
- const sessionDir = join127(this._workingDirectory, ".oa", "session", this._sessionId);
534182
+ const { join: join128 } = __require("node:path");
534183
+ const sessionDir = join128(this._workingDirectory, ".oa", "session", this._sessionId);
534002
534184
  mkdirSync67(sessionDir, { recursive: true });
534003
534185
  const checkpoint = {
534004
534186
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -534011,7 +534193,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
534011
534193
  memexEntryCount: this._memexArchive.size,
534012
534194
  fileRegistrySize: this._fileRegistry.size
534013
534195
  };
534014
- writeFileSync59(join127(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
534196
+ writeFileSync59(join128(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
534015
534197
  } catch {
534016
534198
  }
534017
534199
  }
@@ -534329,8 +534511,8 @@ System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
534329
534511
  let recoveredTokens = 0;
534330
534512
  for (const [filePath, entry] of entries) {
534331
534513
  try {
534332
- const { readFileSync: readFileSync88 } = await import("node:fs");
534333
- const content = readFileSync88(filePath, "utf8");
534514
+ const { readFileSync: readFileSync89 } = await import("node:fs");
534515
+ const content = readFileSync89(filePath, "utf8");
534334
534516
  const tokenEst = Math.ceil(content.length / 4);
534335
534517
  if (recoveredTokens + tokenEst > fileRecoveryBudget)
534336
534518
  break;
@@ -535838,17 +536020,17 @@ ${result}`
535838
536020
  let resizedBase64 = null;
535839
536021
  try {
535840
536022
  const { execSync: execSync59 } = await import("node:child_process");
535841
- const { writeFileSync: writeFileSync59, readFileSync: readFileSync88, unlinkSync: unlinkSync25 } = await import("node:fs");
535842
- const { join: join127 } = await import("node:path");
536023
+ const { writeFileSync: writeFileSync59, readFileSync: readFileSync89, unlinkSync: unlinkSync25 } = await import("node:fs");
536024
+ const { join: join128 } = await import("node:path");
535843
536025
  const { tmpdir: tmpdir22 } = await import("node:os");
535844
- const tmpIn = join127(tmpdir22(), `oa_img_in_${Date.now()}.png`);
535845
- const tmpOut = join127(tmpdir22(), `oa_img_out_${Date.now()}.jpg`);
536026
+ const tmpIn = join128(tmpdir22(), `oa_img_in_${Date.now()}.png`);
536027
+ const tmpOut = join128(tmpdir22(), `oa_img_out_${Date.now()}.jpg`);
535846
536028
  writeFileSync59(tmpIn, buffer2);
535847
536029
  const pyBin = process.platform === "win32" ? "python" : "python3";
535848
536030
  const escapedIn = tmpIn.replace(/\\/g, "\\\\");
535849
536031
  const escapedOut = tmpOut.replace(/\\/g, "\\\\");
535850
536032
  execSync59(`${pyBin} -c "from PIL import Image; img = Image.open('${escapedIn}'); img.thumbnail((512, 512), Image.LANCZOS); img = img.convert('RGB'); img.save('${escapedOut}', 'JPEG', quality=75)"`, { timeout: 1e4, stdio: "pipe" });
535851
- const resizedBuf = readFileSync88(tmpOut);
536033
+ const resizedBuf = readFileSync89(tmpOut);
535852
536034
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
535853
536035
  try {
535854
536036
  unlinkSync25(tmpIn);
@@ -544388,25 +544570,25 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
544388
544570
  async function fetchPeerModels(peerId, authKey) {
544389
544571
  try {
544390
544572
  const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
544391
- const { existsSync: existsSync109, readFileSync: readFileSync88 } = await import("node:fs");
544392
- const { join: join127 } = await import("node:path");
544573
+ const { existsSync: existsSync110, readFileSync: readFileSync89 } = await import("node:fs");
544574
+ const { join: join128 } = await import("node:path");
544393
544575
  const cwd4 = process.cwd();
544394
544576
  const nexusTool = new NexusTool2(cwd4);
544395
544577
  const nexusDir = nexusTool.getNexusDir();
544396
544578
  let isLocalPeer = false;
544397
544579
  try {
544398
- const statusPath = join127(nexusDir, "status.json");
544399
- if (existsSync109(statusPath)) {
544400
- const status = JSON.parse(readFileSync88(statusPath, "utf8"));
544580
+ const statusPath = join128(nexusDir, "status.json");
544581
+ if (existsSync110(statusPath)) {
544582
+ const status = JSON.parse(readFileSync89(statusPath, "utf8"));
544401
544583
  if (status.peerId === peerId) isLocalPeer = true;
544402
544584
  }
544403
544585
  } catch {
544404
544586
  }
544405
544587
  if (isLocalPeer) {
544406
- const pricingPath = join127(nexusDir, "pricing.json");
544407
- if (existsSync109(pricingPath)) {
544588
+ const pricingPath = join128(nexusDir, "pricing.json");
544589
+ if (existsSync110(pricingPath)) {
544408
544590
  try {
544409
- const pricing = JSON.parse(readFileSync88(pricingPath, "utf8"));
544591
+ const pricing = JSON.parse(readFileSync89(pricingPath, "utf8"));
544410
544592
  const localModels = (pricing.models || []).map((m2) => ({
544411
544593
  name: m2.model || "unknown",
544412
544594
  size: m2.parameterSize || "",
@@ -544419,10 +544601,10 @@ async function fetchPeerModels(peerId, authKey) {
544419
544601
  }
544420
544602
  }
544421
544603
  }
544422
- const cachePath = join127(nexusDir, "peer-models-cache.json");
544423
- if (existsSync109(cachePath)) {
544604
+ const cachePath = join128(nexusDir, "peer-models-cache.json");
544605
+ if (existsSync110(cachePath)) {
544424
544606
  try {
544425
- const cache8 = JSON.parse(readFileSync88(cachePath, "utf8"));
544607
+ const cache8 = JSON.parse(readFileSync89(cachePath, "utf8"));
544426
544608
  if (cache8.peerId === peerId && cache8.models?.length > 0) {
544427
544609
  const age = Date.now() - new Date(cache8.cachedAt).getTime();
544428
544610
  if (age < 5 * 60 * 1e3) {
@@ -544534,10 +544716,10 @@ async function fetchPeerModels(peerId, authKey) {
544534
544716
  } catch {
544535
544717
  }
544536
544718
  if (isLocalPeer) {
544537
- const pricingPath = join127(nexusDir, "pricing.json");
544538
- if (existsSync109(pricingPath)) {
544719
+ const pricingPath = join128(nexusDir, "pricing.json");
544720
+ if (existsSync110(pricingPath)) {
544539
544721
  try {
544540
- const pricing = JSON.parse(readFileSync88(pricingPath, "utf8"));
544722
+ const pricing = JSON.parse(readFileSync89(pricingPath, "utf8"));
544541
544723
  return (pricing.models || []).map((m2) => ({
544542
544724
  name: m2.model || "unknown",
544543
544725
  size: m2.parameterSize || "",
@@ -562356,9 +562538,9 @@ async function ensureVoiceDeps(ctx3) {
562356
562538
  }
562357
562539
  if (typeof mod2.getVenvPython === "function") {
562358
562540
  const { dirname: dirname39 } = await import("node:path");
562359
- const { existsSync: existsSync109 } = await import("node:fs");
562541
+ const { existsSync: existsSync110 } = await import("node:fs");
562360
562542
  const venvPy = mod2.getVenvPython();
562361
- if (existsSync109(venvPy)) {
562543
+ if (existsSync110(venvPy)) {
562362
562544
  process.env.TRANSCRIBE_PYTHON = venvPy;
562363
562545
  const venvBin = dirname39(venvPy);
562364
562546
  const sep2 = process.platform === "win32" ? ";" : ":";
@@ -562676,11 +562858,11 @@ async function handleSlashCommand(input, ctx3) {
562676
562858
  let key = process.env["OA_API_KEY"] || "";
562677
562859
  if (!key) {
562678
562860
  try {
562679
- const { homedir: homedir45 } = await import("node:os");
562680
- const { readFileSync: readFileSync88, existsSync: existsSync109 } = await import("node:fs");
562681
- const { join: join127 } = await import("node:path");
562682
- const p2 = join127(homedir45(), ".open-agents", "api.key");
562683
- if (existsSync109(p2)) key = readFileSync88(p2, "utf8").trim();
562861
+ const { homedir: homedir46 } = await import("node:os");
562862
+ const { readFileSync: readFileSync89, existsSync: existsSync110 } = await import("node:fs");
562863
+ const { join: join128 } = await import("node:path");
562864
+ const p2 = join128(homedir46(), ".open-agents", "api.key");
562865
+ if (existsSync110(p2)) key = readFileSync89(p2, "utf8").trim();
562684
562866
  } catch {
562685
562867
  }
562686
562868
  }
@@ -562718,14 +562900,14 @@ async function handleSlashCommand(input, ctx3) {
562718
562900
  if (action === "new") {
562719
562901
  try {
562720
562902
  const { randomBytes: randomBytes25 } = await import("node:crypto");
562721
- const { homedir: homedir45 } = await import("node:os");
562903
+ const { homedir: homedir46 } = await import("node:os");
562722
562904
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
562723
- const { join: join127 } = await import("node:path");
562905
+ const { join: join128 } = await import("node:path");
562724
562906
  const newKey = randomBytes25(16).toString("hex");
562725
562907
  process.env["OA_API_KEY"] = newKey;
562726
- const dir = join127(homedir45(), ".open-agents");
562908
+ const dir = join128(homedir46(), ".open-agents");
562727
562909
  mkdirSync67(dir, { recursive: true });
562728
- writeFileSync59(join127(dir, "api.key"), newKey + "\n", "utf8");
562910
+ writeFileSync59(join128(dir, "api.key"), newKey + "\n", "utf8");
562729
562911
  renderInfo2(`New API key: ${c3.bold(c3.yellow(newKey))}`);
562730
562912
  renderInfo2("Restart the daemon to apply if needed. Use /access any to restart quickly.");
562731
562913
  } catch (e2) {
@@ -562912,12 +563094,12 @@ async function handleSlashCommand(input, ctx3) {
562912
563094
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
562913
563095
  renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
562914
563096
  try {
562915
- const { homedir: homedir46 } = await import("node:os");
563097
+ const { homedir: homedir47 } = await import("node:os");
562916
563098
  const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
562917
- const { join: join128 } = await import("node:path");
562918
- const dir = join128(homedir46(), ".open-agents");
563099
+ const { join: join129 } = await import("node:path");
563100
+ const dir = join129(homedir47(), ".open-agents");
562919
563101
  mkdirSync68(dir, { recursive: true });
562920
- writeFileSync60(join128(dir, "api.key"), apiKey + "\n", "utf8");
563102
+ writeFileSync60(join129(dir, "api.key"), apiKey + "\n", "utf8");
562921
563103
  } catch {
562922
563104
  }
562923
563105
  }
@@ -562928,12 +563110,12 @@ async function handleSlashCommand(input, ctx3) {
562928
563110
  }
562929
563111
  const port2 = parseInt(process.env["OA_PORT"] || "11435", 10);
562930
563112
  try {
562931
- const { homedir: homedir46 } = await import("node:os");
563113
+ const { homedir: homedir47 } = await import("node:os");
562932
563114
  const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
562933
- const { join: join128 } = await import("node:path");
562934
- const dir = join128(homedir46(), ".open-agents");
563115
+ const { join: join129 } = await import("node:path");
563116
+ const dir = join129(homedir47(), ".open-agents");
562935
563117
  mkdirSync68(dir, { recursive: true });
562936
- writeFileSync60(join128(dir, "access"), `${val2}
563118
+ writeFileSync60(join129(dir, "access"), `${val2}
562937
563119
  `, "utf8");
562938
563120
  } catch {
562939
563121
  }
@@ -563014,12 +563196,12 @@ async function handleSlashCommand(input, ctx3) {
563014
563196
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
563015
563197
  renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
563016
563198
  try {
563017
- const { homedir: homedir46 } = await import("node:os");
563199
+ const { homedir: homedir47 } = await import("node:os");
563018
563200
  const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
563019
- const { join: join128 } = await import("node:path");
563020
- const dir = join128(homedir46(), ".open-agents");
563201
+ const { join: join129 } = await import("node:path");
563202
+ const dir = join129(homedir47(), ".open-agents");
563021
563203
  mkdirSync68(dir, { recursive: true });
563022
- writeFileSync60(join128(dir, "api.key"), apiKey + "\n", "utf8");
563204
+ writeFileSync60(join129(dir, "api.key"), apiKey + "\n", "utf8");
563023
563205
  } catch {
563024
563206
  }
563025
563207
  }
@@ -563029,13 +563211,13 @@ async function handleSlashCommand(input, ctx3) {
563029
563211
  ctx3.saveSettings({ oaAccess: val });
563030
563212
  }
563031
563213
  const port = parseInt(process.env["OA_PORT"] || "11435", 10);
563032
- const { homedir: homedir45 } = await import("node:os");
563214
+ const { homedir: homedir46 } = await import("node:os");
563033
563215
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
563034
- const { join: join127 } = await import("node:path");
563216
+ const { join: join128 } = await import("node:path");
563035
563217
  try {
563036
- const dir = join127(homedir45(), ".open-agents");
563218
+ const dir = join128(homedir46(), ".open-agents");
563037
563219
  mkdirSync67(dir, { recursive: true });
563038
- writeFileSync59(join127(dir, "access"), `${val}
563220
+ writeFileSync59(join128(dir, "access"), `${val}
563039
563221
  `, "utf8");
563040
563222
  } catch (e2) {
563041
563223
  renderWarning2(`Could not persist ~/.open-agents/access: ${e2 instanceof Error ? e2.message : String(e2)}`);
@@ -563388,9 +563570,9 @@ async function handleSlashCommand(input, ctx3) {
563388
563570
  renderInfo2("No wallet configured. Ask the agent to create one via the nexus tool.");
563389
563571
  }
563390
563572
  } else if (sub === "name") {
563391
- const { homedir: homedir45 } = __require("node:os");
563573
+ const { homedir: homedir46 } = __require("node:os");
563392
563574
  const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
563393
- const namePath = __require("node:path").join(homedir45(), ".open-agents", "agent-name");
563575
+ const namePath = __require("node:path").join(homedir46(), ".open-agents", "agent-name");
563394
563576
  if (rest2) {
563395
563577
  const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
563396
563578
  if (!customName) {
@@ -565587,8 +565769,8 @@ sleep 1
565587
565769
  let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
565588
565770
  if (!sponsorName || sponsorName.length < 2) {
565589
565771
  try {
565590
- const { homedir: homedir45 } = __require("os");
565591
- const namePath = __require("path").join(homedir45(), ".open-agents", "agent-name");
565772
+ const { homedir: homedir46 } = __require("os");
565773
+ const namePath = __require("path").join(homedir46(), ".open-agents", "agent-name");
565592
565774
  if (existsSync83(namePath)) sponsorName = readFileSync66(namePath, "utf8").trim();
565593
565775
  } catch {
565594
565776
  }
@@ -567253,9 +567435,9 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
567253
567435
  }
567254
567436
  const { basename: basename21, join: pathJoin } = await import("node:path");
567255
567437
  const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync67, existsSync: exists2 } = await import("node:fs");
567256
- const { homedir: homedir45 } = await import("node:os");
567438
+ const { homedir: homedir46 } = await import("node:os");
567257
567439
  const modelName = basename21(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
567258
- const destDir = pathJoin(homedir45(), ".open-agents", "voice", "models", modelName);
567440
+ const destDir = pathJoin(homedir46(), ".open-agents", "voice", "models", modelName);
567259
567441
  if (!exists2(destDir)) mkdirSync67(destDir, { recursive: true });
567260
567442
  copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
567261
567443
  copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
@@ -568183,8 +568365,8 @@ async function handlePeerEndpoint(peerId, authKey, ctx3, local) {
568183
568365
  if (models.length > 0) {
568184
568366
  try {
568185
568367
  const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67 } = await import("node:fs");
568186
- const { join: join127, dirname: dirname39 } = await import("node:path");
568187
- const cachePath = join127(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
568368
+ const { join: join128, dirname: dirname39 } = await import("node:path");
568369
+ const cachePath = join128(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
568188
568370
  mkdirSync67(dirname39(cachePath), { recursive: true });
568189
568371
  writeFileSync59(cachePath, JSON.stringify({
568190
568372
  peerId,
@@ -568755,17 +568937,17 @@ async function handleUpdate(subcommand, ctx3) {
568755
568937
  try {
568756
568938
  const { createRequire: createRequire8 } = await import("node:module");
568757
568939
  const { fileURLToPath: fileURLToPath20 } = await import("node:url");
568758
- const { dirname: dirname39, join: join127 } = await import("node:path");
568759
- const { existsSync: existsSync109 } = await import("node:fs");
568940
+ const { dirname: dirname39, join: join128 } = await import("node:path");
568941
+ const { existsSync: existsSync110 } = await import("node:fs");
568760
568942
  const req2 = createRequire8(import.meta.url);
568761
568943
  const thisDir = dirname39(fileURLToPath20(import.meta.url));
568762
568944
  const candidates = [
568763
- join127(thisDir, "..", "package.json"),
568764
- join127(thisDir, "..", "..", "package.json"),
568765
- join127(thisDir, "..", "..", "..", "package.json")
568945
+ join128(thisDir, "..", "package.json"),
568946
+ join128(thisDir, "..", "..", "package.json"),
568947
+ join128(thisDir, "..", "..", "..", "package.json")
568766
568948
  ];
568767
568949
  for (const pkgPath of candidates) {
568768
- if (existsSync109(pkgPath)) {
568950
+ if (existsSync110(pkgPath)) {
568769
568951
  const pkg = req2(pkgPath);
568770
568952
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
568771
568953
  currentVersion = pkg.version ?? "0.0.0";
@@ -569912,14 +570094,14 @@ var init_commands = __esm({
569912
570094
  if (val === "any" && !process.env["OA_API_KEY"]) {
569913
570095
  try {
569914
570096
  const { randomBytes: randomBytes25 } = await import("node:crypto");
569915
- const { homedir: homedir45 } = await import("node:os");
570097
+ const { homedir: homedir46 } = await import("node:os");
569916
570098
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
569917
- const { join: join127 } = await import("node:path");
570099
+ const { join: join128 } = await import("node:path");
569918
570100
  const apiKey = randomBytes25(16).toString("hex");
569919
570101
  process.env["OA_API_KEY"] = apiKey;
569920
- const dir = join127(homedir45(), ".open-agents");
570102
+ const dir = join128(homedir46(), ".open-agents");
569921
570103
  mkdirSync67(dir, { recursive: true });
569922
- writeFileSync59(join127(dir, "api.key"), apiKey + "\n", "utf8");
570104
+ writeFileSync59(join128(dir, "api.key"), apiKey + "\n", "utf8");
569923
570105
  renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
569924
570106
  renderInfo2("Use Authorization: Bearer <key> or click 'key' in the Web UI header to paste it.");
569925
570107
  } catch (e2) {
@@ -569933,12 +570115,12 @@ var init_commands = __esm({
569933
570115
  }
569934
570116
  const port = parseInt(process.env["OA_PORT"] || "11435", 10);
569935
570117
  try {
569936
- const { homedir: homedir45 } = await import("node:os");
570118
+ const { homedir: homedir46 } = await import("node:os");
569937
570119
  const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
569938
- const { join: join127 } = await import("node:path");
569939
- const dir = join127(homedir45(), ".open-agents");
570120
+ const { join: join128 } = await import("node:path");
570121
+ const dir = join128(homedir46(), ".open-agents");
569940
570122
  mkdirSync67(dir, { recursive: true });
569941
- writeFileSync59(join127(dir, "access"), `${val}
570123
+ writeFileSync59(join128(dir, "access"), `${val}
569942
570124
  `, "utf8");
569943
570125
  } catch {
569944
570126
  }
@@ -585471,10 +585653,168 @@ var init_runtime_keys = __esm({
585471
585653
  }
585472
585654
  });
585473
585655
 
585474
- // packages/cli/src/api/routes-v1.ts
585475
- import { existsSync as existsSync101, readFileSync as readFileSync82, readdirSync as readdirSync34, statSync as statSync34 } from "node:fs";
585476
- import { join as join117, resolve as pathResolve2 } from "node:path";
585656
+ // packages/cli/src/api/tor-fallback.ts
585657
+ var tor_fallback_exports = {};
585658
+ __export(tor_fallback_exports, {
585659
+ getLocalOnion: () => getLocalOnion,
585660
+ torIsReachable: () => torIsReachable,
585661
+ tunnelViaTor: () => tunnelViaTor
585662
+ });
585663
+ import { existsSync as existsSync101, readFileSync as readFileSync82 } from "node:fs";
585477
585664
  import { homedir as homedir39 } from "node:os";
585665
+ import { join as join117 } from "node:path";
585666
+ import { createConnection as createConnection3 } from "node:net";
585667
+ function getLocalOnion() {
585668
+ const candidates = [
585669
+ join117(homedir39(), "hidden_service_hostname"),
585670
+ join117(homedir39(), ".oa", "tor", "hostname"),
585671
+ "/var/lib/tor/hidden_service/hostname"
585672
+ ];
585673
+ for (const p2 of candidates) {
585674
+ try {
585675
+ if (existsSync101(p2)) {
585676
+ const v = readFileSync82(p2, "utf-8").trim();
585677
+ if (v && v.endsWith(".onion")) return v;
585678
+ }
585679
+ } catch {
585680
+ }
585681
+ }
585682
+ return null;
585683
+ }
585684
+ async function torIsReachable() {
585685
+ return new Promise((resolve43) => {
585686
+ const sock = createConnection3({ host: DEFAULT_SOCKS_HOST, port: DEFAULT_SOCKS_PORT });
585687
+ let done = false;
585688
+ const finish = (ok2) => {
585689
+ if (done) return;
585690
+ done = true;
585691
+ try {
585692
+ sock.destroy();
585693
+ } catch {
585694
+ }
585695
+ resolve43(ok2);
585696
+ };
585697
+ sock.once("connect", () => finish(true));
585698
+ sock.once("error", () => finish(false));
585699
+ setTimeout(() => finish(false), 500);
585700
+ });
585701
+ }
585702
+ async function tunnelViaTor(req2) {
585703
+ const headers = { ...req2.headers || {} };
585704
+ if (req2.shareKey) headers["authorization"] = `Bearer ${req2.shareKey}`;
585705
+ if (!headers["host"]) headers["host"] = req2.onion;
585706
+ if (req2.body && !headers["content-length"]) headers["content-length"] = String(Buffer.byteLength(req2.body, "utf-8"));
585707
+ if (!headers["connection"]) headers["connection"] = "close";
585708
+ const lines = [`${req2.method.toUpperCase()} ${req2.path} HTTP/1.1`];
585709
+ for (const [k, v] of Object.entries(headers)) lines.push(`${k}: ${v}`);
585710
+ lines.push("");
585711
+ lines.push("");
585712
+ const reqBuf = Buffer.from(lines.join("\r\n") + (req2.body ?? ""), "utf-8");
585713
+ const socksSock = await openSocks5(req2.onion, 80, req2.timeoutMs ?? 6e4);
585714
+ socksSock.write(reqBuf);
585715
+ const chunks = [];
585716
+ for await (const ch of socksSock) chunks.push(ch);
585717
+ const raw = Buffer.concat(chunks).toString("utf-8");
585718
+ const headerEnd = raw.indexOf("\r\n\r\n");
585719
+ if (headerEnd < 0) throw new Error("Tor: malformed response (no header terminator)");
585720
+ const headBlock = raw.slice(0, headerEnd);
585721
+ const bodyText = raw.slice(headerEnd + 4);
585722
+ const headLines = headBlock.split("\r\n");
585723
+ const statusLine = headLines.shift() ?? "";
585724
+ const m2 = statusLine.match(/^HTTP\/[\d.]+ (\d+)/);
585725
+ const status = m2 ? parseInt(m2[1], 10) : 0;
585726
+ const respHeaders = {};
585727
+ for (const ln of headLines) {
585728
+ const idx = ln.indexOf(":");
585729
+ if (idx <= 0) continue;
585730
+ respHeaders[ln.slice(0, idx).toLowerCase()] = ln.slice(idx + 1).trim();
585731
+ }
585732
+ const ct = (respHeaders["content-type"] || "").toLowerCase();
585733
+ const streaming = ct.includes("text/event-stream") || ct.includes("application/x-ndjson");
585734
+ return { status, headers: respHeaders, body: bodyText, streaming };
585735
+ }
585736
+ function openSocks5(targetHost, targetPort, timeoutMs) {
585737
+ return new Promise((resolve43, reject) => {
585738
+ const sock = createConnection3({ host: DEFAULT_SOCKS_HOST, port: DEFAULT_SOCKS_PORT });
585739
+ let stage = "greet";
585740
+ const timer = setTimeout(() => {
585741
+ try {
585742
+ sock.destroy(new Error(`Tor SOCKS5 timeout (${timeoutMs}ms)`));
585743
+ } catch {
585744
+ }
585745
+ reject(new Error(`Tor SOCKS5 timeout (${timeoutMs}ms)`));
585746
+ }, timeoutMs);
585747
+ sock.on("error", (e2) => {
585748
+ clearTimeout(timer);
585749
+ reject(e2);
585750
+ });
585751
+ sock.on("connect", () => {
585752
+ sock.write(Buffer.from([5, 1, 0]));
585753
+ });
585754
+ sock.on("data", (chunk) => {
585755
+ if (stage === "greet") {
585756
+ if (chunk.length < 2 || chunk[0] !== 5 || chunk[1] !== 0) {
585757
+ clearTimeout(timer);
585758
+ reject(new Error("Tor SOCKS5: greeting rejected (auth required?)"));
585759
+ try {
585760
+ sock.destroy();
585761
+ } catch {
585762
+ }
585763
+ return;
585764
+ }
585765
+ const hostBuf = Buffer.from(targetHost, "ascii");
585766
+ const buf = Buffer.alloc(7 + hostBuf.length);
585767
+ buf[0] = 5;
585768
+ buf[1] = 1;
585769
+ buf[2] = 0;
585770
+ buf[3] = 3;
585771
+ buf[4] = hostBuf.length;
585772
+ hostBuf.copy(buf, 5);
585773
+ buf.writeUInt16BE(targetPort, 5 + hostBuf.length);
585774
+ sock.write(buf);
585775
+ stage = "connect";
585776
+ return;
585777
+ }
585778
+ if (stage === "connect") {
585779
+ if (chunk.length < 2 || chunk[0] !== 5) {
585780
+ clearTimeout(timer);
585781
+ reject(new Error("Tor SOCKS5: malformed CONNECT reply"));
585782
+ try {
585783
+ sock.destroy();
585784
+ } catch {
585785
+ }
585786
+ return;
585787
+ }
585788
+ if (chunk[1] !== 0) {
585789
+ const code8 = chunk[1];
585790
+ clearTimeout(timer);
585791
+ reject(new Error(`Tor SOCKS5: CONNECT failed (code ${code8})`));
585792
+ try {
585793
+ sock.destroy();
585794
+ } catch {
585795
+ }
585796
+ return;
585797
+ }
585798
+ clearTimeout(timer);
585799
+ stage = "ready";
585800
+ resolve43(sock);
585801
+ }
585802
+ });
585803
+ });
585804
+ }
585805
+ var DEFAULT_SOCKS_PORT, DEFAULT_SOCKS_HOST;
585806
+ var init_tor_fallback = __esm({
585807
+ "packages/cli/src/api/tor-fallback.ts"() {
585808
+ "use strict";
585809
+ DEFAULT_SOCKS_PORT = parseInt(process.env["OA_TOR_SOCKS_PORT"] || "9050", 10);
585810
+ DEFAULT_SOCKS_HOST = process.env["OA_TOR_SOCKS_HOST"] || "127.0.0.1";
585811
+ }
585812
+ });
585813
+
585814
+ // packages/cli/src/api/routes-v1.ts
585815
+ import { existsSync as existsSync102, readFileSync as readFileSync83, readdirSync as readdirSync34, statSync as statSync34 } from "node:fs";
585816
+ import { join as join118, resolve as pathResolve2 } from "node:path";
585817
+ import { homedir as homedir40 } from "node:os";
585478
585818
  async function tryRouteV1(ctx3) {
585479
585819
  const { pathname, method } = ctx3;
585480
585820
  if (pathname === "/v1/skills" && method === "GET") {
@@ -585557,6 +585897,7 @@ async function tryRouteV1(ctx3) {
585557
585897
  if (m2 && method === "DELETE") return handleRevokeKey(ctx3, decodeURIComponent(m2[1]));
585558
585898
  }
585559
585899
  if (pathname === "/v1/share/generate" && method === "POST") return handleGenerateShare(ctx3);
585900
+ if (pathname === "/v1/remote-proxy" && method === "POST") return handleRemoteProxy(ctx3);
585560
585901
  if (pathname === "/v1/tools" && method === "GET") {
585561
585902
  return handleListTools(ctx3);
585562
585903
  }
@@ -585703,11 +586044,11 @@ async function handleGetSkill(ctx3, name10) {
585703
586044
  async function fallbackDiscoverSkills() {
585704
586045
  return (_root) => {
585705
586046
  const roots = [
585706
- join117(homedir39(), ".local", "share", "ai-writing-guide")
586047
+ join118(homedir40(), ".local", "share", "ai-writing-guide")
585707
586048
  ];
585708
586049
  const out = [];
585709
586050
  for (const root of roots) {
585710
- if (!existsSync101(root)) continue;
586051
+ if (!existsSync102(root)) continue;
585711
586052
  walkForSkills(root, out, 0);
585712
586053
  }
585713
586054
  return out;
@@ -585718,12 +586059,12 @@ function walkForSkills(dir, out, depth) {
585718
586059
  try {
585719
586060
  for (const e2 of readdirSync34(dir, { withFileTypes: true })) {
585720
586061
  if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
585721
- const p2 = join117(dir, e2.name);
586062
+ const p2 = join118(dir, e2.name);
585722
586063
  if (e2.isDirectory()) {
585723
586064
  walkForSkills(p2, out, depth + 1);
585724
586065
  } else if (e2.isFile() && e2.name === "SKILL.md") {
585725
586066
  try {
585726
- const content = readFileSync82(p2, "utf-8").slice(0, 2e3);
586067
+ const content = readFileSync83(p2, "utf-8").slice(0, 2e3);
585727
586068
  const nameMatch = content.match(/^name:\s*(.+)$/m);
585728
586069
  const descMatch = content.match(/^description:\s*(.+)$/m);
585729
586070
  out.push({
@@ -585907,7 +586248,7 @@ async function getMemoryStores() {
585907
586248
  if (memoryInitTried) return null;
585908
586249
  memoryInitTried = true;
585909
586250
  try {
585910
- const dbPath = join117(homedir39(), ".open-agents", "memory.db");
586251
+ const dbPath = join118(homedir40(), ".open-agents", "memory.db");
585911
586252
  const sharedDb = initDb(dbPath);
585912
586253
  memoryStoresCache = {
585913
586254
  episode: new EpisodeStore(dbPath),
@@ -586165,7 +586506,7 @@ async function handleFilesRead(ctx3) {
586165
586506
  }));
586166
586507
  return true;
586167
586508
  }
586168
- if (!existsSync101(resolved)) {
586509
+ if (!existsSync102(resolved)) {
586169
586510
  sendProblem(res, problemDetails({
586170
586511
  type: P.notFound,
586171
586512
  status: 404,
@@ -586197,7 +586538,7 @@ async function handleFilesRead(ctx3) {
586197
586538
  }));
586198
586539
  return true;
586199
586540
  }
586200
- const content = readFileSync82(resolved, "utf-8");
586541
+ const content = readFileSync83(resolved, "utf-8");
586201
586542
  const offset = typeof body.offset === "number" && body.offset >= 0 ? body.offset : 0;
586202
586543
  const limit = typeof body.limit === "number" && body.limit > 0 ? body.limit : content.length;
586203
586544
  const slice2 = content.slice(offset, offset + limit);
@@ -586430,14 +586771,14 @@ async function handleNexusStatus(ctx3) {
586430
586771
  const { res, requestId } = ctx3;
586431
586772
  try {
586432
586773
  const statePaths = [
586433
- join117(process.cwd(), ".oa", "nexus-peer-state.json"),
586434
- join117(homedir39(), ".open-agents", "nexus-peer-cache.json")
586774
+ join118(process.cwd(), ".oa", "nexus-peer-state.json"),
586775
+ join118(homedir40(), ".open-agents", "nexus-peer-cache.json")
586435
586776
  ];
586436
586777
  const states = [];
586437
586778
  for (const p2 of statePaths) {
586438
- if (!existsSync101(p2)) continue;
586779
+ if (!existsSync102(p2)) continue;
586439
586780
  try {
586440
- const raw = readFileSync82(p2, "utf-8");
586781
+ const raw = readFileSync83(p2, "utf-8");
586441
586782
  states.push({ source: p2, data: JSON.parse(raw) });
586442
586783
  } catch (e2) {
586443
586784
  states.push({ source: p2, error: String(e2) });
@@ -586464,8 +586805,8 @@ async function handleNexusStatus(ctx3) {
586464
586805
  }
586465
586806
  function loadAgentName() {
586466
586807
  try {
586467
- const p2 = join117(homedir39(), ".open-agents", "agent-name");
586468
- if (existsSync101(p2)) return readFileSync82(p2, "utf-8").trim();
586808
+ const p2 = join118(homedir40(), ".open-agents", "agent-name");
586809
+ if (existsSync102(p2)) return readFileSync83(p2, "utf-8").trim();
586469
586810
  } catch {
586470
586811
  }
586471
586812
  return null;
@@ -586474,14 +586815,14 @@ async function handleSponsors(ctx3) {
586474
586815
  const { req: req2, res, url, requestId } = ctx3;
586475
586816
  try {
586476
586817
  const candidates = [
586477
- join117(homedir39(), ".open-agents", "sponsor-cache.json"),
586478
- join117(homedir39(), ".open-agents", "sponsors.json")
586818
+ join118(homedir40(), ".open-agents", "sponsor-cache.json"),
586819
+ join118(homedir40(), ".open-agents", "sponsors.json")
586479
586820
  ];
586480
586821
  let sponsors = [];
586481
586822
  for (const p2 of candidates) {
586482
- if (!existsSync101(p2)) continue;
586823
+ if (!existsSync102(p2)) continue;
586483
586824
  try {
586484
- const raw = JSON.parse(readFileSync82(p2, "utf-8"));
586825
+ const raw = JSON.parse(readFileSync83(p2, "utf-8"));
586485
586826
  if (Array.isArray(raw)) {
586486
586827
  sponsors = raw;
586487
586828
  break;
@@ -586550,8 +586891,8 @@ async function handleEvaluate(ctx3) {
586550
586891
  }));
586551
586892
  return true;
586552
586893
  }
586553
- const jobPath = join117(process.cwd(), ".oa", "jobs", `${runId}.json`);
586554
- if (!existsSync101(jobPath)) {
586894
+ const jobPath = join118(process.cwd(), ".oa", "jobs", `${runId}.json`);
586895
+ if (!existsSync102(jobPath)) {
586555
586896
  sendProblem(res, problemDetails({
586556
586897
  type: P.notFound,
586557
586898
  status: 404,
@@ -586561,7 +586902,7 @@ async function handleEvaluate(ctx3) {
586561
586902
  }));
586562
586903
  return true;
586563
586904
  }
586564
- const job = JSON.parse(readFileSync82(jobPath, "utf-8"));
586905
+ const job = JSON.parse(readFileSync83(jobPath, "utf-8"));
586565
586906
  sendJson(res, 200, {
586566
586907
  run_id: runId,
586567
586908
  task: job.task,
@@ -586698,6 +587039,74 @@ async function handleMintKey(ctx3) {
586698
587039
  }
586699
587040
  return true;
586700
587041
  }
587042
+ function _readStatusFile(p2) {
587043
+ if (!existsSync102(p2)) return null;
587044
+ try {
587045
+ const data = JSON.parse(readFileSync83(p2, "utf-8"));
587046
+ if (data?.connected && typeof data.peerId === "string" && data.peerId.length > 10) {
587047
+ return {
587048
+ peerId: data.peerId,
587049
+ agentName: typeof data.agentName === "string" ? data.agentName : null,
587050
+ source: p2
587051
+ };
587052
+ }
587053
+ } catch {
587054
+ }
587055
+ return null;
587056
+ }
587057
+ function resolveLocalPeerId() {
587058
+ const override = process.env["OA_NEXUS_DIR"];
587059
+ if (override) {
587060
+ const r2 = _readStatusFile(join118(override, "status.json"));
587061
+ if (r2) return r2;
587062
+ }
587063
+ try {
587064
+ const regPath = join118(homedir40(), ".open-agents", "nexus-registry.json");
587065
+ if (existsSync102(regPath)) {
587066
+ const reg = JSON.parse(readFileSync83(regPath, "utf-8"));
587067
+ const entries = Array.isArray(reg?.dirs) ? reg.dirs : [];
587068
+ for (const entry of entries) {
587069
+ const dir = typeof entry === "string" ? entry : entry?.dir;
587070
+ if (typeof dir === "string") {
587071
+ const r2 = _readStatusFile(join118(dir, "status.json"));
587072
+ if (r2) return r2;
587073
+ }
587074
+ }
587075
+ }
587076
+ } catch {
587077
+ }
587078
+ const candidates = [
587079
+ join118(process.cwd(), ".oa", "nexus", "status.json"),
587080
+ join118(homedir40(), ".oa", "nexus", "status.json"),
587081
+ join118(homedir40(), ".open-agents", "nexus", "status.json")
587082
+ ];
587083
+ for (const p2 of candidates) {
587084
+ const r2 = _readStatusFile(p2);
587085
+ if (r2) return r2;
587086
+ }
587087
+ const now = Date.now();
587088
+ if (_peerIdScanCache && now - _peerIdScanCache.ts < 6e4) {
587089
+ return _peerIdScanCache.result;
587090
+ }
587091
+ let scanResult = null;
587092
+ try {
587093
+ const { execSync: execSync59 } = __require("node:child_process");
587094
+ const cmd = `find "${homedir40()}" -maxdepth 4 -path '*/.oa/nexus/status.json' -type f 2>/dev/null | head -50`;
587095
+ const out = execSync59(cmd, { encoding: "utf-8", timeout: 2e3 }).trim();
587096
+ for (const line of out.split("\n")) {
587097
+ const f2 = line.trim();
587098
+ if (!f2) continue;
587099
+ const r2 = _readStatusFile(f2);
587100
+ if (r2) {
587101
+ scanResult = r2;
587102
+ break;
587103
+ }
587104
+ }
587105
+ } catch {
587106
+ }
587107
+ _peerIdScanCache = { ts: now, result: scanResult };
587108
+ return scanResult;
587109
+ }
586701
587110
  async function handleGenerateShare(ctx3) {
586702
587111
  const { req: req2, res, requestId } = ctx3;
586703
587112
  const reqAuth = req2;
@@ -586742,19 +587151,48 @@ async function handleGenerateShare(ctx3) {
586742
587151
  }));
586743
587152
  return true;
586744
587153
  }
587154
+ const directOnly = body["direct"] === true;
587155
+ const peerInfo = directOnly ? null : resolveLocalPeerId();
586745
587156
  const scheme = String(req2.headers["x-forwarded-proto"] || (req2.socket?.encrypted ? "https" : "http"));
586746
- const shareUrl = `oa-share://${hostPort}#${fullKey}`;
586747
- const plainUrl = `${scheme}://${hostPort}/?oa-key=${encodeURIComponent(fullKey)}&oa-share-label=${encodeURIComponent(label)}`;
587157
+ const { getLocalOnion: getLocalOnion2 } = await Promise.resolve().then(() => (init_tor_fallback(), tor_fallback_exports));
587158
+ const onion = getLocalOnion2();
587159
+ let shareUrl;
587160
+ let mode;
587161
+ if (peerInfo && hostHeader) {
587162
+ shareUrl = `oa-share://${peerInfo.peerId}@${hostPort}#${fullKey}`;
587163
+ mode = "libp2p+lan";
587164
+ } else if (peerInfo) {
587165
+ shareUrl = `oa-share://${peerInfo.peerId}#${fullKey}`;
587166
+ mode = "libp2p";
587167
+ } else {
587168
+ shareUrl = `oa-share://${hostPort}#${fullKey}`;
587169
+ mode = "direct";
587170
+ }
587171
+ const plainParams = [];
587172
+ if (peerInfo) plainParams.push(`oa-share-peer=${encodeURIComponent(peerInfo.peerId)}`);
587173
+ plainParams.push(`oa-key=${encodeURIComponent(fullKey)}`);
587174
+ if (onion) plainParams.push(`oa-onion=${encodeURIComponent(onion)}`);
587175
+ plainParams.push(`oa-share-label=${encodeURIComponent(label)}`);
587176
+ const plainUrl = `${scheme}://${hostPort}/?${plainParams.join("&")}`;
586748
587177
  sendJson(res, 201, {
586749
587178
  shareUrl,
586750
587179
  plainUrl,
587180
+ mode,
587181
+ peerId: peerInfo?.peerId || null,
587182
+ onion: onion || null,
587183
+ agentName: peerInfo?.agentName || null,
586751
587184
  host,
586752
587185
  port,
586753
587186
  key: fullKey,
586754
587187
  keyPrefix: keyPrefix2,
586755
587188
  label,
586756
587189
  issuedAt: rec.created || (/* @__PURE__ */ new Date()).toISOString(),
586757
- _note: "This is the ONLY response that contains the full key. Hand off the URL now."
587190
+ reach: {
587191
+ libp2p: !!peerInfo,
587192
+ tor: !!onion,
587193
+ direct: !peerInfo
587194
+ },
587195
+ _note: peerInfo && onion ? "Globally reachable via libp2p (primary) and Tor (.onion fallback)." : peerInfo ? "Globally reachable via libp2p. For maximum reach add Tor: see scripts/tor/tor_setup.sh." : "Nexus daemon offline — URL is direct-HTTP only (LAN/VPN reach). Start nexus for global reach."
586758
587196
  });
586759
587197
  } catch (err) {
586760
587198
  sendProblem(res, problemDetails({
@@ -586767,6 +587205,242 @@ async function handleGenerateShare(ctx3) {
586767
587205
  }
586768
587206
  return true;
586769
587207
  }
587208
+ async function handleRemoteProxy(ctx3) {
587209
+ const { req: req2, res, requestId } = ctx3;
587210
+ const reqAuth = req2;
587211
+ if (reqAuth._authScope !== "admin" && reqAuth._authScope !== "run") {
587212
+ sendProblem(res, problemDetails({
587213
+ type: P.forbidden,
587214
+ status: 403,
587215
+ title: "Auth required",
587216
+ detail: "Remote proxy requires 'run' or 'admin' scope on the LOCAL daemon.",
587217
+ instance: requestId
587218
+ }));
587219
+ return true;
587220
+ }
587221
+ let body;
587222
+ try {
587223
+ body = await parseJsonBodyStrict(req2);
587224
+ } catch {
587225
+ sendProblem(res, problemDetails({
587226
+ type: P.invalidRequest,
587227
+ status: 400,
587228
+ title: "Invalid JSON body",
587229
+ detail: "Body must be JSON object with peerId, key, method, path.",
587230
+ instance: requestId
587231
+ }));
587232
+ return true;
587233
+ }
587234
+ const peerId = String(body?.peerId || "").trim();
587235
+ const onionHint = typeof body?.onion === "string" && body.onion.endsWith(".onion") ? body.onion : null;
587236
+ const shareKey = String(body?.key || "").trim();
587237
+ const method = String(body?.method || "GET").toUpperCase();
587238
+ const path8 = String(body?.path || "/").trim();
587239
+ const headers = body?.headers && typeof body.headers === "object" ? body.headers : {};
587240
+ const useStream = body?.stream === true;
587241
+ const timeoutMs = typeof body?.timeoutMs === "number" ? body.timeoutMs : 6e4;
587242
+ if (!peerId && !onionHint || !shareKey) {
587243
+ sendProblem(res, problemDetails({
587244
+ type: P.invalidRequest,
587245
+ status: 400,
587246
+ title: "key + (peerId or onion) required",
587247
+ detail: "Provide a share key and at least one of peerId (libp2p) or onion (Tor).",
587248
+ instance: requestId
587249
+ }));
587250
+ return true;
587251
+ }
587252
+ const nexusCandidates = [
587253
+ join118(process.cwd(), ".oa", "nexus"),
587254
+ join118(homedir40(), ".oa", "nexus"),
587255
+ join118(homedir40(), ".open-agents", "nexus")
587256
+ ];
587257
+ let nexusDirPath = null;
587258
+ for (const p2 of nexusCandidates) {
587259
+ if (existsSync102(join118(p2, "status.json"))) {
587260
+ nexusDirPath = p2;
587261
+ break;
587262
+ }
587263
+ }
587264
+ let tool = null;
587265
+ if (peerId && nexusDirPath) {
587266
+ const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
587267
+ const nexusToolRepoRoot = nexusDirPath.replace(/[\\/]\.oa[\\/]nexus$/, "");
587268
+ tool = new NexusTool2(nexusToolRepoRoot);
587269
+ }
587270
+ const tunnelInput = {
587271
+ method,
587272
+ path: path8,
587273
+ headers,
587274
+ body: body?.body,
587275
+ key: shareKey
587276
+ };
587277
+ function torEnvelope(t2) {
587278
+ return {
587279
+ event: "http.head",
587280
+ data: JSON.stringify({ status: t2.status, headers: t2.headers, streaming: t2.streaming }),
587281
+ // The browser fetch interceptor reads either `event: http.head + data` (with embedded
587282
+ // status/headers) or falls back to `raw`. We pass both.
587283
+ raw: t2.body,
587284
+ transport: "tor"
587285
+ };
587286
+ }
587287
+ if (!useStream) {
587288
+ let libp2pErr = null;
587289
+ if (tool) {
587290
+ try {
587291
+ const raw = await tool.sendCommand("invoke_capability", {
587292
+ target_peer: peerId,
587293
+ capability: "http_tunnel",
587294
+ input: JSON.stringify(tunnelInput)
587295
+ }, timeoutMs);
587296
+ let parsed = null;
587297
+ try {
587298
+ parsed = JSON.parse(raw);
587299
+ } catch {
587300
+ parsed = { raw };
587301
+ }
587302
+ if (parsed && typeof parsed === "object") parsed.transport = "libp2p";
587303
+ sendJson(res, 200, parsed);
587304
+ return true;
587305
+ } catch (e2) {
587306
+ libp2pErr = e2;
587307
+ }
587308
+ }
587309
+ if (onionHint) {
587310
+ try {
587311
+ const { tunnelViaTor: tunnelViaTor2, torIsReachable: torIsReachable2 } = await Promise.resolve().then(() => (init_tor_fallback(), tor_fallback_exports));
587312
+ if (await torIsReachable2()) {
587313
+ const t2 = await tunnelViaTor2({
587314
+ onion: onionHint,
587315
+ method,
587316
+ path: path8,
587317
+ headers,
587318
+ body: typeof body?.body === "string" ? body.body : body?.body !== void 0 ? JSON.stringify(body.body) : void 0,
587319
+ shareKey,
587320
+ timeoutMs
587321
+ });
587322
+ sendJson(res, 200, torEnvelope(t2));
587323
+ return true;
587324
+ }
587325
+ } catch (torErr) {
587326
+ sendProblem(res, problemDetails({
587327
+ type: P.internalError,
587328
+ status: 502,
587329
+ title: "Both libp2p and Tor transports failed",
587330
+ detail: `libp2p: ${libp2pErr instanceof Error ? libp2pErr.message : String(libp2pErr || "n/a")}; tor: ${torErr instanceof Error ? torErr.message : String(torErr)}`,
587331
+ instance: requestId
587332
+ }));
587333
+ return true;
587334
+ }
587335
+ }
587336
+ sendProblem(res, problemDetails({
587337
+ type: P.internalError,
587338
+ status: 502,
587339
+ title: "No transport reached the remote",
587340
+ detail: tool ? `libp2p invoke failed: ${libp2pErr instanceof Error ? libp2pErr.message : String(libp2pErr)}${onionHint ? "; Tor SOCKS5 not reachable on 127.0.0.1:9050" : "; no .onion fallback available"}` : "Local nexus daemon is offline and no .onion fallback was provided. Start nexus with `oa connect` or include onion in the request.",
587341
+ instance: requestId
587342
+ }));
587343
+ return true;
587344
+ }
587345
+ if (!tool) {
587346
+ sendProblem(res, problemDetails({
587347
+ type: P.internalError,
587348
+ status: 503,
587349
+ title: "Streaming requires libp2p (nexus not running)",
587350
+ detail: "SSE/streaming proxy requires the local nexus daemon. Start it with `oa connect`, or use a non-streaming endpoint with the Tor fallback.",
587351
+ instance: requestId
587352
+ }));
587353
+ return true;
587354
+ }
587355
+ const streamFile = join118(nexusDirPath, `tunnel-${requestId}-${Date.now()}.jsonl`);
587356
+ try {
587357
+ const { writeFileSync: _wfs } = await import("node:fs");
587358
+ _wfs(streamFile, "");
587359
+ } catch {
587360
+ }
587361
+ res.statusCode = 200;
587362
+ res.setHeader("content-type", "text/event-stream");
587363
+ res.setHeader("cache-control", "no-cache");
587364
+ res.setHeader("x-accel-buffering", "no");
587365
+ res.flushHeaders?.();
587366
+ let stopped = false;
587367
+ const stop2 = () => {
587368
+ stopped = true;
587369
+ };
587370
+ req2.on("close", stop2);
587371
+ req2.on("aborted", stop2);
587372
+ const invokeP = tool.sendCommand("invoke_capability", {
587373
+ target_peer: peerId,
587374
+ capability: "http_tunnel",
587375
+ input: JSON.stringify(tunnelInput),
587376
+ stream_file: streamFile
587377
+ }, timeoutMs).catch((err) => {
587378
+ if (!stopped) {
587379
+ try {
587380
+ res.write(`event: error
587381
+ data: ${JSON.stringify({ error: err instanceof Error ? err.message : String(err) })}
587382
+
587383
+ `);
587384
+ } catch {
587385
+ }
587386
+ }
587387
+ });
587388
+ const { readFileSync: _rfs, existsSync: _exists } = await import("node:fs");
587389
+ let lastSize = 0;
587390
+ let leftover = "";
587391
+ while (!stopped) {
587392
+ try {
587393
+ if (_exists(streamFile)) {
587394
+ const stat5 = (await import("node:fs")).statSync(streamFile);
587395
+ if (stat5.size > lastSize) {
587396
+ const fd = (await import("node:fs")).openSync(streamFile, "r");
587397
+ const len = stat5.size - lastSize;
587398
+ const buf = Buffer.alloc(len);
587399
+ (await import("node:fs")).readSync(fd, buf, 0, len, lastSize);
587400
+ (await import("node:fs")).closeSync(fd);
587401
+ lastSize = stat5.size;
587402
+ const txt = leftover + buf.toString("utf-8");
587403
+ const parts = txt.split("\n");
587404
+ leftover = parts.pop() ?? "";
587405
+ for (const ln of parts) {
587406
+ if (!ln.trim()) continue;
587407
+ let parsed;
587408
+ try {
587409
+ parsed = JSON.parse(ln);
587410
+ } catch {
587411
+ continue;
587412
+ }
587413
+ const eventName = parsed.type === "event" ? parsed.event || "data" : parsed.type;
587414
+ res.write(`event: ${eventName}
587415
+ `);
587416
+ res.write(`data: ${JSON.stringify(parsed)}
587417
+
587418
+ `);
587419
+ if (parsed.type === "done" || parsed.type === "error") {
587420
+ stopped = true;
587421
+ break;
587422
+ }
587423
+ }
587424
+ }
587425
+ }
587426
+ } catch {
587427
+ }
587428
+ if (stopped) break;
587429
+ await new Promise((r2) => setTimeout(r2, 30));
587430
+ }
587431
+ await invokeP.catch(() => {
587432
+ });
587433
+ try {
587434
+ res.end();
587435
+ } catch {
587436
+ }
587437
+ try {
587438
+ const { unlinkSync: _unl } = await import("node:fs");
587439
+ _unl(streamFile);
587440
+ } catch {
587441
+ }
587442
+ return true;
587443
+ }
586770
587444
  async function handleRevokeKey(ctx3, prefix) {
586771
587445
  const { req: req2, res, requestId } = ctx3;
586772
587446
  const reqAuth = req2;
@@ -587118,17 +587792,17 @@ async function handleListAgentTypes(ctx3) {
587118
587792
  }
587119
587793
  async function handleListEngines(ctx3) {
587120
587794
  const { res } = ctx3;
587121
- const home = homedir39();
587795
+ const home = homedir40();
587122
587796
  sendJson(res, 200, {
587123
587797
  engines: [
587124
- { name: "dream", state_file: join117(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
587125
- { name: "bless", state_file: join117(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
587126
- { name: "call", state_file: join117(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
587127
- { name: "listen", state_file: join117(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
587128
- { name: "telegram", state_file: join117(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
587129
- { name: "expose", state_file: join117(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
587130
- { name: "nexus", state_file: join117(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
587131
- { name: "ipfs", state_file: join117(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
587798
+ { name: "dream", state_file: join118(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
587799
+ { name: "bless", state_file: join118(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
587800
+ { name: "call", state_file: join118(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
587801
+ { name: "listen", state_file: join118(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
587802
+ { name: "telegram", state_file: join118(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
587803
+ { name: "expose", state_file: join118(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
587804
+ { name: "nexus", state_file: join118(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
587805
+ { name: "ipfs", state_file: join118(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
587132
587806
  ],
587133
587807
  note: "Engine instrumentation lives in the running TUI process. Full status + control requires the daemon↔TUI bridge (PT-07). See parity audit WO-PARITY-04."
587134
587808
  });
@@ -587211,12 +587885,12 @@ async function tryAimsRoute(ctx3) {
587211
587885
  return false;
587212
587886
  }
587213
587887
  function aimsDir() {
587214
- return join117(homedir39(), ".open-agents", "aims");
587888
+ return join118(homedir40(), ".open-agents", "aims");
587215
587889
  }
587216
587890
  function readAimsFile(name10, fallback) {
587217
587891
  try {
587218
- const p2 = join117(aimsDir(), name10);
587219
- if (existsSync101(p2)) return JSON.parse(readFileSync82(p2, "utf-8"));
587892
+ const p2 = join118(aimsDir(), name10);
587893
+ if (existsSync102(p2)) return JSON.parse(readFileSync83(p2, "utf-8"));
587220
587894
  } catch {
587221
587895
  }
587222
587896
  return fallback;
@@ -587225,7 +587899,7 @@ function writeAimsFile(name10, data) {
587225
587899
  const dir = aimsDir();
587226
587900
  const { mkdirSync: mkdirSync67, writeFileSync: wf, renameSync: rn } = __require("node:fs");
587227
587901
  mkdirSync67(dir, { recursive: true });
587228
- const finalPath = join117(dir, name10);
587902
+ const finalPath = join118(dir, name10);
587229
587903
  const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
587230
587904
  try {
587231
587905
  wf(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
@@ -587555,12 +588229,12 @@ async function handleAimsSuppliers(ctx3) {
587555
588229
  }
587556
588230
  ];
587557
588231
  const sponsorPaths = [
587558
- join117(homedir39(), ".open-agents", "sponsor-cache.json")
588232
+ join118(homedir40(), ".open-agents", "sponsor-cache.json")
587559
588233
  ];
587560
588234
  for (const p2 of sponsorPaths) {
587561
- if (!existsSync101(p2)) continue;
588235
+ if (!existsSync102(p2)) continue;
587562
588236
  try {
587563
- const raw = JSON.parse(readFileSync82(p2, "utf-8"));
588237
+ const raw = JSON.parse(readFileSync83(p2, "utf-8"));
587564
588238
  const list = Array.isArray(raw) ? raw : raw?.sponsors ?? [];
587565
588239
  for (const s2 of list) {
587566
588240
  suppliers.push({
@@ -587702,7 +588376,7 @@ async function handleAimsConfigHistory(ctx3) {
587702
588376
  return true;
587703
588377
  }
587704
588378
  }
587705
- var PROBLEM_BASE, P, mcpManagerCache, memoryStoresCache, memoryInitTried, FILE_READ_MAX_BYTES, _aimsLocks;
588379
+ var PROBLEM_BASE, P, mcpManagerCache, memoryStoresCache, memoryInitTried, FILE_READ_MAX_BYTES, _peerIdScanCache, _aimsLocks;
587706
588380
  var init_routes_v1 = __esm({
587707
588381
  "packages/cli/src/api/routes-v1.ts"() {
587708
588382
  "use strict";
@@ -587728,6 +588402,7 @@ var init_routes_v1 = __esm({
587728
588402
  memoryStoresCache = null;
587729
588403
  memoryInitTried = false;
587730
588404
  FILE_READ_MAX_BYTES = 2 * 1024 * 1024;
588405
+ _peerIdScanCache = null;
587731
588406
  _aimsLocks = /* @__PURE__ */ new Map();
587732
588407
  }
587733
588408
  });
@@ -590881,35 +591556,173 @@ document.getElementById('key-btn').onclick = () => {
590881
591556
  };
590882
591557
  function saveKey() {
590883
591558
  const raw = document.getElementById('key-input').value || '';
590884
- // SHARE: detect oa-share://host:port#key OR http(s)://host:port/?oa-key=...
590885
591559
  const parsed = parseShareInput(raw);
590886
591560
  if (parsed) {
590887
- // Pasting a share URL → switch into REMOTE mode and reload page
590888
- // against the remote origin with the key in localStorage.
590889
- saveRecentKey({ key: parsed.key, host: parsed.host, label: parsed.label || ('remote ' + parsed.host) });
590890
- try {
590891
- localStorage.setItem('oa.remoteHost', parsed.host);
590892
- localStorage.setItem('oa.remoteScheme', parsed.scheme || 'http');
590893
- localStorage.setItem('oa-api-key', parsed.key);
590894
- } catch {}
590895
- // Redirect to the remote host's UI with the key carried in localStorage
590896
- // (the remote origin uses its own localStorage so we set on first
590897
- // load there). We open the remote UI in a new tab to preserve the
590898
- // local session.
590899
- const remoteUrl = (parsed.scheme || 'http') + '://' + parsed.host + '/?oa-key=' + encodeURIComponent(parsed.key) + '&oa-share-label=' + encodeURIComponent(parsed.label || '');
590900
- window.open(remoteUrl, '_blank');
590901
- closeKeyModal();
590902
- return;
591561
+ // Save into recent-keys for autocomplete
591562
+ const recLabel = parsed.label || (parsed.peerId
591563
+ ? ('remote ' + (parsed.peerId.slice(0, 12) + '…'))
591564
+ : ('remote ' + parsed.host));
591565
+ saveRecentKey({
591566
+ key: parsed.key, peerId: parsed.peerId, onion: parsed.onion || null,
591567
+ host: parsed.host, label: recLabel,
591568
+ });
591569
+ if (parsed.peerId || parsed.onion) {
591570
+ // ─── REMOTE MODE: libp2p (primary) + Tor (fallback) ──────────────
591571
+ // Stay on this page; route /v1/... calls through this daemon's
591572
+ // /v1/remote-proxy. The local daemon will try libp2p invoke first
591573
+ // (when peerId is set); if that fails (or peerId missing) it
591574
+ // falls back to Tor SOCKS5 → onion (when onion is set).
591575
+ try {
591576
+ localStorage.setItem('oa.activeRemoteShare', JSON.stringify({
591577
+ peerId: parsed.peerId,
591578
+ onion: parsed.onion || null,
591579
+ key: parsed.key,
591580
+ host: parsed.host || null,
591581
+ label: recLabel,
591582
+ activatedAt: new Date().toISOString(),
591583
+ }));
591584
+ } catch {}
591585
+ installRemoteFetchProxy();
591586
+ closeKeyModal();
591587
+ try { location.reload(); } catch { loadModels(); }
591588
+ return;
591589
+ }
591590
+ if (parsed.host) {
591591
+ // Legacy direct-HTTP — open the remote origin in a new tab.
591592
+ const remoteUrl = (parsed.scheme || 'http') + '://' + parsed.host + '/?oa-key=' + encodeURIComponent(parsed.key) + '&oa-share-label=' + encodeURIComponent(parsed.label || '');
591593
+ window.open(remoteUrl, '_blank');
591594
+ closeKeyModal();
591595
+ return;
591596
+ }
590903
591597
  }
590904
591598
  apiKey = raw;
590905
591599
  localStorage.setItem('oa-api-key', apiKey);
590906
- // Track this key in the recent-keys list so future paste autocompletes it.
590907
591600
  if (apiKey) {
590908
591601
  saveRecentKey({ key: apiKey, host: location.host, label: 'local ' + location.host });
590909
591602
  }
590910
591603
  closeKeyModal();
590911
591604
  loadModels();
590912
591605
  }
591606
+
591607
+ // ─── Remote-mode fetch proxy ─────────────────────────────────────────────
591608
+ // When 'oa.activeRemoteShare' is set, intercept window.fetch so any
591609
+ // /v1/... call gets re-routed via POST /v1/remote-proxy to be tunneled
591610
+ // through libp2p to the remote peer. SSE streams keep their text/event-
591611
+ // stream shape end-to-end.
591612
+ let _oaRemoteFetchInstalled = false;
591613
+ function getActiveRemoteShare() {
591614
+ try {
591615
+ const raw = localStorage.getItem('oa.activeRemoteShare');
591616
+ if (!raw) return null;
591617
+ const obj = JSON.parse(raw);
591618
+ if (!obj || !obj.peerId || !obj.key) return null;
591619
+ return obj;
591620
+ } catch { return null; }
591621
+ }
591622
+ function clearActiveRemoteShare() {
591623
+ try { localStorage.removeItem('oa.activeRemoteShare'); } catch {}
591624
+ }
591625
+ function installRemoteFetchProxy() {
591626
+ if (_oaRemoteFetchInstalled) return;
591627
+ _oaRemoteFetchInstalled = true;
591628
+ const _origFetch = window.fetch.bind(window);
591629
+ window.fetch = async function(input, init) {
591630
+ const share = getActiveRemoteShare();
591631
+ if (!share) return _origFetch(input, init);
591632
+ let urlStr = '';
591633
+ if (typeof input === 'string') urlStr = input;
591634
+ else if (input && input.url) urlStr = input.url;
591635
+ else return _origFetch(input, init);
591636
+ let pathOnly;
591637
+ try {
591638
+ const u = new URL(urlStr, location.href);
591639
+ // Don't proxy:
591640
+ // - cross-origin (already remote)
591641
+ // - the proxy endpoint itself (infinite loop)
591642
+ // - non-/v1/* routes (e.g. /assets, /openapi.json)
591643
+ if (u.origin !== location.origin) return _origFetch(input, init);
591644
+ if (u.pathname === '/v1/remote-proxy') return _origFetch(input, init);
591645
+ if (!u.pathname.startsWith('/v1/')) return _origFetch(input, init);
591646
+ pathOnly = u.pathname + u.search;
591647
+ } catch { return _origFetch(input, init); }
591648
+
591649
+ const method = ((init && init.method) || (input && input.method) || 'GET').toUpperCase();
591650
+ const headersIn = {};
591651
+ if (init && init.headers) {
591652
+ const h = init.headers;
591653
+ if (h instanceof Headers) h.forEach((v, k) => { headersIn[k] = v; });
591654
+ else if (Array.isArray(h)) h.forEach(([k, v]) => { headersIn[k] = v; });
591655
+ else Object.assign(headersIn, h);
591656
+ }
591657
+ let bodyOut;
591658
+ if (init && init.body !== undefined && init.body !== null) {
591659
+ if (typeof init.body === 'string') bodyOut = init.body;
591660
+ else if (init.body instanceof FormData) {
591661
+ const obj = {}; init.body.forEach((v, k) => { obj[k] = v; });
591662
+ bodyOut = obj;
591663
+ } else bodyOut = init.body;
591664
+ }
591665
+ // Heuristic: SSE if Accept includes text/event-stream OR the path is
591666
+ // a known streaming endpoint. We open the proxy in stream mode and
591667
+ // surface a Response with text/event-stream.
591668
+ const acceptHdr = (headersIn['accept'] || headersIn['Accept'] || '').toLowerCase();
591669
+ const wantsStream = acceptHdr.includes('text/event-stream')
591670
+ || pathOnly.includes('/v1/chat/completions')
591671
+ || pathOnly.includes('/v1/events');
591672
+
591673
+ const proxyBody = JSON.stringify({
591674
+ peerId: share.peerId || null,
591675
+ onion: share.onion || null,
591676
+ key: share.key,
591677
+ method, path: pathOnly, headers: headersIn, body: bodyOut,
591678
+ stream: wantsStream, timeoutMs: 120000,
591679
+ });
591680
+ if (wantsStream) {
591681
+ // Pass through as-is — receiver returns text/event-stream.
591682
+ return _origFetch('/v1/remote-proxy', {
591683
+ method: 'POST',
591684
+ headers: { 'content-type': 'application/json', 'accept': 'text/event-stream' },
591685
+ body: proxyBody,
591686
+ });
591687
+ }
591688
+ // Non-stream: receiver returns a JSON envelope { status, headers, body }.
591689
+ // Synthesize a Response that mimics the original remote response.
591690
+ const proxyResp = await _origFetch('/v1/remote-proxy', {
591691
+ method: 'POST',
591692
+ headers: { 'content-type': 'application/json' },
591693
+ body: proxyBody,
591694
+ });
591695
+ if (!proxyResp.ok) return proxyResp;
591696
+ let env = null;
591697
+ try { env = await proxyResp.json(); } catch {}
591698
+ if (!env || typeof env !== 'object') {
591699
+ return new Response('', { status: 502, statusText: 'Empty proxy response' });
591700
+ }
591701
+ // The non-stream envelope is the http_tunnel handler last event,
591702
+ // with its body JSON-stringified inside the data field. Unwrap it.
591703
+ let status = 200;
591704
+ let headersOut = new Headers();
591705
+ let bodyText = '';
591706
+ if (typeof env.raw === 'string') {
591707
+ // Single-shot result from the http_tunnel head+body events combined
591708
+ bodyText = env.raw;
591709
+ } else if (env.event === 'http.body' || env.event === 'http.head') {
591710
+ try {
591711
+ const inner = JSON.parse(env.data);
591712
+ if (inner.status) status = inner.status;
591713
+ if (inner.headers) Object.entries(inner.headers).forEach(([k, v]) => headersOut.set(k, String(v)));
591714
+ } catch {}
591715
+ bodyText = String(env.data || '');
591716
+ } else {
591717
+ bodyText = JSON.stringify(env);
591718
+ }
591719
+ return new Response(bodyText, { status, headers: headersOut });
591720
+ };
591721
+ }
591722
+ // Auto-install on every load if a remote share is active.
591723
+ try {
591724
+ if (getActiveRemoteShare()) installRemoteFetchProxy();
591725
+ } catch {}
590913
591726
  function clearKey() {
590914
591727
  apiKey = '';
590915
591728
  localStorage.removeItem('oa-api-key');
@@ -590930,14 +591743,23 @@ function openKeyModal() {
590930
591743
  window.openKeyModal = openKeyModal;
590931
591744
 
590932
591745
  // ─── Share URL parsing ─────────────────────────────────────────────────
590933
- // Accepts BOTH:
590934
- // oa-share://[peerId@]host:port#key
590935
- // http(s)://host:port/?oa-key=KEY[&oa-share-label=LABEL]
590936
- // Returns { host, key, scheme?, label? } or null when the input is a plain key.
591746
+ // Accepts:
591747
+ // oa-share://<peerId>#<key> (libp2p, global)
591748
+ // oa-share://<peerId>@<host:port>#<key> (libp2p w/ LAN hint)
591749
+ // oa-share://<host:port>#<key> (legacy direct-HTTP)
591750
+ // http(s)://host:port/?oa-key=KEY[&oa-share-peer=PID&oa-share-label=L]
591751
+ // Returns { peerId?, host?, key, scheme?, label? } or null when the input
591752
+ // is a plain key. peerId is a libp2p PeerID (starts with 12D3KooW or Qm).
591753
+ function _looksLikePeerId(s) {
591754
+ if (!s || typeof s !== 'string') return false;
591755
+ // libp2p PeerIDs are base58-encoded multihashes, typically starting with
591756
+ // 12D3KooW (Ed25519) or Qm (RSA). Length ~46-52 chars, no dots or colons.
591757
+ return /^(12D3KooW|Qm)[1-9A-HJ-NP-Za-km-z]{30,}$/.test(s);
591758
+ }
590937
591759
  function parseShareInput(raw) {
590938
591760
  const v = String(raw || '').trim();
590939
591761
  if (!v) return null;
590940
- // oa-share scheme — use a custom parser since URL() doesn't always honor it.
591762
+ // oa-share scheme — custom parser since URL() doesn't always honor it.
590941
591763
  if (v.toLowerCase().startsWith('oa-share://')) {
590942
591764
  const after = v.slice('oa-share://'.length);
590943
591765
  const hashIdx = after.indexOf('#');
@@ -590945,19 +591767,36 @@ function parseShareInput(raw) {
590945
591767
  const hostPart = after.slice(0, hashIdx);
590946
591768
  const key = after.slice(hashIdx + 1);
590947
591769
  if (!hostPart || !key) return null;
590948
- // Strip optional peerId@ prefix (forward-compat for libp2p tunneling).
591770
+ // Three shapes:
591771
+ // peerId@host:port → libp2p+LAN
591772
+ // peerId → libp2p only (no host)
591773
+ // host:port → legacy direct
590949
591774
  const atIdx = hostPart.indexOf('@');
590950
- const host = atIdx >= 0 ? hostPart.slice(atIdx + 1) : hostPart;
590951
- return { host, key, scheme: 'http' };
591775
+ if (atIdx >= 0) {
591776
+ const peerId = hostPart.slice(0, atIdx);
591777
+ const host = hostPart.slice(atIdx + 1);
591778
+ return { peerId: _looksLikePeerId(peerId) ? peerId : null, host, key, scheme: 'http' };
591779
+ }
591780
+ if (_looksLikePeerId(hostPart)) {
591781
+ return { peerId: hostPart, host: null, key, scheme: 'libp2p' };
591782
+ }
591783
+ return { peerId: null, host: hostPart, key, scheme: 'http' };
590952
591784
  }
590953
- // http(s) URL with ?oa-key=...
591785
+ // http(s) URL with ?oa-key=, optional ?oa-share-peer=, optional ?oa-onion=
590954
591786
  if (/^https?:\\/\\//i.test(v)) {
590955
591787
  try {
590956
591788
  const u = new URL(v);
590957
591789
  const k = u.searchParams.get('oa-key');
590958
591790
  if (!k) return null;
591791
+ const peerIdQ = u.searchParams.get('oa-share-peer') || null;
591792
+ const onionQ = u.searchParams.get('oa-onion') || null;
590959
591793
  const label = u.searchParams.get('oa-share-label') || '';
590960
- return { host: u.host, key: k, scheme: u.protocol.replace(':', ''), label };
591794
+ return {
591795
+ peerId: _looksLikePeerId(peerIdQ) ? peerIdQ : null,
591796
+ onion: (onionQ && onionQ.endsWith('.onion')) ? onionQ : null,
591797
+ host: u.host, key: k,
591798
+ scheme: u.protocol.replace(':', ''), label,
591799
+ };
590961
591800
  } catch { return null; }
590962
591801
  }
590963
591802
  return null;
@@ -591133,17 +591972,32 @@ window.copyShareUrl = copyShareUrl;
591133
591972
  // inline with a "close connection" button that severs and shuffles the
591134
591973
  // key into recents.
591135
591974
  function refreshKeyModalRemoteState() {
591136
- const remote = (function() {
591975
+ // Two remote modes coexist:
591976
+ // 1. libp2p — oa.activeRemoteShare = {peerId, key, host?, label}
591977
+ // 2. direct — oa.remoteHost (legacy, set by ?oa-key= pickup)
591978
+ const active = getActiveRemoteShare();
591979
+ const directHost = (function() {
591137
591980
  try { return localStorage.getItem('oa.remoteHost') || ''; } catch { return ''; }
591138
591981
  })();
591982
+ const isRemote = !!active || !!directHost;
591983
+ let remoteLabel;
591984
+ if (active) {
591985
+ const parts = [];
591986
+ if (active.peerId) parts.push('libp2p ' + active.peerId.slice(0, 12) + '…');
591987
+ if (active.onion) parts.push('tor ' + active.onion.slice(0, 16) + '…');
591988
+ if (active.host) parts.push(active.host);
591989
+ remoteLabel = parts.join(' / ') || 'remote';
591990
+ } else {
591991
+ remoteLabel = directHost;
591992
+ }
591139
591993
  const stateBox = document.getElementById('remote-state');
591140
591994
  const btn = document.getElementById('sidebar-key-btn');
591141
- if (remote && btn) {
591995
+ if (isRemote && btn) {
591142
591996
  btn.textContent = 'remote';
591143
591997
  btn.style.background = 'var(--color-accent)';
591144
591998
  btn.style.color = '#fff';
591145
591999
  btn.style.borderColor = 'var(--color-accent)';
591146
- btn.title = 'connected to remote ' + remote + ' — click to view / disconnect';
592000
+ btn.title = 'connected to ' + remoteLabel + ' — click to view / disconnect';
591147
592001
  } else if (btn) {
591148
592002
  btn.textContent = 'key';
591149
592003
  btn.style.background = 'transparent';
@@ -591152,27 +592006,43 @@ function refreshKeyModalRemoteState() {
591152
592006
  btn.title = 'set API key / share access';
591153
592007
  }
591154
592008
  if (!stateBox) return;
591155
- if (remote) {
591156
- const safeRemote = escapeHtml(remote);
592009
+ if (isRemote) {
592010
+ const safe = escapeHtml(remoteLabel);
592011
+ let mode;
592012
+ if (active) {
592013
+ const tiers = [];
592014
+ if (active.peerId) tiers.push('libp2p');
592015
+ if (active.onion) tiers.push('tor');
592016
+ mode = tiers.join(' + ') + ' (global)';
592017
+ } else {
592018
+ mode = 'direct (LAN/VPN)';
592019
+ }
591157
592020
  stateBox.style.display = 'block';
591158
592021
  stateBox.innerHTML =
591159
592022
  '<div style="font-weight:500;color:var(--color-accent)">REMOTE connection active</div>' +
591160
- '<div style="margin-top:4px;font-size:0.74rem">host <code>' + safeRemote + '</code></div>' +
592023
+ '<div style="margin-top:4px;font-size:0.74rem">mode <code>' + escapeHtml(mode) + '</code></div>' +
592024
+ '<div style="margin-top:2px;font-size:0.74rem">target <code>' + safe + '</code></div>' +
591161
592025
  '<div style="margin-top:8px"><button type="button" onclick="closeRemoteConnection()" style="background:var(--color-error);color:#fff;border:none;padding:4px 10px;border-radius:var(--radius-sm);cursor:pointer;font-size:0.74rem">close connection</button></div>';
591162
592026
  } else {
591163
592027
  stateBox.style.display = 'none';
591164
592028
  }
591165
592029
  }
591166
592030
  function closeRemoteConnection() {
591167
- // Move current remote key into recents BEFORE clearing.
591168
- let savedKey = '';
591169
- let savedHost = '';
591170
- try {
591171
- savedKey = localStorage.getItem('oa-api-key') || '';
591172
- savedHost = localStorage.getItem('oa.remoteHost') || '';
591173
- } catch {}
591174
- if (savedKey) {
591175
- saveRecentKey({ key: savedKey, host: savedHost, label: 'recent remote ' + savedHost });
592031
+ // Save the active remote into recents before clearing.
592032
+ const active = getActiveRemoteShare();
592033
+ if (active) {
592034
+ saveRecentKey({
592035
+ key: active.key, peerId: active.peerId, host: active.host,
592036
+ label: 'recent ' + (active.label || ('remote ' + (active.peerId || '').slice(0, 12) + '')),
592037
+ });
592038
+ clearActiveRemoteShare();
592039
+ } else {
592040
+ let savedKey = ''; let savedHost = '';
592041
+ try {
592042
+ savedKey = localStorage.getItem('oa-api-key') || '';
592043
+ savedHost = localStorage.getItem('oa.remoteHost') || '';
592044
+ } catch {}
592045
+ if (savedKey) saveRecentKey({ key: savedKey, host: savedHost, label: 'recent remote ' + savedHost });
591176
592046
  }
591177
592047
  try {
591178
592048
  localStorage.removeItem('oa.remoteHost');
@@ -591181,7 +592051,6 @@ function closeRemoteConnection() {
591181
592051
  } catch {}
591182
592052
  apiKey = '';
591183
592053
  refreshKeyModalRemoteState();
591184
- // Reload to drop any cached state from the remote target.
591185
592054
  location.reload();
591186
592055
  }
591187
592056
  window.closeRemoteConnection = closeRemoteConnection;
@@ -595973,15 +596842,15 @@ var init_auth_oidc = __esm({
595973
596842
  });
595974
596843
 
595975
596844
  // packages/cli/src/api/usage-tracker.ts
595976
- import { mkdirSync as mkdirSync60, readFileSync as readFileSync83, writeFileSync as writeFileSync52, existsSync as existsSync102 } from "node:fs";
595977
- import { join as join118 } from "node:path";
596845
+ import { mkdirSync as mkdirSync60, readFileSync as readFileSync84, writeFileSync as writeFileSync52, existsSync as existsSync103 } from "node:fs";
596846
+ import { join as join119 } from "node:path";
595978
596847
  function initUsageTracker(oaDir) {
595979
- const dir = join118(oaDir, "usage");
596848
+ const dir = join119(oaDir, "usage");
595980
596849
  mkdirSync60(dir, { recursive: true });
595981
- usageFile = join118(dir, "token-usage.json");
596850
+ usageFile = join119(dir, "token-usage.json");
595982
596851
  try {
595983
- if (existsSync102(usageFile)) {
595984
- store = JSON.parse(readFileSync83(usageFile, "utf-8"));
596852
+ if (existsSync103(usageFile)) {
596853
+ store = JSON.parse(readFileSync84(usageFile, "utf-8"));
595985
596854
  }
595986
596855
  } catch {
595987
596856
  store = { providers: {}, lastSaved: "" };
@@ -596045,24 +596914,24 @@ var init_usage_tracker = __esm({
596045
596914
  });
596046
596915
 
596047
596916
  // packages/cli/src/api/profiles.ts
596048
- import { existsSync as existsSync103, readFileSync as readFileSync84, writeFileSync as writeFileSync53, mkdirSync as mkdirSync61, readdirSync as readdirSync35, unlinkSync as unlinkSync23 } from "node:fs";
596049
- import { join as join119 } from "node:path";
596050
- import { homedir as homedir40 } from "node:os";
596917
+ import { existsSync as existsSync104, readFileSync as readFileSync85, writeFileSync as writeFileSync53, mkdirSync as mkdirSync61, readdirSync as readdirSync35, unlinkSync as unlinkSync23 } from "node:fs";
596918
+ import { join as join120 } from "node:path";
596919
+ import { homedir as homedir41 } from "node:os";
596051
596920
  import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes22, scryptSync as scryptSync3 } from "node:crypto";
596052
596921
  function globalProfileDir() {
596053
- return join119(homedir40(), ".open-agents", "profiles");
596922
+ return join120(homedir41(), ".open-agents", "profiles");
596054
596923
  }
596055
596924
  function projectProfileDir(projectDir2) {
596056
- return join119(projectDir2 || process.cwd(), ".oa", "profiles");
596925
+ return join120(projectDir2 || process.cwd(), ".oa", "profiles");
596057
596926
  }
596058
596927
  function listProfiles(projectDir2) {
596059
596928
  const result = [];
596060
596929
  const seen = /* @__PURE__ */ new Set();
596061
596930
  const projDir = projectProfileDir(projectDir2);
596062
- if (existsSync103(projDir)) {
596931
+ if (existsSync104(projDir)) {
596063
596932
  for (const f2 of readdirSync35(projDir).filter((f3) => f3.endsWith(".json"))) {
596064
596933
  try {
596065
- const raw = JSON.parse(readFileSync84(join119(projDir, f2), "utf8"));
596934
+ const raw = JSON.parse(readFileSync85(join120(projDir, f2), "utf8"));
596066
596935
  const name10 = f2.replace(".json", "");
596067
596936
  seen.add(name10);
596068
596937
  result.push({
@@ -596076,12 +596945,12 @@ function listProfiles(projectDir2) {
596076
596945
  }
596077
596946
  }
596078
596947
  const globDir = globalProfileDir();
596079
- if (existsSync103(globDir)) {
596948
+ if (existsSync104(globDir)) {
596080
596949
  for (const f2 of readdirSync35(globDir).filter((f3) => f3.endsWith(".json"))) {
596081
596950
  const name10 = f2.replace(".json", "");
596082
596951
  if (seen.has(name10)) continue;
596083
596952
  try {
596084
- const raw = JSON.parse(readFileSync84(join119(globDir, f2), "utf8"));
596953
+ const raw = JSON.parse(readFileSync85(join120(globDir, f2), "utf8"));
596085
596954
  result.push({
596086
596955
  name: name10,
596087
596956
  description: raw.description || "",
@@ -596096,11 +596965,11 @@ function listProfiles(projectDir2) {
596096
596965
  }
596097
596966
  function loadProfile(name10, password, projectDir2) {
596098
596967
  const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
596099
- const projPath = join119(projectProfileDir(projectDir2), `${sanitized}.json`);
596100
- const globPath = join119(globalProfileDir(), `${sanitized}.json`);
596101
- const filePath = existsSync103(projPath) ? projPath : existsSync103(globPath) ? globPath : null;
596968
+ const projPath = join120(projectProfileDir(projectDir2), `${sanitized}.json`);
596969
+ const globPath = join120(globalProfileDir(), `${sanitized}.json`);
596970
+ const filePath = existsSync104(projPath) ? projPath : existsSync104(globPath) ? globPath : null;
596102
596971
  if (!filePath) return null;
596103
- const raw = JSON.parse(readFileSync84(filePath, "utf8"));
596972
+ const raw = JSON.parse(readFileSync85(filePath, "utf8"));
596104
596973
  if (raw.encrypted === true) {
596105
596974
  if (!password) return null;
596106
596975
  return decryptProfile(raw, password);
@@ -596111,7 +596980,7 @@ function saveProfile(profile, password, scope = "global", projectDir2) {
596111
596980
  const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
596112
596981
  mkdirSync61(dir, { recursive: true });
596113
596982
  const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
596114
- const filePath = join119(dir, `${sanitized}.json`);
596983
+ const filePath = join120(dir, `${sanitized}.json`);
596115
596984
  profile.modified = (/* @__PURE__ */ new Date()).toISOString();
596116
596985
  if (password) {
596117
596986
  const encrypted = encryptProfile(profile, password);
@@ -596124,8 +596993,8 @@ function saveProfile(profile, password, scope = "global", projectDir2) {
596124
596993
  function deleteProfile(name10, scope = "global", projectDir2) {
596125
596994
  const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
596126
596995
  const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
596127
- const filePath = join119(dir, `${sanitized}.json`);
596128
- if (existsSync103(filePath)) {
596996
+ const filePath = join120(dir, `${sanitized}.json`);
596997
+ if (existsSync104(filePath)) {
596129
596998
  unlinkSync23(filePath);
596130
596999
  return true;
596131
597000
  }
@@ -596240,23 +597109,23 @@ var init_profiles = __esm({
596240
597109
 
596241
597110
  // packages/cli/src/docker.ts
596242
597111
  import { execSync as execSync56, spawn as spawn24 } from "node:child_process";
596243
- import { existsSync as existsSync104, mkdirSync as mkdirSync62, writeFileSync as writeFileSync54 } from "node:fs";
596244
- import { join as join120, resolve as resolve37, dirname as dirname35 } from "node:path";
596245
- import { homedir as homedir41 } from "node:os";
597112
+ import { existsSync as existsSync105, mkdirSync as mkdirSync62, writeFileSync as writeFileSync54 } from "node:fs";
597113
+ import { join as join121, resolve as resolve37, dirname as dirname35 } from "node:path";
597114
+ import { homedir as homedir42 } from "node:os";
596246
597115
  import { fileURLToPath as fileURLToPath16 } from "node:url";
596247
597116
  function getDockerDir() {
596248
597117
  try {
596249
597118
  if (typeof __dirname !== "undefined") {
596250
- return join120(__dirname, "..", "..", "..", "docker");
597119
+ return join121(__dirname, "..", "..", "..", "docker");
596251
597120
  }
596252
597121
  } catch {
596253
597122
  }
596254
597123
  try {
596255
597124
  const thisDir = dirname35(fileURLToPath16(import.meta.url));
596256
- return join120(thisDir, "..", "..", "..", "docker");
597125
+ return join121(thisDir, "..", "..", "..", "docker");
596257
597126
  } catch {
596258
597127
  }
596259
- return join120(process.cwd(), "docker");
597128
+ return join121(process.cwd(), "docker");
596260
597129
  }
596261
597130
  function isDockerAvailable() {
596262
597131
  try {
@@ -596387,10 +597256,10 @@ async function ensureOaImage(force = false) {
596387
597256
  }
596388
597257
  let buildContext;
596389
597258
  const dockerDir = getDockerDir();
596390
- if (existsSync104(join120(dockerDir, "Dockerfile"))) {
597259
+ if (existsSync105(join121(dockerDir, "Dockerfile"))) {
596391
597260
  buildContext = dockerDir;
596392
597261
  } else {
596393
- buildContext = join120(homedir41(), ".oa", "docker-build");
597262
+ buildContext = join121(homedir42(), ".oa", "docker-build");
596394
597263
  mkdirSync62(buildContext, { recursive: true });
596395
597264
  writeDockerfiles(buildContext);
596396
597265
  }
@@ -596465,8 +597334,8 @@ chown -R node:node /workspace /home/node/.oa /home/node/.open-agents 2>/dev/null
596465
597334
  if [ "$1" = "oa" ]; then shift; exec su - node -c "cd /workspace && oa $*"; fi
596466
597335
  exec "$@"
596467
597336
  `;
596468
- writeFileSync54(join120(dir, "Dockerfile"), dockerfile);
596469
- writeFileSync54(join120(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
597337
+ writeFileSync54(join121(dir, "Dockerfile"), dockerfile);
597338
+ writeFileSync54(join121(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
596470
597339
  }
596471
597340
  function hasNvidiaGpu() {
596472
597341
  try {
@@ -596719,23 +597588,23 @@ import * as http5 from "node:http";
596719
597588
  import * as https3 from "node:https";
596720
597589
  import { createRequire as createRequire5 } from "node:module";
596721
597590
  import { fileURLToPath as fileURLToPath17 } from "node:url";
596722
- import { dirname as dirname36, join as join121, resolve as resolve38 } from "node:path";
596723
- import { homedir as homedir42 } from "node:os";
597591
+ import { dirname as dirname36, join as join122, resolve as resolve38 } from "node:path";
597592
+ import { homedir as homedir43 } from "node:os";
596724
597593
  import { spawn as spawn25, execSync as execSync57 } from "node:child_process";
596725
- import { mkdirSync as mkdirSync63, writeFileSync as writeFileSync55, readFileSync as readFileSync85, readdirSync as readdirSync36, existsSync as existsSync105, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
597594
+ import { mkdirSync as mkdirSync63, writeFileSync as writeFileSync55, readFileSync as readFileSync86, readdirSync as readdirSync36, existsSync as existsSync106, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
596726
597595
  import { randomBytes as randomBytes23, randomUUID as randomUUID16 } from "node:crypto";
596727
597596
  import { createHash as createHash19 } from "node:crypto";
596728
597597
  function getVersion3() {
596729
597598
  try {
596730
597599
  const thisDir = dirname36(fileURLToPath17(import.meta.url));
596731
597600
  const candidates = [
596732
- join121(thisDir, "..", "package.json"),
596733
- join121(thisDir, "..", "..", "package.json"),
596734
- join121(thisDir, "..", "..", "..", "package.json")
597601
+ join122(thisDir, "..", "package.json"),
597602
+ join122(thisDir, "..", "..", "package.json"),
597603
+ join122(thisDir, "..", "..", "..", "package.json")
596735
597604
  ];
596736
597605
  for (const pkgPath of candidates) {
596737
597606
  try {
596738
- if (!existsSync105(pkgPath)) continue;
597607
+ if (!existsSync106(pkgPath)) continue;
596739
597608
  const pkg = require3(pkgPath);
596740
597609
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
596741
597610
  return pkg.version ?? "0.0.0";
@@ -596937,9 +597806,9 @@ function isOriginAllowed(origin) {
596937
597806
  if (!origin) return true;
596938
597807
  let accessMode = (process.env["OA_ACCESS"] || "").toLowerCase().trim();
596939
597808
  try {
596940
- const accessFile = join121(homedir42(), ".open-agents", "access");
596941
- if (existsSync105(accessFile)) {
596942
- const persisted = readFileSync85(accessFile, "utf8").trim().toLowerCase();
597809
+ const accessFile = join122(homedir43(), ".open-agents", "access");
597810
+ if (existsSync106(accessFile)) {
597811
+ const persisted = readFileSync86(accessFile, "utf8").trim().toLowerCase();
596943
597812
  if (persisted === "any" || persisted === "lan" || persisted === "loopback") {
596944
597813
  accessMode = persisted;
596945
597814
  }
@@ -596999,7 +597868,7 @@ async function retrieveMemoryContext(userMessage, sessionId, maxEpisodes = 5) {
596999
597868
  if (!memMod || !memMod.EpisodeStore) {
597000
597869
  return { contextBlock: "", retrieved: [] };
597001
597870
  }
597002
- const dbPath = join121(homedir42(), ".open-agents", "memory.db");
597871
+ const dbPath = join122(homedir43(), ".open-agents", "memory.db");
597003
597872
  const store2 = new memMod.EpisodeStore(dbPath);
597004
597873
  const recent = store2.search({ limit: 30, sessionId: void 0 }) ?? [];
597005
597874
  const qLower = userMessage.toLowerCase();
@@ -597042,7 +597911,7 @@ async function writeMemoryEpisodes(sessionId, userMessage, assistantContent, too
597042
597911
  try {
597043
597912
  const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2)).catch(() => null);
597044
597913
  if (!memMod || !memMod.EpisodeStore) return 0;
597045
- const dbPath = join121(homedir42(), ".open-agents", "memory.db");
597914
+ const dbPath = join122(homedir43(), ".open-agents", "memory.db");
597046
597915
  const store2 = new memMod.EpisodeStore(dbPath);
597047
597916
  let written = 0;
597048
597917
  try {
@@ -597364,27 +598233,27 @@ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError, ti
597364
598233
  }
597365
598234
  function jobsDir() {
597366
598235
  const root = resolve38(process.cwd());
597367
- const dir = join121(root, ".oa", "jobs");
598236
+ const dir = join122(root, ".oa", "jobs");
597368
598237
  mkdirSync63(dir, { recursive: true });
597369
598238
  return dir;
597370
598239
  }
597371
598240
  function loadJob(id) {
597372
- const file = join121(jobsDir(), `${id}.json`);
597373
- if (!existsSync105(file)) return null;
598241
+ const file = join122(jobsDir(), `${id}.json`);
598242
+ if (!existsSync106(file)) return null;
597374
598243
  try {
597375
- return JSON.parse(readFileSync85(file, "utf-8"));
598244
+ return JSON.parse(readFileSync86(file, "utf-8"));
597376
598245
  } catch {
597377
598246
  return null;
597378
598247
  }
597379
598248
  }
597380
598249
  function listJobs() {
597381
598250
  const dir = jobsDir();
597382
- if (!existsSync105(dir)) return [];
598251
+ if (!existsSync106(dir)) return [];
597383
598252
  const files = readdirSync36(dir).filter((f2) => f2.endsWith(".json")).sort();
597384
598253
  const jobs = [];
597385
598254
  for (const file of files) {
597386
598255
  try {
597387
- jobs.push(JSON.parse(readFileSync85(join121(dir, file), "utf-8")));
598256
+ jobs.push(JSON.parse(readFileSync86(join122(dir, file), "utf-8")));
597388
598257
  } catch {
597389
598258
  }
597390
598259
  }
@@ -597394,14 +598263,14 @@ function pruneOldJobs() {
597394
598263
  const retentionH = parseFloat(process.env["OA_RUN_RETENTION_H"] || "24");
597395
598264
  const cutoffMs = Date.now() - (Number.isFinite(retentionH) && retentionH > 0 ? retentionH : 24) * 36e5;
597396
598265
  const dir = jobsDir();
597397
- if (!existsSync105(dir)) return { pruned: 0, kept: 0 };
598266
+ if (!existsSync106(dir)) return { pruned: 0, kept: 0 };
597398
598267
  let pruned = 0;
597399
598268
  let kept = 0;
597400
598269
  for (const file of readdirSync36(dir)) {
597401
598270
  if (!file.endsWith(".json")) continue;
597402
- const path8 = join121(dir, file);
598271
+ const path8 = join122(dir, file);
597403
598272
  try {
597404
- const job = JSON.parse(readFileSync85(path8, "utf-8"));
598273
+ const job = JSON.parse(readFileSync86(path8, "utf-8"));
597405
598274
  if (job.status === "running") {
597406
598275
  kept++;
597407
598276
  continue;
@@ -597414,7 +598283,7 @@ function pruneOldJobs() {
597414
598283
  } catch {
597415
598284
  }
597416
598285
  const outFile = path8.replace(/\.json$/, ".output");
597417
- if (existsSync105(outFile)) {
598286
+ if (existsSync106(outFile)) {
597418
598287
  try {
597419
598288
  unlinkSync24(outFile);
597420
598289
  } catch {
@@ -597707,7 +598576,7 @@ function autoSeedTodosFromPrompt(prompt) {
597707
598576
  return [];
597708
598577
  }
597709
598578
  function atomicJobWrite(dir, id, job) {
597710
- const finalPath = join121(dir, `${id}.json`);
598579
+ const finalPath = join122(dir, `${id}.json`);
597711
598580
  const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
597712
598581
  try {
597713
598582
  writeFileSync55(tmpPath, JSON.stringify(job, null, 2), "utf-8");
@@ -599133,23 +600002,23 @@ ${task}` : task;
599133
600002
  });
599134
600003
  }
599135
600004
  function updateStateFile() {
599136
- return join121(homedir42(), ".open-agents", "update-state.json");
600005
+ return join122(homedir43(), ".open-agents", "update-state.json");
599137
600006
  }
599138
600007
  function updateLogPath() {
599139
- return join121(homedir42(), ".open-agents", "update.log");
600008
+ return join122(homedir43(), ".open-agents", "update.log");
599140
600009
  }
599141
600010
  function readUpdateState() {
599142
600011
  try {
599143
600012
  const p2 = updateStateFile();
599144
- if (!existsSync105(p2)) return null;
599145
- return JSON.parse(readFileSync85(p2, "utf-8"));
600013
+ if (!existsSync106(p2)) return null;
600014
+ return JSON.parse(readFileSync86(p2, "utf-8"));
599146
600015
  } catch {
599147
600016
  return null;
599148
600017
  }
599149
600018
  }
599150
600019
  function writeUpdateState(state) {
599151
600020
  try {
599152
- const dir = join121(homedir42(), ".open-agents");
600021
+ const dir = join122(homedir43(), ".open-agents");
599153
600022
  mkdirSync63(dir, { recursive: true });
599154
600023
  const finalPath = updateStateFile();
599155
600024
  const tmpPath = `${finalPath}.tmp.${process.pid}`;
@@ -599197,15 +600066,15 @@ async function handleV1Update(req2, res, requestId) {
599197
600066
  const { execSync: es } = require3("node:child_process");
599198
600067
  const isWin2 = process.platform === "win32";
599199
600068
  let npmBin = "";
599200
- for (const candidate of isWin2 ? [join121(nodeDir, "npm.cmd"), join121(nodeDir, "npm")] : [join121(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
599201
- if (existsSync105(candidate)) {
600069
+ for (const candidate of isWin2 ? [join122(nodeDir, "npm.cmd"), join122(nodeDir, "npm")] : [join122(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
600070
+ if (existsSync106(candidate)) {
599202
600071
  npmBin = candidate;
599203
600072
  break;
599204
600073
  }
599205
600074
  }
599206
600075
  if (!npmBin) npmBin = isWin2 ? "npm.cmd" : "npm";
599207
600076
  const pkgSpec = `open-agents-ai@${targetVersion}`;
599208
- const dir = join121(homedir42(), ".open-agents");
600077
+ const dir = join122(homedir43(), ".open-agents");
599209
600078
  fs7.mkdirSync(dir, { recursive: true });
599210
600079
  const logFd = fs7.openSync(logPath3, "w");
599211
600080
  const npmPrefix = dirname36(nodeDir);
@@ -599215,13 +600084,13 @@ async function handleV1Update(req2, res, requestId) {
599215
600084
  globalBinDir = es(`${npmBin} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
599216
600085
  } else {
599217
600086
  const npmCliCandidates = [
599218
- join121(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
599219
- join121(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
600087
+ join122(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
600088
+ join122(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
599220
600089
  ];
599221
600090
  let npmCli = "";
599222
600091
  for (const c9 of npmCliCandidates) {
599223
600092
  try {
599224
- if (existsSync105(c9)) {
600093
+ if (existsSync106(c9)) {
599225
600094
  npmCli = c9;
599226
600095
  break;
599227
600096
  }
@@ -599253,13 +600122,13 @@ async function handleV1Update(req2, res, requestId) {
599253
600122
  });
599254
600123
  } else {
599255
600124
  const npmCliCandidates = [
599256
- join121(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
599257
- join121(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
600125
+ join122(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
600126
+ join122(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
599258
600127
  ];
599259
600128
  let npmCli = "";
599260
600129
  for (const c9 of npmCliCandidates) {
599261
600130
  try {
599262
- if (existsSync105(c9)) {
600131
+ if (existsSync106(c9)) {
599263
600132
  npmCli = c9;
599264
600133
  break;
599265
600134
  }
@@ -599356,8 +600225,8 @@ function handleV1UpdateStatus(res) {
599356
600225
  let logTail = "";
599357
600226
  let exitCode = null;
599358
600227
  try {
599359
- if (existsSync105(logPath3)) {
599360
- const raw = readFileSync85(logPath3, "utf-8");
600228
+ if (existsSync106(logPath3)) {
600229
+ const raw = readFileSync86(logPath3, "utf-8");
599361
600230
  const m2 = raw.match(/__EXIT_CODE=(\d+)/);
599362
600231
  if (m2) exitCode = parseInt(m2[1], 10);
599363
600232
  logTail = raw.slice(-2e3);
@@ -599453,7 +600322,7 @@ async function handleV1Run(req2, res) {
599453
600322
  if (workingDir) {
599454
600323
  cwd4 = resolve38(workingDir);
599455
600324
  } else if (isolate) {
599456
- const wsDir = join121(dir, "..", "workspaces", id);
600325
+ const wsDir = join122(dir, "..", "workspaces", id);
599457
600326
  mkdirSync63(wsDir, { recursive: true });
599458
600327
  cwd4 = wsDir;
599459
600328
  } else {
@@ -599640,7 +600509,7 @@ async function handleV1Run(req2, res) {
599640
600509
  let output = "";
599641
600510
  let tailBytes = 0;
599642
600511
  const TAIL_BUDGET = 1048576;
599643
- const outputWriter = new DiskTaskOutput(join121(dir, `${id}.output`));
600512
+ const outputWriter = new DiskTaskOutput(join122(dir, `${id}.output`));
599644
600513
  job.outputFile = outputWriter.path;
599645
600514
  atomicJobWrite(dir, id, job);
599646
600515
  child.stdout?.on("data", (chunk) => {
@@ -602214,7 +603083,7 @@ ${steering}`;
602214
603083
  function getScheduleRoots() {
602215
603084
  const rootsEnv = process.env["OA_SCHEDULE_ROOTS"] || "";
602216
603085
  const roots = rootsEnv.split(rootsEnv.includes(";") ? ";" : ":").filter(Boolean);
602217
- const defaults3 = [process.cwd(), join121(homedir42(), "Documents")];
603086
+ const defaults3 = [process.cwd(), join122(homedir43(), "Documents")];
602218
603087
  const set = /* @__PURE__ */ new Set([...defaults3, ...roots]);
602219
603088
  return [...set];
602220
603089
  }
@@ -602226,10 +603095,10 @@ function listScheduledTasks() {
602226
603095
  for (const root of roots) {
602227
603096
  try {
602228
603097
  walk(root, 0, (dir) => {
602229
- if (dir.endsWith(`${join121(".oa", "scheduled")}`) || dir.includes(`${join121(".oa", "scheduled")}`)) {
602230
- const file = join121(dir, "tasks.json");
603098
+ if (dir.endsWith(`${join122(".oa", "scheduled")}`) || dir.includes(`${join122(".oa", "scheduled")}`)) {
603099
+ const file = join122(dir, "tasks.json");
602231
603100
  try {
602232
- const raw = readFileSync85(file, "utf-8");
603101
+ const raw = readFileSync86(file, "utf-8");
602233
603102
  const json = JSON.parse(raw);
602234
603103
  const tasks = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
602235
603104
  tasks.forEach((t2, i2) => {
@@ -602294,7 +603163,7 @@ function walk(dir, depth, onDir, maxDepth) {
602294
603163
  if (e2.name === "node_modules" || e2.name.startsWith(".")) {
602295
603164
  if (e2.name !== ".oa") continue;
602296
603165
  }
602297
- const child = join121(dir, e2.name);
603166
+ const child = join122(dir, e2.name);
602298
603167
  walk(child, depth + 1, onDir, maxDepth);
602299
603168
  }
602300
603169
  }
@@ -602303,7 +603172,7 @@ function setScheduledEnabled(id, enabled2) {
602303
603172
  const target = tasks.find((t2) => t2.id === id);
602304
603173
  if (!target) return false;
602305
603174
  try {
602306
- const raw = readFileSync85(target.file, "utf-8");
603175
+ const raw = readFileSync86(target.file, "utf-8");
602307
603176
  const json = JSON.parse(raw);
602308
603177
  const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
602309
603178
  if (!arr[target.index]) return false;
@@ -602336,7 +603205,7 @@ function deleteScheduledById(id) {
602336
603205
  const target = tasks.find((t2) => t2.id === id);
602337
603206
  if (!target) return false;
602338
603207
  try {
602339
- const raw = readFileSync85(target.file, "utf-8");
603208
+ const raw = readFileSync86(target.file, "utf-8");
602340
603209
  const json = JSON.parse(raw);
602341
603210
  const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
602342
603211
  if (!arr[target.index]) return false;
@@ -602601,11 +603470,11 @@ function reconcileScheduledTasks(apply) {
602601
603470
  const errors = [];
602602
603471
  for (const f2 of found) {
602603
603472
  const wdir = f2.workingDir || process.cwd();
602604
- const file = join121(wdir, ".oa", "scheduled", "tasks.json");
603473
+ const file = join122(wdir, ".oa", "scheduled", "tasks.json");
602605
603474
  try {
602606
603475
  let json = { tasks: [] };
602607
603476
  try {
602608
- const raw = readFileSync85(file, "utf-8");
603477
+ const raw = readFileSync86(file, "utf-8");
602609
603478
  json = JSON.parse(raw);
602610
603479
  } catch {
602611
603480
  }
@@ -602616,8 +603485,8 @@ function reconcileScheduledTasks(apply) {
602616
603485
  const entry = { task: f2.task || `legacy ${f2.id}`, schedule: f2.cron, enabled: true };
602617
603486
  arr.push(entry);
602618
603487
  const toWrite = Array.isArray(json?.tasks) ? { ...json, tasks: arr } : Array.isArray(json) ? arr : { tasks: arr };
602619
- mkdirSync63(join121(wdir, ".oa", "scheduled"), { recursive: true });
602620
- mkdirSync63(join121(wdir, ".oa", "scheduled", "logs"), { recursive: true });
603488
+ mkdirSync63(join122(wdir, ".oa", "scheduled"), { recursive: true });
603489
+ mkdirSync63(join122(wdir, ".oa", "scheduled", "logs"), { recursive: true });
602621
603490
  writeFileSync55(file, JSON.stringify(toWrite, null, 2));
602622
603491
  adopted.push({ file, index: arr.length - 1 });
602623
603492
  }
@@ -602662,32 +603531,32 @@ function writeCrontabLines(lines) {
602662
603531
  }
602663
603532
  function canonicalCronLine(rec) {
602664
603533
  const oaBin = findOaBinary4();
602665
- const logDir = join121(rec.workingDir, ".oa", "scheduled", "logs");
602666
- const logFile = join121(logDir, `${rec.id}.log`);
602667
- const storeFile = join121(rec.workingDir, ".oa", "scheduled", "tasks.json");
603534
+ const logDir = join122(rec.workingDir, ".oa", "scheduled", "logs");
603535
+ const logFile = join122(logDir, `${rec.id}.log`);
603536
+ const storeFile = join122(rec.workingDir, ".oa", "scheduled", "tasks.json");
602668
603537
  const taskEsc = rec.task.replace(/'/g, "'\\''");
602669
- const lockDir = join121(rec.workingDir, ".oa", "run");
602670
- const lockPath = join121(lockDir, `${rec.id}.lock`);
603538
+ const lockDir = join122(rec.workingDir, ".oa", "run");
603539
+ const lockPath = join122(lockDir, `${rec.id}.lock`);
602671
603540
  const wrapper = [
602672
603541
  `cd ${JSON.stringify(rec.workingDir)}`,
602673
603542
  `mkdir -p ${JSON.stringify(logDir)}`,
602674
603543
  `mkdir -p ${JSON.stringify(lockDir)}`,
602675
603544
  `if mkdir ${JSON.stringify(lockPath)} 2>/dev/null; then`,
602676
- ` echo $$ > ${JSON.stringify(join121(lockPath, "pid"))}`,
603545
+ ` echo $$ > ${JSON.stringify(join122(lockPath, "pid"))}`,
602677
603546
  ` trap 'rm -rf ${lockPath}' EXIT`,
602678
603547
  `else`,
602679
- ` if [ -f ${JSON.stringify(join121(lockPath, "pid"))} ]; then`,
602680
- ` oldpid=$(cat ${JSON.stringify(join121(lockPath, "pid"))} 2>/dev/null || echo)`,
603548
+ ` if [ -f ${JSON.stringify(join122(lockPath, "pid"))} ]; then`,
603549
+ ` oldpid=$(cat ${JSON.stringify(join122(lockPath, "pid"))} 2>/dev/null || echo)`,
602681
603550
  ` if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then`,
602682
603551
  ` echo "[oa-scheduler] ${rec.id} already running as PID $oldpid; skipping" >> ${JSON.stringify(logFile)}`,
602683
603552
  ` exit 0`,
602684
603553
  ` else`,
602685
603554
  ` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
602686
- ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join121(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
603555
+ ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join122(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
602687
603556
  ` fi`,
602688
603557
  ` else`,
602689
603558
  ` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
602690
- ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join121(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
603559
+ ` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join122(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
602691
603560
  ` fi`,
602692
603561
  `fi`,
602693
603562
  `${oaBin} '${taskEsc}' >> ${JSON.stringify(logFile)} 2>&1; _oa_exit=$?`,
@@ -602719,9 +603588,9 @@ function fixupOrMigrateScheduled(mode, dryRun) {
602719
603588
  try {
602720
603589
  if (!f2.workingDir || !f2.task) continue;
602721
603590
  const unitBase = `oa-${f2.id}`;
602722
- const unitDir = join121(homedir42(), ".config", "systemd", "user");
602723
- const svc = join121(unitDir, `${unitBase}.service`);
602724
- const tim = join121(unitDir, `${unitBase}.timer`);
603591
+ const unitDir = join122(homedir43(), ".config", "systemd", "user");
603592
+ const svc = join122(unitDir, `${unitBase}.service`);
603593
+ const tim = join122(unitDir, `${unitBase}.timer`);
602725
603594
  const oaBin = findOaBinary4();
602726
603595
  const rec = { id: f2.id, cron: f2.cron, workingDir: f2.workingDir, task: f2.task };
602727
603596
  const cmd = canonicalCronLine(rec).split(" ").slice(5).join(" ");
@@ -602847,8 +603716,8 @@ function startApiServer(options2 = {}) {
602847
603716
  const config = loadConfig();
602848
603717
  const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
602849
603718
  const cwd4 = process.cwd();
602850
- initAuditLog(join121(cwd4, ".oa"));
602851
- initUsageTracker(join121(cwd4, ".oa"));
603719
+ initAuditLog(join122(cwd4, ".oa"));
603720
+ initUsageTracker(join122(cwd4, ".oa"));
602852
603721
  try {
602853
603722
  const taskMgr = getSharedTaskManager();
602854
603723
  taskMgr.setEventPublisher((type, data, opts) => {
@@ -602899,7 +603768,7 @@ function startApiServer(options2 = {}) {
602899
603768
  if (!f2.endsWith(".json") || f2.includes(".tmp.")) continue;
602900
603769
  const sid = f2.replace(/\.json$/, "");
602901
603770
  try {
602902
- const items = JSON.parse(readFileSync85(join121(dir, f2), "utf-8"));
603771
+ const items = JSON.parse(readFileSync86(join122(dir, f2), "utf-8"));
602903
603772
  if (Array.isArray(items)) {
602904
603773
  cache8.set(sid, new Map(items.map((t2) => [t2.id, t2])));
602905
603774
  }
@@ -602911,10 +603780,10 @@ function startApiServer(options2 = {}) {
602911
603780
  const watcher = fsWatch3(dir, (_evt, fname) => {
602912
603781
  if (!fname || !fname.endsWith(".json") || fname.includes(".tmp.")) return;
602913
603782
  const sid = fname.replace(/\.json$/, "");
602914
- const fp = join121(dir, fname);
603783
+ const fp = join122(dir, fname);
602915
603784
  let next = [];
602916
603785
  try {
602917
- if (!existsSync105(fp)) {
603786
+ if (!existsSync106(fp)) {
602918
603787
  const old = cache8.get(sid);
602919
603788
  if (old) {
602920
603789
  for (const t2 of old.values()) {
@@ -602927,7 +603796,7 @@ function startApiServer(options2 = {}) {
602927
603796
  }
602928
603797
  return;
602929
603798
  }
602930
- next = JSON.parse(readFileSync85(fp, "utf-8"));
603799
+ next = JSON.parse(readFileSync86(fp, "utf-8"));
602931
603800
  if (!Array.isArray(next)) return;
602932
603801
  } catch {
602933
603802
  return;
@@ -602966,14 +603835,14 @@ function startApiServer(options2 = {}) {
602966
603835
  const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
602967
603836
  if (retentionDays > 0) {
602968
603837
  try {
602969
- const jobsDir3 = join121(cwd4, ".oa", "jobs");
602970
- if (existsSync105(jobsDir3)) {
603838
+ const jobsDir3 = join122(cwd4, ".oa", "jobs");
603839
+ if (existsSync106(jobsDir3)) {
602971
603840
  const cutoff = Date.now() - retentionDays * 864e5;
602972
603841
  for (const f2 of readdirSync36(jobsDir3)) {
602973
603842
  if (!f2.endsWith(".json")) continue;
602974
603843
  try {
602975
- const jobPath = join121(jobsDir3, f2);
602976
- const job = JSON.parse(readFileSync85(jobPath, "utf-8"));
603844
+ const jobPath = join122(jobsDir3, f2);
603845
+ const job = JSON.parse(readFileSync86(jobPath, "utf-8"));
602977
603846
  const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
602978
603847
  if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
602979
603848
  const { unlinkSync: unlinkSync25 } = require3("node:fs");
@@ -602993,8 +603862,8 @@ function startApiServer(options2 = {}) {
602993
603862
  if (useTls) {
602994
603863
  try {
602995
603864
  tlsOpts = {
602996
- cert: readFileSync85(resolve38(tlsCert)),
602997
- key: readFileSync85(resolve38(tlsKey))
603865
+ cert: readFileSync86(resolve38(tlsCert)),
603866
+ key: readFileSync86(resolve38(tlsKey))
602998
603867
  };
602999
603868
  } catch (e2) {
603000
603869
  log22(`
@@ -603005,9 +603874,9 @@ function startApiServer(options2 = {}) {
603005
603874
  }
603006
603875
  let runtimeAccessMode = resolveAccessMode(process.env["OA_ACCESS"], host);
603007
603876
  try {
603008
- const accessFile = join121(homedir42(), ".open-agents", "access");
603009
- if (existsSync105(accessFile)) {
603010
- const persisted = readFileSync85(accessFile, "utf8").trim();
603877
+ const accessFile = join122(homedir43(), ".open-agents", "access");
603878
+ if (existsSync106(accessFile)) {
603879
+ const persisted = readFileSync86(accessFile, "utf8").trim();
603011
603880
  const resolved = resolveAccessMode(persisted, host);
603012
603881
  if (resolved) runtimeAccessMode = resolved;
603013
603882
  }
@@ -603060,9 +603929,9 @@ function startApiServer(options2 = {}) {
603060
603929
  const previous = runtimeAccessMode;
603061
603930
  runtimeAccessMode = requested;
603062
603931
  try {
603063
- const dir = join121(homedir42(), ".open-agents");
603932
+ const dir = join122(homedir43(), ".open-agents");
603064
603933
  mkdirSync63(dir, { recursive: true });
603065
- writeFileSync55(join121(dir, "access"), `${runtimeAccessMode}
603934
+ writeFileSync55(join122(dir, "access"), `${runtimeAccessMode}
603066
603935
  `, "utf8");
603067
603936
  } catch {
603068
603937
  }
@@ -603275,9 +604144,9 @@ function startApiServer(options2 = {}) {
603275
604144
  try {
603276
604145
  const { startEmbeddingWorkers: startEmbeddingWorkers2 } = await Promise.resolve().then(() => (init_embedding_workers(), embedding_workers_exports));
603277
604146
  const { ensureEmbedDeps: ensureEmbedDeps2, runEmbedImage: runEmbedImage2, runEmbedAudio: runEmbedAudio2 } = await Promise.resolve().then(() => (init_py_embed(), py_embed_exports));
603278
- const dbBase = join121(cwd4, ".oa");
603279
- const epStore = new mem.EpisodeStore(join121(dbBase, "memory.db"));
603280
- const kg = new mem.TemporalGraph(join121(dbBase, "kg.db"));
604147
+ const dbBase = join122(cwd4, ".oa");
604148
+ const epStore = new mem.EpisodeStore(join122(dbBase, "memory.db"));
604149
+ const kg = new mem.TemporalGraph(join122(dbBase, "kg.db"));
603281
604150
  try {
603282
604151
  ensureEmbedDeps2();
603283
604152
  } catch {
@@ -603354,6 +604223,49 @@ function startApiServer(options2 = {}) {
603354
604223
  `);
603355
604224
  log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
603356
604225
  `);
604226
+ try {
604227
+ const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: _exists, readFileSync: _rfs } = require3("node:fs");
604228
+ const { join: _join } = require3("node:path");
604229
+ const { homedir: _homedir } = require3("node:os");
604230
+ const apiHint = JSON.stringify({
604231
+ port,
604232
+ host: host === "0.0.0.0" ? "127.0.0.1" : host,
604233
+ scheme: proto,
604234
+ pid: process.pid,
604235
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
604236
+ version: version4
604237
+ }, null, 2);
604238
+ const dirSet = /* @__PURE__ */ new Set();
604239
+ try {
604240
+ const regPath = _join(_homedir(), ".open-agents", "nexus-registry.json");
604241
+ if (_exists(regPath)) {
604242
+ const reg = JSON.parse(_rfs(regPath, "utf-8"));
604243
+ for (const e2 of reg?.dirs || []) {
604244
+ const d2 = typeof e2 === "string" ? e2 : e2?.dir;
604245
+ if (typeof d2 === "string") dirSet.add(d2);
604246
+ }
604247
+ }
604248
+ } catch {
604249
+ }
604250
+ if (process.env["OA_NEXUS_DIR"]) dirSet.add(process.env["OA_NEXUS_DIR"]);
604251
+ dirSet.add(_join(process.cwd(), ".oa", "nexus"));
604252
+ dirSet.add(_join(_homedir(), ".oa", "nexus"));
604253
+ dirSet.add(_join(_homedir(), ".open-agents", "nexus"));
604254
+ let written = 0;
604255
+ for (const dir of dirSet) {
604256
+ try {
604257
+ if (!_exists(dir)) mkdirSync67(dir, { recursive: true });
604258
+ writeFileSync59(_join(dir, "api-port.json"), apiHint);
604259
+ written++;
604260
+ } catch {
604261
+ }
604262
+ }
604263
+ if (written > 0) log22(` api-port hint: wrote to ${written} nexus dir(s)
604264
+ `);
604265
+ } catch (e2) {
604266
+ log22(` WARN: api-port hint write failed: ${e2.message}
604267
+ `);
604268
+ }
603357
604269
  try {
603358
604270
  adoptHandoffRuns();
603359
604271
  } catch (e2) {
@@ -603587,10 +604499,10 @@ async function handleMemoryIngest(req2, res, ollamaUrl) {
603587
604499
  const labels = Array.isArray(b.labels) ? b.labels : [];
603588
604500
  const mediaPath = typeof b.media_path === "string" ? b.media_path : void 0;
603589
604501
  const cwd4 = process.cwd();
603590
- const dbBase = join121(cwd4, ".oa");
604502
+ const dbBase = join122(cwd4, ".oa");
603591
604503
  const { EpisodeStore: EpisodeStore3, TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
603592
- const epStore = new EpisodeStore3(join121(dbBase, "memory.db"));
603593
- const kg = new TemporalGraph3(join121(dbBase, "kg.db"));
604504
+ const epStore = new EpisodeStore3(join122(dbBase, "memory.db"));
604505
+ const kg = new TemporalGraph3(join122(dbBase, "kg.db"));
603594
604506
  const meta = {};
603595
604507
  if (mediaPath) meta.media_path = mediaPath;
603596
604508
  const epId = epStore.insert({ modality, content: content || (mediaPath || ""), metadata: meta, toolName: "memory_ingest" });
@@ -603657,7 +604569,7 @@ async function handleEntitiesList(req2, res) {
603657
604569
  const type = url.searchParams.get("type") || "person";
603658
604570
  const limit = Math.max(1, Math.min(1e3, parseInt(url.searchParams.get("limit") || "100", 10)));
603659
604571
  const { TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
603660
- const kg = new TemporalGraph3(join121(process.cwd(), ".oa", "kg.db"));
604572
+ const kg = new TemporalGraph3(join122(process.cwd(), ".oa", "kg.db"));
603661
604573
  const nodes = kg.nodesByType(type, limit).map((n2) => ({ id: n2.id, text: n2.text, mentionCount: n2.mentionCount, firstSeen: n2.firstSeen, lastSeen: n2.lastSeen }));
603662
604574
  jsonResponse(res, 200, { object: "list", data: nodes });
603663
604575
  } catch (err) {
@@ -603679,7 +604591,7 @@ async function handleMemorySearch2(req2, res) {
603679
604591
  const wLex = typeof b.lexical_weight === "number" ? b.lexical_weight : 1;
603680
604592
  const wEmb = typeof b.embedding_weight === "number" ? b.embedding_weight : 1;
603681
604593
  const { EpisodeStore: EpisodeStore3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
603682
- const epStore = new EpisodeStore3(join121(process.cwd(), ".oa", "memory.db"));
604594
+ const epStore = new EpisodeStore3(join122(process.cwd(), ".oa", "memory.db"));
603683
604595
  const results = epStore.search({ query, modality, limit }, { queryEmbedding: qEmb, lexicalWeight: wLex, embeddingWeight: wEmb });
603684
604596
  jsonResponse(res, 200, { object: "list", data: results.map((e2) => ({ id: e2.id, modality: e2.modality, content: e2.content, timestamp: e2.timestamp })) });
603685
604597
  } catch (err) {
@@ -603796,13 +604708,13 @@ var init_serve = __esm({
603796
604708
 
603797
604709
  // packages/cli/src/tui/interactive.ts
603798
604710
  import { cwd } from "node:process";
603799
- import { resolve as resolve39, join as join122, dirname as dirname37, extname as extname12 } from "node:path";
604711
+ import { resolve as resolve39, join as join123, dirname as dirname37, extname as extname12 } from "node:path";
603800
604712
  import { createRequire as createRequire6 } from "node:module";
603801
604713
  import { fileURLToPath as fileURLToPath18 } from "node:url";
603802
- import { readFileSync as readFileSync86, writeFileSync as writeFileSync56, appendFileSync as appendFileSync8, rmSync as rmSync5, readdirSync as readdirSync37, mkdirSync as mkdirSync64 } from "node:fs";
603803
- import { existsSync as existsSync106 } from "node:fs";
604714
+ import { readFileSync as readFileSync87, writeFileSync as writeFileSync56, appendFileSync as appendFileSync8, rmSync as rmSync5, readdirSync as readdirSync37, mkdirSync as mkdirSync64 } from "node:fs";
604715
+ import { existsSync as existsSync107 } from "node:fs";
603804
604716
  import { execSync as execSync58 } from "node:child_process";
603805
- import { homedir as homedir43 } from "node:os";
604717
+ import { homedir as homedir44 } from "node:os";
603806
604718
  function formatTimeAgo2(date) {
603807
604719
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
603808
604720
  if (seconds < 60) return "just now";
@@ -603818,12 +604730,12 @@ function getVersion4() {
603818
604730
  const require4 = createRequire6(import.meta.url);
603819
604731
  const thisDir = dirname37(fileURLToPath18(import.meta.url));
603820
604732
  const candidates = [
603821
- join122(thisDir, "..", "package.json"),
603822
- join122(thisDir, "..", "..", "package.json"),
603823
- join122(thisDir, "..", "..", "..", "package.json")
604733
+ join123(thisDir, "..", "package.json"),
604734
+ join123(thisDir, "..", "..", "package.json"),
604735
+ join123(thisDir, "..", "..", "..", "package.json")
603824
604736
  ];
603825
604737
  for (const pkgPath of candidates) {
603826
- if (existsSync106(pkgPath)) {
604738
+ if (existsSync107(pkgPath)) {
603827
604739
  const pkg = require4(pkgPath);
603828
604740
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
603829
604741
  return pkg.version ?? "0.0.0";
@@ -604629,14 +605541,14 @@ Meta-critique: quality ${meta.quality}/5, thorough: ${meta.thorough}`;
604629
605541
  function gatherMemorySnippets(root) {
604630
605542
  const snippets = [];
604631
605543
  const dirs = [
604632
- join122(root, ".oa", "memory"),
604633
- join122(root, ".open-agents", "memory")
605544
+ join123(root, ".oa", "memory"),
605545
+ join123(root, ".open-agents", "memory")
604634
605546
  ];
604635
605547
  for (const dir of dirs) {
604636
- if (!existsSync106(dir)) continue;
605548
+ if (!existsSync107(dir)) continue;
604637
605549
  try {
604638
605550
  for (const f2 of readdirSync37(dir).filter((f3) => f3.endsWith(".json"))) {
604639
- const data = JSON.parse(readFileSync86(join122(dir, f2), "utf-8"));
605551
+ const data = JSON.parse(readFileSync87(join123(dir, f2), "utf-8"));
604640
605552
  for (const val of Object.values(data)) {
604641
605553
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
604642
605554
  if (v.length > 10) snippets.push(v);
@@ -604790,9 +605702,9 @@ ${metabolismMemories}
604790
605702
  } catch {
604791
605703
  }
604792
605704
  try {
604793
- const archeFile = join122(repoRoot, ".oa", "arche", "variants.json");
604794
- if (existsSync106(archeFile)) {
604795
- const variants = JSON.parse(readFileSync86(archeFile, "utf8"));
605705
+ const archeFile = join123(repoRoot, ".oa", "arche", "variants.json");
605706
+ if (existsSync107(archeFile)) {
605707
+ const variants = JSON.parse(readFileSync87(archeFile, "utf8"));
604796
605708
  if (variants.length > 0) {
604797
605709
  let filtered = variants;
604798
605710
  if (taskType) {
@@ -604964,9 +605876,9 @@ RULES:
604964
605876
  const compactionThreshold = Number.isFinite(envOverride) && envOverride > 0 ? envOverride : modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
604965
605877
  let identityInjection = "";
604966
605878
  try {
604967
- const ikStateFile = join122(repoRoot, ".oa", "identity", "self-state.json");
604968
- if (existsSync106(ikStateFile)) {
604969
- const selfState = JSON.parse(readFileSync86(ikStateFile, "utf8"));
605879
+ const ikStateFile = join123(repoRoot, ".oa", "identity", "self-state.json");
605880
+ if (existsSync107(ikStateFile)) {
605881
+ const selfState = JSON.parse(readFileSync87(ikStateFile, "utf8"));
604970
605882
  const lines = [
604971
605883
  `[Identity State v${selfState.version}]`,
604972
605884
  `Self: ${selfState.narrative_summary}`,
@@ -605828,11 +606740,11 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
605828
606740
  });
605829
606741
  }
605830
606742
  try {
605831
- const ikDir = join122(repoRoot, ".oa", "identity");
605832
- const ikFile = join122(ikDir, "self-state.json");
606743
+ const ikDir = join123(repoRoot, ".oa", "identity");
606744
+ const ikFile = join123(ikDir, "self-state.json");
605833
606745
  let ikState;
605834
- if (existsSync106(ikFile)) {
605835
- ikState = JSON.parse(readFileSync86(ikFile, "utf8"));
606746
+ if (existsSync107(ikFile)) {
606747
+ ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
605836
606748
  } else {
605837
606749
  mkdirSync64(ikDir, { recursive: true });
605838
606750
  const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
@@ -605909,9 +606821,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
605909
606821
  } else {
605910
606822
  renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
605911
606823
  try {
605912
- const ikFile = join122(repoRoot, ".oa", "identity", "self-state.json");
605913
- if (existsSync106(ikFile)) {
605914
- const ikState = JSON.parse(readFileSync86(ikFile, "utf8"));
606824
+ const ikFile = join123(repoRoot, ".oa", "identity", "self-state.json");
606825
+ if (existsSync107(ikFile)) {
606826
+ const ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
605915
606827
  if (!ikState.stats) ikState.stats = { queries_served: 0 };
605916
606828
  ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
605917
606829
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.03);
@@ -606167,10 +607079,10 @@ async function startInteractive(config, repoPath) {
606167
607079
  process.stdin.pause();
606168
607080
  }
606169
607081
  try {
606170
- const oaDir = join122(repoRoot, ".oa");
606171
- const nexusPidFile = join122(oaDir, "nexus", "daemon.pid");
606172
- if (existsSync106(nexusPidFile)) {
606173
- const pid = parseInt(readFileSync86(nexusPidFile, "utf8").trim(), 10);
607082
+ const oaDir = join123(repoRoot, ".oa");
607083
+ const nexusPidFile = join123(oaDir, "nexus", "daemon.pid");
607084
+ if (existsSync107(nexusPidFile)) {
607085
+ const pid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
606174
607086
  if (pid > 0) {
606175
607087
  try {
606176
607088
  process.kill(pid, 0);
@@ -606830,7 +607742,7 @@ ${result.summary}`
606830
607742
  let p2pGateway = null;
606831
607743
  let peerMesh = null;
606832
607744
  let inferenceRouter = null;
606833
- const secretVault = new SecretVault(join122(repoRoot, ".oa", "vault.enc"));
607745
+ const secretVault = new SecretVault(join123(repoRoot, ".oa", "vault.enc"));
606834
607746
  let adminSessionKey = null;
606835
607747
  const callSubAgents = /* @__PURE__ */ new Map();
606836
607748
  const streamRenderer = new StreamRenderer();
@@ -607061,13 +607973,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607061
607973
  const hits = allCompletions.filter((c9) => c9.toLowerCase().startsWith(lower));
607062
607974
  return [hits, line];
607063
607975
  }
607064
- const HISTORY_DIR = join122(homedir43(), ".open-agents");
607065
- const HISTORY_FILE = join122(HISTORY_DIR, "repl-history");
607976
+ const HISTORY_DIR = join123(homedir44(), ".open-agents");
607977
+ const HISTORY_FILE = join123(HISTORY_DIR, "repl-history");
607066
607978
  const MAX_HISTORY_LINES = 500;
607067
607979
  let savedHistory = [];
607068
607980
  try {
607069
- if (existsSync106(HISTORY_FILE)) {
607070
- const raw = readFileSync86(HISTORY_FILE, "utf8").trim();
607981
+ if (existsSync107(HISTORY_FILE)) {
607982
+ const raw = readFileSync87(HISTORY_FILE, "utf8").trim();
607071
607983
  if (raw) savedHistory = raw.split("\n").reverse();
607072
607984
  }
607073
607985
  } catch {
@@ -607217,7 +608129,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607217
608129
  mkdirSync64(HISTORY_DIR, { recursive: true });
607218
608130
  appendFileSync8(HISTORY_FILE, line + "\n", "utf8");
607219
608131
  if (Math.random() < 0.02) {
607220
- const all2 = readFileSync86(HISTORY_FILE, "utf8").trim().split("\n");
608132
+ const all2 = readFileSync87(HISTORY_FILE, "utf8").trim().split("\n");
607221
608133
  if (all2.length > MAX_HISTORY_LINES) {
607222
608134
  writeFileSync56(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
607223
608135
  }
@@ -607404,10 +608316,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607404
608316
  const { unlinkSync: _rmStale } = await import("node:fs");
607405
608317
  const { homedir: _hdir } = await import("node:os");
607406
608318
  for (const dp of [
607407
- join122(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
607408
- join122(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
608319
+ join123(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
608320
+ join123(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
607409
608321
  ]) {
607410
- if (existsSync106(dp)) try {
608322
+ if (existsSync107(dp)) try {
607411
608323
  _rmStale(dp);
607412
608324
  } catch {
607413
608325
  }
@@ -607418,9 +608330,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607418
608330
  const autoNexus = new NexusTool(repoRoot);
607419
608331
  const _registerNexusDaemon = () => {
607420
608332
  try {
607421
- const nexusPidFile = join122(repoRoot, ".oa", "nexus", "daemon.pid");
607422
- if (existsSync106(nexusPidFile)) {
607423
- const nPid = parseInt(readFileSync86(nexusPidFile, "utf8").trim(), 10);
608333
+ const nexusPidFile = join123(repoRoot, ".oa", "nexus", "daemon.pid");
608334
+ if (existsSync107(nexusPidFile)) {
608335
+ const nPid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
607424
608336
  if (nPid > 0 && !registry2.daemons.has("Nexus")) {
607425
608337
  registry2.register({ name: "Nexus", pid: nPid, startedAt: Date.now(), status: "running" });
607426
608338
  statusBar.ensureMonitorTimer();
@@ -607477,7 +608389,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607477
608389
  } catch {
607478
608390
  }
607479
608391
  try {
607480
- const oaDir = join122(repoRoot, ".oa");
608392
+ const oaDir = join123(repoRoot, ".oa");
607481
608393
  const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
607482
608394
  onInfo: (msg) => writeContent(() => renderInfo2(msg)),
607483
608395
  onError: (msg) => writeContent(() => renderWarning2(msg))
@@ -607509,7 +608421,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607509
608421
  } catch {
607510
608422
  }
607511
608423
  try {
607512
- const oaDir = join122(repoRoot, ".oa");
608424
+ const oaDir = join123(repoRoot, ".oa");
607513
608425
  const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
607514
608426
  onInfo: (msg) => writeContent(() => renderInfo2(msg)),
607515
608427
  onError: (msg) => writeContent(() => renderWarning2(msg))
@@ -607550,10 +608462,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607550
608462
  }
607551
608463
  try {
607552
608464
  const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
607553
- const globalNamePath = join122(_hd(), ".open-agents", "agent-name");
608465
+ const globalNamePath = join123(_hd(), ".open-agents", "agent-name");
607554
608466
  let agName = "";
607555
608467
  try {
607556
- if (existsSync106(globalNamePath)) agName = readFileSync86(globalNamePath, "utf8").trim();
608468
+ if (existsSync107(globalNamePath)) agName = readFileSync87(globalNamePath, "utf8").trim();
607557
608469
  } catch {
607558
608470
  }
607559
608471
  if (!agName) {
@@ -607582,11 +608494,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
607582
608494
  }
607583
608495
  if (!ollamaAlive) {
607584
608496
  try {
607585
- const savedSponsorsPath = join122(repoRoot, ".oa", "sponsor", "known-sponsors.json");
608497
+ const savedSponsorsPath = join123(repoRoot, ".oa", "sponsor", "known-sponsors.json");
607586
608498
  let savedSponsors = [];
607587
608499
  try {
607588
- if (existsSync106(savedSponsorsPath)) {
607589
- savedSponsors = JSON.parse(readFileSync86(savedSponsorsPath, "utf8"));
608500
+ if (existsSync107(savedSponsorsPath)) {
608501
+ savedSponsors = JSON.parse(readFileSync87(savedSponsorsPath, "utf8"));
607590
608502
  const oneHourAgo = Date.now() - 36e5;
607591
608503
  savedSponsors = savedSponsors.filter((s2) => (s2.lastVerified || 0) > oneHourAgo);
607592
608504
  }
@@ -608678,10 +609590,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
608678
609590
  if (name10 === "voice_list_files") {
608679
609591
  const baseDir = String(args?.dir ?? ".");
608680
609592
  const { readdirSync: readdirSync39, statSync: statSync36 } = __require("node:fs");
608681
- const { join: join127, resolve: resolve43 } = __require("node:path");
608682
- const base3 = baseDir.startsWith("/") ? baseDir : resolve43(join127(repoRoot, baseDir));
609593
+ const { join: join128, resolve: resolve43 } = __require("node:path");
609594
+ const base3 = baseDir.startsWith("/") ? baseDir : resolve43(join128(repoRoot, baseDir));
608683
609595
  const items = readdirSync39(base3).slice(0, 200).map((f2) => {
608684
- const s2 = statSync36(join127(base3, f2));
609596
+ const s2 = statSync36(join128(base3, f2));
608685
609597
  return { name: f2, dir: s2.isDirectory(), size: s2.size };
608686
609598
  });
608687
609599
  return JSON.stringify({ dir: base3, items }, null, 2);
@@ -608769,7 +609681,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
608769
609681
  kind,
608770
609682
  targetUrl,
608771
609683
  authKey,
608772
- stateDir: join122(repoRoot, ".oa"),
609684
+ stateDir: join123(repoRoot, ".oa"),
608773
609685
  passthrough: passthrough ?? false,
608774
609686
  loadbalance: loadbalance ?? false,
608775
609687
  endpointAuth: passthrough ? currentConfig.apiKey : void 0,
@@ -608815,7 +609727,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
608815
609727
  await tunnelGateway.stop();
608816
609728
  tunnelGateway = null;
608817
609729
  }
608818
- const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join122(repoRoot, ".oa") });
609730
+ const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join123(repoRoot, ".oa") });
608819
609731
  newTunnel.on("stats", (stats) => {
608820
609732
  statusBar.setExposeStatus({
608821
609733
  status: stats.status,
@@ -608902,9 +609814,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
608902
609814
  });
608903
609815
  if (!result.success) throw new Error(result.error || "Connect failed");
608904
609816
  try {
608905
- const nexusPidFile = join122(repoRoot, ".oa", "nexus", "daemon.pid");
608906
- if (existsSync106(nexusPidFile)) {
608907
- const pid = parseInt(readFileSync86(nexusPidFile, "utf8").trim(), 10);
609817
+ const nexusPidFile = join123(repoRoot, ".oa", "nexus", "daemon.pid");
609818
+ if (existsSync107(nexusPidFile)) {
609819
+ const pid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
608908
609820
  if (pid > 0) {
608909
609821
  registry2.register({
608910
609822
  name: "Nexus",
@@ -609092,10 +610004,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
609092
610004
  writeContent(() => renderInfo2(`Killed ${bgKilled} background task(s).`));
609093
610005
  }
609094
610006
  try {
609095
- const nexusDir = join122(repoRoot, OA_DIR, "nexus");
609096
- const pidFile = join122(nexusDir, "daemon.pid");
609097
- if (existsSync106(pidFile)) {
609098
- const pid = parseInt(readFileSync86(pidFile, "utf8").trim(), 10);
610007
+ const nexusDir = join123(repoRoot, OA_DIR, "nexus");
610008
+ const pidFile = join123(nexusDir, "daemon.pid");
610009
+ if (existsSync107(pidFile)) {
610010
+ const pid = parseInt(readFileSync87(pidFile, "utf8").trim(), 10);
609099
610011
  if (pid > 0) {
609100
610012
  try {
609101
610013
  if (process.platform === "win32") {
@@ -609117,13 +610029,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
609117
610029
  } catch {
609118
610030
  }
609119
610031
  try {
609120
- const voiceDir2 = join122(homedir43(), ".open-agents", "voice");
610032
+ const voiceDir2 = join123(homedir44(), ".open-agents", "voice");
609121
610033
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
609122
610034
  for (const pf of voicePidFiles) {
609123
- const pidPath = join122(voiceDir2, pf);
609124
- if (existsSync106(pidPath)) {
610035
+ const pidPath = join123(voiceDir2, pf);
610036
+ if (existsSync107(pidPath)) {
609125
610037
  try {
609126
- const pid = parseInt(readFileSync86(pidPath, "utf8").trim(), 10);
610038
+ const pid = parseInt(readFileSync87(pidPath, "utf8").trim(), 10);
609127
610039
  if (pid > 0) {
609128
610040
  if (process.platform === "win32") {
609129
610041
  try {
@@ -609147,8 +610059,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
609147
610059
  execSync58(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
609148
610060
  } catch {
609149
610061
  }
609150
- const oaPath = join122(repoRoot, OA_DIR);
609151
- if (existsSync106(oaPath)) {
610062
+ const oaPath = join123(repoRoot, OA_DIR);
610063
+ if (existsSync107(oaPath)) {
609152
610064
  let deleted = false;
609153
610065
  for (let attempt = 0; attempt < 3; attempt++) {
609154
610066
  try {
@@ -609232,19 +610144,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
609232
610144
  try {
609233
610145
  const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
609234
610146
  if (isPersonaPlexRunning2()) {
609235
- const ppPidFile = join122(homedir43(), ".open-agents", "voice", "personaplex", "daemon.pid");
609236
- const ppPortFile = join122(homedir43(), ".open-agents", "voice", "personaplex", "daemon.port");
609237
- if (existsSync106(ppPidFile)) {
609238
- const ppPid = parseInt(readFileSync86(ppPidFile, "utf8").trim(), 10);
609239
- const ppPort = existsSync106(ppPortFile) ? parseInt(readFileSync86(ppPortFile, "utf8").trim(), 10) : void 0;
610147
+ const ppPidFile = join123(homedir44(), ".open-agents", "voice", "personaplex", "daemon.pid");
610148
+ const ppPortFile = join123(homedir44(), ".open-agents", "voice", "personaplex", "daemon.port");
610149
+ if (existsSync107(ppPidFile)) {
610150
+ const ppPid = parseInt(readFileSync87(ppPidFile, "utf8").trim(), 10);
610151
+ const ppPort = existsSync107(ppPortFile) ? parseInt(readFileSync87(ppPortFile, "utf8").trim(), 10) : void 0;
609240
610152
  if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
609241
610153
  registry2.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
609242
610154
  }
609243
610155
  }
609244
610156
  }
609245
- const nexusPidFile = join122(repoRoot, ".oa", "nexus", "daemon.pid");
609246
- if (existsSync106(nexusPidFile)) {
609247
- const nPid = parseInt(readFileSync86(nexusPidFile, "utf8").trim(), 10);
610157
+ const nexusPidFile = join123(repoRoot, ".oa", "nexus", "daemon.pid");
610158
+ if (existsSync107(nexusPidFile)) {
610159
+ const nPid = parseInt(readFileSync87(nexusPidFile, "utf8").trim(), 10);
609248
610160
  if (nPid > 0 && !registry2.daemons.has("Nexus")) {
609249
610161
  try {
609250
610162
  process.kill(nPid, 0);
@@ -609611,9 +610523,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
609611
610523
  }
609612
610524
  }
609613
610525
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
609614
- const isImage = isImagePath(cleanPath) && existsSync106(resolve39(repoRoot, cleanPath));
609615
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync106(resolve39(repoRoot, cleanPath));
609616
- const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync106(resolve39(repoRoot, cleanPath));
610526
+ const isImage = isImagePath(cleanPath) && existsSync107(resolve39(repoRoot, cleanPath));
610527
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync107(resolve39(repoRoot, cleanPath));
610528
+ const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync107(resolve39(repoRoot, cleanPath));
609617
610529
  if (activeTask) {
609618
610530
  if (activeTask.runner.isPaused) {
609619
610531
  activeTask.runner.resume();
@@ -609622,7 +610534,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
609622
610534
  if (isImage) {
609623
610535
  try {
609624
610536
  const imgPath = resolve39(repoRoot, cleanPath);
609625
- const imgBuffer = readFileSync86(imgPath);
610537
+ const imgBuffer = readFileSync87(imgPath);
609626
610538
  const base642 = imgBuffer.toString("base64");
609627
610539
  const ext = extname12(cleanPath).toLowerCase();
609628
610540
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -609778,7 +610690,7 @@ ${result.text}`;
609778
610690
  if (isMarkdown && fullInput === input) {
609779
610691
  try {
609780
610692
  const mdPath = resolve39(repoRoot, cleanPath);
609781
- const mdContent = readFileSync86(mdPath, "utf8");
610693
+ const mdContent = readFileSync87(mdPath, "utf8");
609782
610694
  const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
609783
610695
  const result = parseMcpMarkdown2(mdContent);
609784
610696
  if (result.servers.length > 0) {
@@ -610200,11 +611112,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
610200
611112
  const handle2 = startTask(task, config, repoRoot);
610201
611113
  await handle2.promise;
610202
611114
  try {
610203
- const ikDir = join122(repoRoot, ".oa", "identity");
610204
- const ikFile = join122(ikDir, "self-state.json");
611115
+ const ikDir = join123(repoRoot, ".oa", "identity");
611116
+ const ikFile = join123(ikDir, "self-state.json");
610205
611117
  let ikState;
610206
- if (existsSync106(ikFile)) {
610207
- ikState = JSON.parse(readFileSync86(ikFile, "utf8"));
611118
+ if (existsSync107(ikFile)) {
611119
+ ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
610208
611120
  } else {
610209
611121
  mkdirSync64(ikDir, { recursive: true });
610210
611122
  ikState = {
@@ -610241,11 +611153,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
610241
611153
  );
610242
611154
  } catch {
610243
611155
  try {
610244
- const archeDir = join122(repoRoot, ".oa", "arche");
610245
- const archeFile = join122(archeDir, "variants.json");
611156
+ const archeDir = join123(repoRoot, ".oa", "arche");
611157
+ const archeFile = join123(archeDir, "variants.json");
610246
611158
  let variants = [];
610247
611159
  try {
610248
- if (existsSync106(archeFile)) variants = JSON.parse(readFileSync86(archeFile, "utf8"));
611160
+ if (existsSync107(archeFile)) variants = JSON.parse(readFileSync87(archeFile, "utf8"));
610249
611161
  } catch {
610250
611162
  }
610251
611163
  variants.push({
@@ -610265,9 +611177,9 @@ async function runWithTUI(task, config, repoPath, callbacks) {
610265
611177
  }
610266
611178
  }
610267
611179
  try {
610268
- const metaFile = join122(repoRoot, ".oa", "memory", "metabolism", "store.json");
610269
- if (existsSync106(metaFile)) {
610270
- const store2 = JSON.parse(readFileSync86(metaFile, "utf8"));
611180
+ const metaFile = join123(repoRoot, ".oa", "memory", "metabolism", "store.json");
611181
+ if (existsSync107(metaFile)) {
611182
+ const store2 = JSON.parse(readFileSync87(metaFile, "utf8"));
610271
611183
  const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
610272
611184
  let updated = false;
610273
611185
  for (const item of surfaced) {
@@ -610331,9 +611243,9 @@ Rules:
610331
611243
  try {
610332
611244
  const { initDb: initDb2 } = __require("@open-agents/memory");
610333
611245
  const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
610334
- const dbDir = join122(repoRoot, ".oa", "memory");
611246
+ const dbDir = join123(repoRoot, ".oa", "memory");
610335
611247
  mkdirSync64(dbDir, { recursive: true });
610336
- const db = initDb2(join122(dbDir, "structured.db"));
611248
+ const db = initDb2(join123(dbDir, "structured.db"));
610337
611249
  const memStore = new ProceduralMemoryStore2(db);
610338
611250
  memStore.createWithEmbedding({
610339
611251
  content: content.slice(0, 600),
@@ -610348,11 +611260,11 @@ Rules:
610348
611260
  db.close();
610349
611261
  } catch {
610350
611262
  }
610351
- const metaDir = join122(repoRoot, ".oa", "memory", "metabolism");
610352
- const storeFile = join122(metaDir, "store.json");
611263
+ const metaDir = join123(repoRoot, ".oa", "memory", "metabolism");
611264
+ const storeFile = join123(metaDir, "store.json");
610353
611265
  let store2 = [];
610354
611266
  try {
610355
- if (existsSync106(storeFile)) store2 = JSON.parse(readFileSync86(storeFile, "utf8"));
611267
+ if (existsSync107(storeFile)) store2 = JSON.parse(readFileSync87(storeFile, "utf8"));
610356
611268
  } catch {
610357
611269
  }
610358
611270
  store2.push({
@@ -610374,19 +611286,19 @@ Rules:
610374
611286
  } catch {
610375
611287
  }
610376
611288
  try {
610377
- const cohereSettingsFile = join122(repoRoot, ".oa", "settings.json");
611289
+ const cohereSettingsFile = join123(repoRoot, ".oa", "settings.json");
610378
611290
  let cohereActive = false;
610379
611291
  try {
610380
- if (existsSync106(cohereSettingsFile)) {
610381
- const settings = JSON.parse(readFileSync86(cohereSettingsFile, "utf8"));
611292
+ if (existsSync107(cohereSettingsFile)) {
611293
+ const settings = JSON.parse(readFileSync87(cohereSettingsFile, "utf8"));
610382
611294
  cohereActive = settings.cohere === true;
610383
611295
  }
610384
611296
  } catch {
610385
611297
  }
610386
611298
  if (cohereActive) {
610387
- const metaFile = join122(repoRoot, ".oa", "memory", "metabolism", "store.json");
610388
- if (existsSync106(metaFile)) {
610389
- const store2 = JSON.parse(readFileSync86(metaFile, "utf8"));
611299
+ const metaFile = join123(repoRoot, ".oa", "memory", "metabolism", "store.json");
611300
+ if (existsSync107(metaFile)) {
611301
+ const store2 = JSON.parse(readFileSync87(metaFile, "utf8"));
610390
611302
  const latest = store2.filter((m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
610391
611303
  if (latest && latest.scores?.confidence >= 0.6) {
610392
611304
  try {
@@ -610411,18 +611323,18 @@ Rules:
610411
611323
  }
610412
611324
  } catch (err) {
610413
611325
  try {
610414
- const ikFile = join122(repoRoot, ".oa", "identity", "self-state.json");
610415
- if (existsSync106(ikFile)) {
610416
- const ikState = JSON.parse(readFileSync86(ikFile, "utf8"));
611326
+ const ikFile = join123(repoRoot, ".oa", "identity", "self-state.json");
611327
+ if (existsSync107(ikFile)) {
611328
+ const ikState = JSON.parse(readFileSync87(ikFile, "utf8"));
610417
611329
  ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
610418
611330
  ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
610419
611331
  ikState.session_count = (ikState.session_count || 0) + 1;
610420
611332
  ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
610421
611333
  writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
610422
611334
  }
610423
- const metaFile = join122(repoRoot, ".oa", "memory", "metabolism", "store.json");
610424
- if (existsSync106(metaFile)) {
610425
- const store2 = JSON.parse(readFileSync86(metaFile, "utf8"));
611335
+ const metaFile = join123(repoRoot, ".oa", "memory", "metabolism", "store.json");
611336
+ if (existsSync107(metaFile)) {
611337
+ const store2 = JSON.parse(readFileSync87(metaFile, "utf8"));
610426
611338
  const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
610427
611339
  for (const item of surfaced) {
610428
611340
  item.accessCount = (item.accessCount || 0) + 1;
@@ -610433,11 +611345,11 @@ Rules:
610433
611345
  writeFileSync56(metaFile, JSON.stringify(store2, null, 2));
610434
611346
  }
610435
611347
  try {
610436
- const archeDir = join122(repoRoot, ".oa", "arche");
610437
- const archeFile = join122(archeDir, "variants.json");
611348
+ const archeDir = join123(repoRoot, ".oa", "arche");
611349
+ const archeFile = join123(archeDir, "variants.json");
610438
611350
  let variants = [];
610439
611351
  try {
610440
- if (existsSync106(archeFile)) variants = JSON.parse(readFileSync86(archeFile, "utf8"));
611352
+ if (existsSync107(archeFile)) variants = JSON.parse(readFileSync87(archeFile, "utf8"));
610441
611353
  } catch {
610442
611354
  }
610443
611355
  variants.push({
@@ -610541,12 +611453,12 @@ __export(run_exports, {
610541
611453
  });
610542
611454
  import { resolve as resolve40 } from "node:path";
610543
611455
  import { spawn as spawn26 } from "node:child_process";
610544
- import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57, readFileSync as readFileSync87, readdirSync as readdirSync38, existsSync as existsSync107 } from "node:fs";
611456
+ import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57, readFileSync as readFileSync88, readdirSync as readdirSync38, existsSync as existsSync108 } from "node:fs";
610545
611457
  import { randomBytes as randomBytes24 } from "node:crypto";
610546
- import { join as join123 } from "node:path";
611458
+ import { join as join124 } from "node:path";
610547
611459
  function jobsDir2(repoPath) {
610548
611460
  const root = resolve40(repoPath ?? process.cwd());
610549
- const dir = join123(root, ".oa", "jobs");
611461
+ const dir = join124(root, ".oa", "jobs");
610550
611462
  mkdirSync65(dir, { recursive: true });
610551
611463
  return dir;
610552
611464
  }
@@ -610669,7 +611581,7 @@ async function runBackground(task, config, opts) {
610669
611581
  }
610670
611582
  });
610671
611583
  job.pid = child.pid ?? 0;
610672
- writeFileSync57(join123(dir, `${id}.json`), JSON.stringify(job, null, 2));
611584
+ writeFileSync57(join124(dir, `${id}.json`), JSON.stringify(job, null, 2));
610673
611585
  let output = "";
610674
611586
  child.stdout?.on("data", (chunk) => {
610675
611587
  output += chunk.toString();
@@ -610685,7 +611597,7 @@ async function runBackground(task, config, opts) {
610685
611597
  job.summary = result.summary;
610686
611598
  job.durationMs = result.durationMs;
610687
611599
  job.error = result.error;
610688
- writeFileSync57(join123(dir, `${id}.json`), JSON.stringify(job, null, 2));
611600
+ writeFileSync57(join124(dir, `${id}.json`), JSON.stringify(job, null, 2));
610689
611601
  } catch {
610690
611602
  }
610691
611603
  });
@@ -610701,13 +611613,13 @@ async function runBackground(task, config, opts) {
610701
611613
  }
610702
611614
  function statusCommand(jobId, repoPath) {
610703
611615
  const dir = jobsDir2(repoPath);
610704
- const file = join123(dir, `${jobId}.json`);
610705
- if (!existsSync107(file)) {
611616
+ const file = join124(dir, `${jobId}.json`);
611617
+ if (!existsSync108(file)) {
610706
611618
  console.error(`Job not found: ${jobId}`);
610707
611619
  console.log(`Available jobs: oa jobs`);
610708
611620
  process.exit(1);
610709
611621
  }
610710
- const job = JSON.parse(readFileSync87(file, "utf-8"));
611622
+ const job = JSON.parse(readFileSync88(file, "utf-8"));
610711
611623
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
610712
611624
  const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
610713
611625
  console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
@@ -610728,7 +611640,7 @@ function jobsCommand(repoPath) {
610728
611640
  console.log("Jobs:");
610729
611641
  for (const file of files) {
610730
611642
  try {
610731
- const job = JSON.parse(readFileSync87(join123(dir, file), "utf-8"));
611643
+ const job = JSON.parse(readFileSync88(join124(dir, file), "utf-8"));
610732
611644
  const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
610733
611645
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
610734
611646
  const cleanListTask = cleanForStorage(job.task) || job.task;
@@ -610752,13 +611664,13 @@ __export(index_repo_exports, {
610752
611664
  indexRepoCommand: () => indexRepoCommand
610753
611665
  });
610754
611666
  import { resolve as resolve41 } from "node:path";
610755
- import { existsSync as existsSync108, statSync as statSync35 } from "node:fs";
611667
+ import { existsSync as existsSync109, statSync as statSync35 } from "node:fs";
610756
611668
  import { cwd as cwd2 } from "node:process";
610757
611669
  async function indexRepoCommand(opts, _config3) {
610758
611670
  const repoRoot = resolve41(opts.repoPath ?? cwd2());
610759
611671
  printHeader("Index Repository");
610760
611672
  printInfo(`Indexing: ${repoRoot}`);
610761
- if (!existsSync108(repoRoot)) {
611673
+ if (!existsSync109(repoRoot)) {
610762
611674
  printError(`Path does not exist: ${repoRoot}`);
610763
611675
  process.exit(1);
610764
611676
  }
@@ -611010,8 +611922,8 @@ var config_exports2 = {};
611010
611922
  __export(config_exports2, {
611011
611923
  configCommand: () => configCommand
611012
611924
  });
611013
- import { join as join124, resolve as resolve42 } from "node:path";
611014
- import { homedir as homedir44 } from "node:os";
611925
+ import { join as join125, resolve as resolve42 } from "node:path";
611926
+ import { homedir as homedir45 } from "node:os";
611015
611927
  import { cwd as cwd3 } from "node:process";
611016
611928
  function redactIfSensitive(key, value2) {
611017
611929
  if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
@@ -611092,7 +612004,7 @@ function handleShow(opts, config) {
611092
612004
  }
611093
612005
  }
611094
612006
  printSection("Config File");
611095
- printInfo(`~/.open-agents/config.json (${join124(homedir44(), ".open-agents", "config.json")})`);
612007
+ printInfo(`~/.open-agents/config.json (${join125(homedir45(), ".open-agents", "config.json")})`);
611096
612008
  printSection("Priority Chain");
611097
612009
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
611098
612010
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -611131,7 +612043,7 @@ function handleSet(opts, _config3) {
611131
612043
  const coerced = coerceForSettings(key, value2);
611132
612044
  saveProjectSettings(repoRoot, { [key]: coerced });
611133
612045
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value2)}`);
611134
- printInfo(`Saved to ${join124(repoRoot, ".oa", "settings.json")}`);
612046
+ printInfo(`Saved to ${join125(repoRoot, ".oa", "settings.json")}`);
611135
612047
  printInfo("This override applies only when running in this workspace.");
611136
612048
  } catch (err) {
611137
612049
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -611316,7 +612228,7 @@ __export(eval_exports, {
611316
612228
  });
611317
612229
  import { tmpdir as tmpdir21 } from "node:os";
611318
612230
  import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync58 } from "node:fs";
611319
- import { join as join125 } from "node:path";
612231
+ import { join as join126 } from "node:path";
611320
612232
  async function evalCommand(opts, config) {
611321
612233
  const suiteName = opts.suite ?? "basic";
611322
612234
  const suite = SUITES[suiteName];
@@ -611445,10 +612357,10 @@ async function evalCommand(opts, config) {
611445
612357
  process.exit(failed > 0 ? 1 : 0);
611446
612358
  }
611447
612359
  function createTempEvalRepo() {
611448
- const dir = join125(tmpdir21(), `open-agents-eval-${Date.now()}`);
612360
+ const dir = join126(tmpdir21(), `open-agents-eval-${Date.now()}`);
611449
612361
  mkdirSync66(dir, { recursive: true });
611450
612362
  writeFileSync58(
611451
- join125(dir, "package.json"),
612363
+ join126(dir, "package.json"),
611452
612364
  JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n",
611453
612365
  "utf8"
611454
612366
  );
@@ -611512,7 +612424,7 @@ init_typed_node_events();
611512
612424
  import { parseArgs as nodeParseArgs2 } from "node:util";
611513
612425
  import { createRequire as createRequire7 } from "node:module";
611514
612426
  import { fileURLToPath as fileURLToPath19 } from "node:url";
611515
- import { dirname as dirname38, join as join126 } from "node:path";
612427
+ import { dirname as dirname38, join as join127 } from "node:path";
611516
612428
 
611517
612429
  // packages/cli/src/cli.ts
611518
612430
  init_typed_node_events();
@@ -611652,7 +612564,7 @@ init_output();
611652
612564
  function getVersion5() {
611653
612565
  try {
611654
612566
  const require4 = createRequire7(import.meta.url);
611655
- const pkgPath = join126(dirname38(fileURLToPath19(import.meta.url)), "..", "package.json");
612567
+ const pkgPath = join127(dirname38(fileURLToPath19(import.meta.url)), "..", "package.json");
611656
612568
  const pkg = require4(pkgPath);
611657
612569
  return pkg.version;
611658
612570
  } catch {
@@ -611967,11 +612879,11 @@ function crashLog(label, err) {
611967
612879
  `;
611968
612880
  try {
611969
612881
  const { appendFileSync: appendFileSync9, mkdirSync: mkdirSync67 } = __require("node:fs");
611970
- const { join: join127 } = __require("node:path");
611971
- const { homedir: homedir45 } = __require("node:os");
611972
- const logDir = join127(homedir45(), ".open-agents");
612882
+ const { join: join128 } = __require("node:path");
612883
+ const { homedir: homedir46 } = __require("node:os");
612884
+ const logDir = join128(homedir46(), ".open-agents");
611973
612885
  mkdirSync67(logDir, { recursive: true });
611974
- appendFileSync9(join127(logDir, "crash.log"), logLine);
612886
+ appendFileSync9(join128(logDir, "crash.log"), logLine);
611975
612887
  } catch {
611976
612888
  }
611977
612889
  try {