open-agents-ai 0.105.6 → 0.106.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +969 -544
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5639,8 +5639,8 @@ function deleteCustomToolDefinition(name, scope, repoRoot) {
5639
5639
  const dir = scope === "project" && repoRoot ? projectToolsDir(repoRoot) : globalToolsDir();
5640
5640
  const filePath = join13(dir, `${name}.json`);
5641
5641
  if (existsSync10(filePath)) {
5642
- const { unlinkSync: unlinkSync10 } = __require("node:fs");
5643
- unlinkSync10(filePath);
5642
+ const { unlinkSync: unlinkSync11 } = __require("node:fs");
5643
+ unlinkSync11(filePath);
5644
5644
  return true;
5645
5645
  }
5646
5646
  return false;
@@ -7511,6 +7511,315 @@ ${result.filesCreated.join("\n")}`);
7511
7511
  }
7512
7512
  });
7513
7513
 
7514
+ // packages/execution/dist/tools/repl.js
7515
+ import { spawn as spawn6 } from "node:child_process";
7516
+ import { createServer } from "node:net";
7517
+ import { join as join18 } from "node:path";
7518
+ import { tmpdir as tmpdir3 } from "node:os";
7519
+ import { randomBytes as randomBytes2 } from "node:crypto";
7520
+ import { unlinkSync as unlinkSync2 } from "node:fs";
7521
+ var ReplTool;
7522
+ var init_repl = __esm({
7523
+ "packages/execution/dist/tools/repl.js"() {
7524
+ "use strict";
7525
+ ReplTool = class {
7526
+ name = "repl_exec";
7527
+ description = "Execute Python code in a persistent REPL environment. Variables, imports, and functions persist between calls within the same task. Use for data processing, analysis, and building up results across multiple steps. A special function llm_query(prompt, context='') is available to invoke the language model from within Python code for semantic analysis of text chunks. Write results to files or print them to see output.";
7528
+ parameters = {
7529
+ type: "object",
7530
+ properties: {
7531
+ code: {
7532
+ type: "string",
7533
+ description: "Python code to execute in the persistent REPL"
7534
+ },
7535
+ reset: {
7536
+ type: "boolean",
7537
+ description: "Reset the REPL state (kill process, clear all variables). Default: false"
7538
+ }
7539
+ },
7540
+ required: ["code"]
7541
+ };
7542
+ proc = null;
7543
+ ipcServer = null;
7544
+ ipcPath = null;
7545
+ cwd;
7546
+ llmQueryHandler = null;
7547
+ subCallCount = 0;
7548
+ maxSubCalls;
7549
+ execTimeout;
7550
+ constructor(cwd4, options) {
7551
+ this.cwd = cwd4;
7552
+ this.llmQueryHandler = options?.llmQueryHandler ?? null;
7553
+ this.maxSubCalls = options?.maxSubCalls ?? 50;
7554
+ this.execTimeout = options?.execTimeout ?? 6e4;
7555
+ }
7556
+ /** Set the llm_query handler (called after construction when backend is available) */
7557
+ setLlmQueryHandler(handler) {
7558
+ this.llmQueryHandler = handler;
7559
+ }
7560
+ /** Get the number of sub-calls made this session */
7561
+ getSubCallCount() {
7562
+ return this.subCallCount;
7563
+ }
7564
+ async execute(args) {
7565
+ const code = String(args.code ?? "");
7566
+ const reset = Boolean(args.reset);
7567
+ if (reset) {
7568
+ await this.dispose();
7569
+ return { success: true, output: "REPL state cleared.", durationMs: 0 };
7570
+ }
7571
+ if (!code.trim()) {
7572
+ return { success: false, output: "No code provided.", error: "Empty code", durationMs: 0 };
7573
+ }
7574
+ const start = performance.now();
7575
+ try {
7576
+ if (!this.proc || this.proc.killed || this.proc.exitCode !== null) {
7577
+ await this.startProcess();
7578
+ }
7579
+ const result = await this.executeCode(code);
7580
+ return { ...result, durationMs: performance.now() - start };
7581
+ } catch (err) {
7582
+ const msg = err instanceof Error ? err.message : String(err);
7583
+ return { success: false, output: `REPL error: ${msg}`, error: msg, durationMs: performance.now() - start };
7584
+ }
7585
+ }
7586
+ // ── Process lifecycle ────────────────────────────────────────────────────
7587
+ async startProcess() {
7588
+ await this.startIpcServer();
7589
+ this.proc = spawn6("python3", ["-u", "-i", "-q"], {
7590
+ cwd: this.cwd,
7591
+ stdio: ["pipe", "pipe", "pipe"],
7592
+ env: {
7593
+ ...process.env,
7594
+ PYTHONUNBUFFERED: "1",
7595
+ PYTHONDONTWRITEBYTECODE: "1",
7596
+ OA_LLM_QUERY_SOCKET: this.ipcPath ?? ""
7597
+ }
7598
+ });
7599
+ this.proc.on("error", () => {
7600
+ });
7601
+ const initCode = this.buildInitCode();
7602
+ await this.executeCode(initCode, true);
7603
+ }
7604
+ buildInitCode() {
7605
+ return `
7606
+ import sys, os, json, socket
7607
+
7608
+ def llm_query(prompt, context=""):
7609
+ """Invoke the language model on a sub-prompt. Returns the model's text response.
7610
+ Use for semantic analysis, summarization, or reasoning about text chunks.
7611
+ Args:
7612
+ prompt: The question/instruction for the model
7613
+ context: Additional text context (max ~500K chars)
7614
+ Returns: Model's text response as a string
7615
+ """
7616
+ sock_path = os.environ.get("OA_LLM_QUERY_SOCKET", "")
7617
+ if not sock_path:
7618
+ return "[llm_query unavailable: no IPC socket]"
7619
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
7620
+ try:
7621
+ sock.connect(sock_path)
7622
+ request = json.dumps({"prompt": str(prompt), "context": str(context)[:500000]})
7623
+ # Send length-prefixed message
7624
+ data = request.encode("utf-8")
7625
+ sock.sendall(len(data).to_bytes(4, "big") + data)
7626
+ # Read length-prefixed response
7627
+ length_bytes = b""
7628
+ while len(length_bytes) < 4:
7629
+ chunk = sock.recv(4 - len(length_bytes))
7630
+ if not chunk:
7631
+ return "[llm_query: connection closed]"
7632
+ length_bytes += chunk
7633
+ resp_len = int.from_bytes(length_bytes, "big")
7634
+ resp_data = b""
7635
+ while len(resp_data) < resp_len:
7636
+ chunk = sock.recv(min(resp_len - len(resp_data), 65536))
7637
+ if not chunk:
7638
+ break
7639
+ resp_data += chunk
7640
+ result = json.loads(resp_data.decode("utf-8"))
7641
+ if "error" in result:
7642
+ return f"[llm_query error: {result['error']}]"
7643
+ return result.get("response", "")
7644
+ except Exception as e:
7645
+ return f"[llm_query error: {e}]"
7646
+ finally:
7647
+ sock.close()
7648
+
7649
+ # Signal REPL ready
7650
+ print("__OA_REPL_READY__")
7651
+ `.trim();
7652
+ }
7653
+ // ── IPC Server (for llm_query bridge) ──────────────────────────────────
7654
+ async startIpcServer() {
7655
+ if (this.ipcServer)
7656
+ return;
7657
+ const sockId = randomBytes2(8).toString("hex");
7658
+ this.ipcPath = join18(tmpdir3(), `oa-repl-ipc-${sockId}.sock`);
7659
+ return new Promise((resolve32, reject) => {
7660
+ this.ipcServer = createServer((conn) => {
7661
+ let buffer = new Uint8Array(0);
7662
+ conn.on("data", (chunk) => {
7663
+ const combined = new Uint8Array(buffer.length + chunk.length);
7664
+ combined.set(buffer, 0);
7665
+ combined.set(chunk, buffer.length);
7666
+ buffer = combined;
7667
+ this.processIpcBuffer(conn, buffer).then((remaining) => {
7668
+ buffer = remaining;
7669
+ });
7670
+ });
7671
+ conn.on("error", () => {
7672
+ });
7673
+ });
7674
+ this.ipcServer.on("error", reject);
7675
+ this.ipcServer.listen(this.ipcPath, () => resolve32());
7676
+ });
7677
+ }
7678
+ async processIpcBuffer(conn, input) {
7679
+ let buffer = input;
7680
+ while (buffer.length >= 4) {
7681
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
7682
+ const msgLen = view.getUint32(0, false);
7683
+ if (buffer.length < 4 + msgLen)
7684
+ break;
7685
+ const msgData = new TextDecoder().decode(buffer.subarray(4, 4 + msgLen));
7686
+ buffer = buffer.subarray(4 + msgLen);
7687
+ let response;
7688
+ try {
7689
+ const req = JSON.parse(msgData);
7690
+ if (!this.llmQueryHandler) {
7691
+ response = { error: "llm_query handler not configured" };
7692
+ } else if (this.subCallCount >= this.maxSubCalls) {
7693
+ response = { error: `Sub-call limit reached (${this.maxSubCalls})` };
7694
+ } else {
7695
+ this.subCallCount++;
7696
+ const result = await this.llmQueryHandler(req.prompt, req.context);
7697
+ response = { response: result };
7698
+ }
7699
+ } catch (err) {
7700
+ response = { error: err instanceof Error ? err.message : String(err) };
7701
+ }
7702
+ const respBytes = new TextEncoder().encode(JSON.stringify(response));
7703
+ const header = new Uint8Array(4);
7704
+ new DataView(header.buffer).setUint32(0, respBytes.length, false);
7705
+ const packet = new Uint8Array(4 + respBytes.length);
7706
+ packet.set(header, 0);
7707
+ packet.set(respBytes, 4);
7708
+ try {
7709
+ conn.write(packet);
7710
+ } catch {
7711
+ }
7712
+ }
7713
+ return buffer;
7714
+ }
7715
+ // ── Code execution ─────────────────────────────────────────────────────
7716
+ executeCode(code, isInit = false) {
7717
+ return new Promise((resolve32) => {
7718
+ if (!this.proc?.stdin || !this.proc?.stdout || !this.proc?.stderr) {
7719
+ resolve32({ success: false, output: "REPL process not available", error: "No process", durationMs: 0 });
7720
+ return;
7721
+ }
7722
+ const sentinel = `__OA_SENTINEL_${randomBytes2(6).toString("hex")}__`;
7723
+ let stdout = "";
7724
+ let stderr = "";
7725
+ let resolved = false;
7726
+ const timeout = setTimeout(() => {
7727
+ if (!resolved) {
7728
+ resolved = true;
7729
+ resolve32({
7730
+ success: false,
7731
+ output: stdout || "Execution timed out",
7732
+ error: `Timeout after ${this.execTimeout / 1e3}s`,
7733
+ durationMs: this.execTimeout
7734
+ });
7735
+ }
7736
+ }, this.execTimeout);
7737
+ const onStdout = (data) => {
7738
+ const text = data.toString();
7739
+ stdout += text;
7740
+ if (stdout.includes(sentinel)) {
7741
+ cleanup();
7742
+ const cleanOutput = stdout.split(sentinel)[0].trim();
7743
+ if (isInit) {
7744
+ const ready = cleanOutput.includes("__OA_REPL_READY__");
7745
+ const displayOutput = cleanOutput.replace("__OA_REPL_READY__", "").trim();
7746
+ resolve32({
7747
+ success: ready,
7748
+ output: displayOutput || "REPL initialized",
7749
+ durationMs: 0
7750
+ });
7751
+ } else {
7752
+ resolve32({
7753
+ success: true,
7754
+ output: cleanOutput || "(no output)",
7755
+ durationMs: 0
7756
+ });
7757
+ }
7758
+ }
7759
+ if (stdout.length > 2e5) {
7760
+ cleanup();
7761
+ resolve32({
7762
+ success: true,
7763
+ output: stdout.slice(0, 2e5) + "\n[output truncated at 200KB]",
7764
+ durationMs: 0
7765
+ });
7766
+ }
7767
+ };
7768
+ const onStderr = (data) => {
7769
+ stderr += data.toString();
7770
+ if (stderr.length > 5e4) {
7771
+ stderr = stderr.slice(0, 5e4) + "\n[stderr truncated]";
7772
+ }
7773
+ };
7774
+ const cleanup = () => {
7775
+ if (resolved)
7776
+ return;
7777
+ resolved = true;
7778
+ clearTimeout(timeout);
7779
+ this.proc?.stdout?.removeListener("data", onStdout);
7780
+ this.proc?.stderr?.removeListener("data", onStderr);
7781
+ };
7782
+ this.proc.stdout.on("data", onStdout);
7783
+ this.proc.stderr.on("data", onStderr);
7784
+ const wrappedCode = `
7785
+ try:
7786
+ exec(${JSON.stringify(code)})
7787
+ except Exception as __oa_e:
7788
+ import traceback as __oa_tb
7789
+ print(f"Error: {__oa_e}")
7790
+ __oa_tb.print_exc()
7791
+ print("${sentinel}")
7792
+ `;
7793
+ this.proc.stdin.write(wrappedCode + "\n");
7794
+ });
7795
+ }
7796
+ // ── Cleanup ────────────────────────────────────────────────────────────
7797
+ async dispose() {
7798
+ if (this.proc && !this.proc.killed) {
7799
+ try {
7800
+ this.proc.stdin?.end();
7801
+ this.proc.kill("SIGTERM");
7802
+ } catch {
7803
+ }
7804
+ this.proc = null;
7805
+ }
7806
+ if (this.ipcServer) {
7807
+ this.ipcServer.close();
7808
+ this.ipcServer = null;
7809
+ }
7810
+ if (this.ipcPath) {
7811
+ try {
7812
+ unlinkSync2(this.ipcPath);
7813
+ } catch {
7814
+ }
7815
+ this.ipcPath = null;
7816
+ }
7817
+ this.subCallCount = 0;
7818
+ }
7819
+ };
7820
+ }
7821
+ });
7822
+
7514
7823
  // packages/execution/dist/tools/structured-read.js
7515
7824
  import { readFile as readFile8, stat as stat2 } from "node:fs/promises";
7516
7825
  import { resolve as resolve15, extname as extname5 } from "node:path";
@@ -7848,8 +8157,8 @@ ${parts.join("\n\n")}`,
7848
8157
 
7849
8158
  // packages/execution/dist/tools/vision.js
7850
8159
  import { readFileSync as readFileSync11, existsSync as existsSync14, statSync as statSync5 } from "node:fs";
7851
- import { execSync as execSync11, spawn as spawn6 } from "node:child_process";
7852
- import { resolve as resolve16, extname as extname6, basename as basename5, dirname as dirname6, join as join18 } from "node:path";
8160
+ import { execSync as execSync11, spawn as spawn7 } from "node:child_process";
8161
+ import { resolve as resolve16, extname as extname6, basename as basename5, dirname as dirname6, join as join19 } from "node:path";
7853
8162
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7854
8163
  async function probeStation(endpoint) {
7855
8164
  try {
@@ -7864,7 +8173,7 @@ async function probeStation(endpoint) {
7864
8173
  }
7865
8174
  }
7866
8175
  function findStationBinary() {
7867
- const oaVenvPython = join18(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "python");
8176
+ const oaVenvPython = join19(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "python");
7868
8177
  if (existsSync14(oaVenvPython)) {
7869
8178
  try {
7870
8179
  execSync11(`${JSON.stringify(oaVenvPython)} -c "import moondream_station"`, { stdio: "pipe", timeout: 5e3 });
@@ -7872,7 +8181,7 @@ function findStationBinary() {
7872
8181
  } catch {
7873
8182
  }
7874
8183
  }
7875
- const oaVenvBin = join18(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "moondream-station");
8184
+ const oaVenvBin = join19(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "moondream-station");
7876
8185
  if (existsSync14(oaVenvBin))
7877
8186
  return oaVenvBin;
7878
8187
  const thisDir = dirname6(fileURLToPath2(import.meta.url));
@@ -7906,7 +8215,7 @@ async function autoLaunchStation(port = 2020) {
7906
8215
  if (!existsSync14(launcherScript))
7907
8216
  return false;
7908
8217
  return new Promise((resolvePromise) => {
7909
- const child = spawn6(pythonBin, [launcherScript, "--port", String(port)], {
8218
+ const child = spawn7(pythonBin, [launcherScript, "--port", String(port)], {
7910
8219
  stdio: ["ignore", "pipe", "pipe"],
7911
8220
  detached: true
7912
8221
  });
@@ -8223,8 +8532,8 @@ ${response}`, durationMs: performance.now() - start };
8223
8532
  // packages/execution/dist/tools/desktop-click.js
8224
8533
  import { readFileSync as readFileSync12, existsSync as existsSync15 } from "node:fs";
8225
8534
  import { execSync as execSync12 } from "node:child_process";
8226
- import { tmpdir as tmpdir3 } from "node:os";
8227
- import { join as join19, dirname as dirname7 } from "node:path";
8535
+ import { tmpdir as tmpdir4 } from "node:os";
8536
+ import { join as join20, dirname as dirname7 } from "node:path";
8228
8537
  import { fileURLToPath as fileURLToPath3 } from "node:url";
8229
8538
  function hasCommand2(cmd) {
8230
8539
  try {
@@ -8348,7 +8657,7 @@ for i in range(${clicks}):
8348
8657
  } catch {
8349
8658
  }
8350
8659
  try {
8351
- const venvPy = join19(__dirname2, "../../../../.moondream-venv/bin/python");
8660
+ const venvPy = join20(__dirname2, "../../../../.moondream-venv/bin/python");
8352
8661
  execSync12(`DISPLAY=:0 ${JSON.stringify(venvPy)} -c "${pyScript}"`, { stdio: "pipe", timeout: 5e3 });
8353
8662
  return;
8354
8663
  } catch {
@@ -8440,7 +8749,7 @@ var init_desktop_click = __esm({
8440
8749
  if (delayMs > 0) {
8441
8750
  await new Promise((r) => setTimeout(r, delayMs));
8442
8751
  }
8443
- const screenshotPath = join19(tmpdir3(), `oa-desktop-click-${Date.now()}.png`);
8752
+ const screenshotPath = join20(tmpdir4(), `oa-desktop-click-${Date.now()}.png`);
8444
8753
  captureScreenshot(screenshotPath);
8445
8754
  const dims = getImageDimensions2(screenshotPath);
8446
8755
  if (!dims) {
@@ -8615,7 +8924,7 @@ Screenshot: ${screenshotPath}`,
8615
8924
  if (delayMs > 0) {
8616
8925
  await new Promise((r) => setTimeout(r, delayMs));
8617
8926
  }
8618
- const screenshotPath = join19(tmpdir3(), `oa-desktop-describe-${Date.now()}.png`);
8927
+ const screenshotPath = join20(tmpdir4(), `oa-desktop-describe-${Date.now()}.png`);
8619
8928
  captureScreenshot(screenshotPath);
8620
8929
  const dims = getImageDimensions2(screenshotPath);
8621
8930
  const imageBuffer = readFileSync12(screenshotPath);
@@ -8853,10 +9162,10 @@ Language: ${language}
8853
9162
  });
8854
9163
 
8855
9164
  // packages/execution/dist/tools/pdf-to-text.js
8856
- import { existsSync as existsSync17, statSync as statSync7, readFileSync as readFileSync13, unlinkSync as unlinkSync2 } from "node:fs";
8857
- import { resolve as resolve18, basename as basename7, join as join20 } from "node:path";
9165
+ import { existsSync as existsSync17, statSync as statSync7, readFileSync as readFileSync13, unlinkSync as unlinkSync3 } from "node:fs";
9166
+ import { resolve as resolve18, basename as basename7, join as join21 } from "node:path";
8858
9167
  import { execSync as execSync14 } from "node:child_process";
8859
- import { tmpdir as tmpdir4 } from "node:os";
9168
+ import { tmpdir as tmpdir5 } from "node:os";
8860
9169
  var PdfToTextTool;
8861
9170
  var init_pdf_to_text = __esm({
8862
9171
  "packages/execution/dist/tools/pdf-to-text.js"() {
@@ -9008,7 +9317,7 @@ ${text}`,
9008
9317
  if (!ocrCheck.available || !tesCheck.available || !gsCheck.available) {
9009
9318
  return null;
9010
9319
  }
9011
- const tmpPdf = join20(tmpdir4(), `oa-ocr-${Date.now()}.pdf`);
9320
+ const tmpPdf = join21(tmpdir5(), `oa-ocr-${Date.now()}.pdf`);
9012
9321
  try {
9013
9322
  const ocrCmd = `ocrmypdf -l ${language} --skip-text ${JSON.stringify(inputPath)} ${JSON.stringify(tmpPdf)}`;
9014
9323
  execSync14(ocrCmd, { stdio: "pipe", timeout: 6e5 });
@@ -9028,7 +9337,7 @@ ${text}`,
9028
9337
  return null;
9029
9338
  } finally {
9030
9339
  try {
9031
- unlinkSync2(tmpPdf);
9340
+ unlinkSync3(tmpPdf);
9032
9341
  } catch {
9033
9342
  }
9034
9343
  }
@@ -9039,10 +9348,10 @@ ${text}`,
9039
9348
 
9040
9349
  // packages/execution/dist/tools/ocr-image-advanced.js
9041
9350
  import { existsSync as existsSync18, statSync as statSync8 } from "node:fs";
9042
- import { resolve as resolve19, basename as basename8, dirname as dirname8, join as join21 } from "node:path";
9351
+ import { resolve as resolve19, basename as basename8, dirname as dirname8, join as join22 } from "node:path";
9043
9352
  import { execSync as execSync15 } from "node:child_process";
9044
9353
  import { fileURLToPath as fileURLToPath4 } from "node:url";
9045
- import { homedir as homedir7, tmpdir as tmpdir5 } from "node:os";
9354
+ import { homedir as homedir7, tmpdir as tmpdir6 } from "node:os";
9046
9355
  function findOcrScript() {
9047
9356
  const thisDir = dirname8(fileURLToPath4(import.meta.url));
9048
9357
  const devPath3 = resolve19(thisDir, "../../scripts/ocr-advanced.py");
@@ -9057,7 +9366,7 @@ function findOcrScript() {
9057
9366
  return null;
9058
9367
  }
9059
9368
  function findPython() {
9060
- const venvPython = join21(homedir7(), ".open-agents", "venv", "bin", "python");
9369
+ const venvPython = join22(homedir7(), ".open-agents", "venv", "bin", "python");
9061
9370
  if (existsSync18(venvPython)) {
9062
9371
  try {
9063
9372
  execSync15(`${JSON.stringify(venvPython)} -c "import cv2, pytesseract, numpy, PIL"`, {
@@ -9203,7 +9512,7 @@ var init_ocr_image_advanced = __esm({
9203
9512
  cmdParts.push("--output-dir", JSON.stringify(resolve19(this.workingDir, outputDir)));
9204
9513
  let debugDir;
9205
9514
  if (debug) {
9206
- debugDir = join21(tmpdir5(), `oa-ocr-debug-${Date.now()}`);
9515
+ debugDir = join22(tmpdir6(), `oa-ocr-debug-${Date.now()}`);
9207
9516
  cmdParts.push("--debug-dir", debugDir);
9208
9517
  }
9209
9518
  try {
@@ -9302,7 +9611,7 @@ var init_ocr_image_advanced = __esm({
9302
9611
  if (region) {
9303
9612
  try {
9304
9613
  const [x, y, w, h] = region.split(",").map(Number);
9305
- const croppedPath = join21(tmpdir5(), `oa-ocr-crop-${Date.now()}.png`);
9614
+ const croppedPath = join22(tmpdir6(), `oa-ocr-crop-${Date.now()}.png`);
9306
9615
  execSync15(`convert ${JSON.stringify(imagePath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
9307
9616
  inputPath = croppedPath;
9308
9617
  } catch {
@@ -9341,20 +9650,20 @@ Note: Advanced Python pipeline not available \u2014 install pytesseract, opencv-
9341
9650
  });
9342
9651
 
9343
9652
  // packages/execution/dist/tools/browser-action.js
9344
- import { execSync as execSync16, spawn as spawn7 } from "node:child_process";
9653
+ import { execSync as execSync16, spawn as spawn8 } from "node:child_process";
9345
9654
  import { existsSync as existsSync19, readFileSync as readFileSync14 } from "node:fs";
9346
- import { join as join22, dirname as dirname9 } from "node:path";
9655
+ import { join as join23, dirname as dirname9 } from "node:path";
9347
9656
  import { fileURLToPath as fileURLToPath5 } from "node:url";
9348
9657
  function findScrapeScript() {
9349
9658
  const candidates = [
9350
9659
  // Published npm package: dist/scripts/web_scrape.py
9351
- join22(__dirname3, "scripts", "web_scrape.py"),
9660
+ join23(__dirname3, "scripts", "web_scrape.py"),
9352
9661
  // Published npm package (from node_modules): node_modules/open-agents-ai/dist/scripts/
9353
- join22(__dirname3, "..", "node_modules", "open-agents-ai", "dist", "scripts", "web_scrape.py"),
9662
+ join23(__dirname3, "..", "node_modules", "open-agents-ai", "dist", "scripts", "web_scrape.py"),
9354
9663
  // Dev monorepo: packages/execution/src/tools/../../scripts/
9355
- join22(__dirname3, "..", "..", "scripts", "web_scrape.py"),
9664
+ join23(__dirname3, "..", "..", "scripts", "web_scrape.py"),
9356
9665
  // Dev monorepo alt: packages/execution/scripts/
9357
- join22(__dirname3, "..", "scripts", "web_scrape.py")
9666
+ join23(__dirname3, "..", "scripts", "web_scrape.py")
9358
9667
  ];
9359
9668
  return candidates.find((p) => existsSync19(p)) || candidates[0];
9360
9669
  }
@@ -9389,7 +9698,7 @@ async function launchService() {
9389
9698
  if (!existsSync19(SCRAPE_SCRIPT)) {
9390
9699
  return `Scrape service script not found at ${SCRAPE_SCRIPT}`;
9391
9700
  }
9392
- serviceProcess = spawn7(python, [SCRAPE_SCRIPT], {
9701
+ serviceProcess = spawn8(python, [SCRAPE_SCRIPT], {
9393
9702
  stdio: "ignore",
9394
9703
  detached: true,
9395
9704
  env: {
@@ -9607,9 +9916,9 @@ var init_browser_action = __esm({
9607
9916
  });
9608
9917
 
9609
9918
  // packages/execution/dist/tools/autoresearch.js
9610
- import { execSync as execSync17, spawn as spawn8 } from "node:child_process";
9919
+ import { execSync as execSync17, spawn as spawn9 } from "node:child_process";
9611
9920
  import { existsSync as existsSync20, readFileSync as readFileSync15, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, appendFileSync, copyFileSync } from "node:fs";
9612
- import { join as join23, resolve as resolve20, dirname as dirname10 } from "node:path";
9921
+ import { join as join24, resolve as resolve20, dirname as dirname10 } from "node:path";
9613
9922
  import { fileURLToPath as fileURLToPath6 } from "node:url";
9614
9923
  function findAutoresearchScript(scriptName) {
9615
9924
  const thisDir = dirname10(fileURLToPath6(import.meta.url));
@@ -9711,7 +10020,7 @@ Requires: NVIDIA GPU, Python 3.10+, uv (astral.sh package manager).`;
9711
10020
  async execute(args) {
9712
10021
  const start = Date.now();
9713
10022
  const action = String(args["action"] ?? "status");
9714
- const workspacePath = String(args["workspace"] ?? join23(this.repoRoot, ".oa", "autoresearch"));
10023
+ const workspacePath = String(args["workspace"] ?? join24(this.repoRoot, ".oa", "autoresearch"));
9715
10024
  try {
9716
10025
  switch (action) {
9717
10026
  case "setup":
@@ -9752,13 +10061,13 @@ Requires: NVIDIA GPU, Python 3.10+, uv (astral.sh package manager).`;
9752
10061
  const prepareScript = findAutoresearchScript("autoresearch-prepare.py");
9753
10062
  const trainScript = findAutoresearchScript("autoresearch-train.py");
9754
10063
  if (prepareScript) {
9755
- copyFileSync(prepareScript, join23(workspace, "prepare.py"));
10064
+ copyFileSync(prepareScript, join24(workspace, "prepare.py"));
9756
10065
  output.push("Copied prepare.py template");
9757
10066
  } else {
9758
10067
  return { success: false, output: output.join("\n"), error: "autoresearch-prepare.py template not found in distribution", durationMs: Date.now() - start };
9759
10068
  }
9760
10069
  if (trainScript) {
9761
- copyFileSync(trainScript, join23(workspace, "train.py"));
10070
+ copyFileSync(trainScript, join24(workspace, "train.py"));
9762
10071
  output.push("Copied train.py template");
9763
10072
  } else {
9764
10073
  return { success: false, output: output.join("\n"), error: "autoresearch-train.py template not found in distribution", durationMs: Date.now() - start };
@@ -9790,7 +10099,7 @@ name = "pytorch-cu128"
9790
10099
  url = "https://download.pytorch.org/whl/cu128"
9791
10100
  explicit = true
9792
10101
  `;
9793
- writeFileSync6(join23(workspace, "pyproject.toml"), pyprojectContent, "utf-8");
10102
+ writeFileSync6(join24(workspace, "pyproject.toml"), pyprojectContent, "utf-8");
9794
10103
  output.push("Created pyproject.toml");
9795
10104
  try {
9796
10105
  execSync17("git rev-parse --git-dir", { cwd: workspace, encoding: "utf-8", timeout: 5e3 });
@@ -9832,7 +10141,7 @@ explicit = true
9832
10141
  const e = err;
9833
10142
  output.push(`Data prep warning: ${(e.stderr ?? e.stdout ?? "failed").slice(0, 500)}`);
9834
10143
  }
9835
- const tsvPath = join23(workspace, "results.tsv");
10144
+ const tsvPath = join24(workspace, "results.tsv");
9836
10145
  if (!existsSync20(tsvPath)) {
9837
10146
  writeFileSync6(tsvPath, "commit val_bpb memory_gb status description\n", "utf-8");
9838
10147
  output.push("Created results.tsv");
@@ -9854,10 +10163,10 @@ Next steps:
9854
10163
  }
9855
10164
  // ── Run experiment ─────────────────────────────────────────────────────
9856
10165
  async run(workspace, args, start) {
9857
- if (!existsSync20(join23(workspace, "train.py"))) {
10166
+ if (!existsSync20(join24(workspace, "train.py"))) {
9858
10167
  return { success: false, output: "", error: `No train.py found in ${workspace}. Run autoresearch(action="setup") first.`, durationMs: Date.now() - start };
9859
10168
  }
9860
- if (!existsSync20(join23(workspace, ".venv")) && existsSync20(join23(workspace, "pyproject.toml"))) {
10169
+ if (!existsSync20(join24(workspace, ".venv")) && existsSync20(join24(workspace, "pyproject.toml"))) {
9861
10170
  try {
9862
10171
  execSync17("uv sync 2>&1", { cwd: workspace, encoding: "utf-8", timeout: 3e5 });
9863
10172
  } catch {
@@ -9865,9 +10174,9 @@ Next steps:
9865
10174
  }
9866
10175
  const timeoutMin = Number(args["timeout_minutes"] ?? 10);
9867
10176
  const timeoutMs = timeoutMin * 60 * 1e3;
9868
- const logPath = join23(workspace, "run.log");
10177
+ const logPath = join24(workspace, "run.log");
9869
10178
  return new Promise((resolveResult) => {
9870
- const proc = spawn8("uv", ["run", "train.py"], {
10179
+ const proc = spawn9("uv", ["run", "train.py"], {
9871
10180
  cwd: workspace,
9872
10181
  timeout: timeoutMs,
9873
10182
  stdio: ["pipe", "pipe", "pipe"],
@@ -9936,7 +10245,7 @@ ${fullLog.slice(-2e3)}`,
9936
10245
  return;
9937
10246
  }
9938
10247
  try {
9939
- writeFileSync6(join23(workspace, ".last-result.json"), JSON.stringify(result, null, 2), "utf-8");
10248
+ writeFileSync6(join24(workspace, ".last-result.json"), JSON.stringify(result, null, 2), "utf-8");
9940
10249
  } catch {
9941
10250
  }
9942
10251
  const memGB = (result.peak_vram_mb / 1024).toFixed(1);
@@ -9972,7 +10281,7 @@ ${fullLog.slice(-2e3)}`,
9972
10281
  }
9973
10282
  // ── Results ────────────────────────────────────────────────────────────
9974
10283
  getResults(workspace, start) {
9975
- const tsvPath = join23(workspace, "results.tsv");
10284
+ const tsvPath = join24(workspace, "results.tsv");
9976
10285
  if (!existsSync20(tsvPath)) {
9977
10286
  return { success: false, output: "", error: `No results.tsv found. Run autoresearch(action="setup") first.`, durationMs: Date.now() - start };
9978
10287
  }
@@ -9999,7 +10308,7 @@ ${fullLog.slice(-2e3)}`,
9999
10308
  // ── Status ─────────────────────────────────────────────────────────────
10000
10309
  getStatus(workspace, start) {
10001
10310
  const output = [];
10002
- if (!existsSync20(join23(workspace, "train.py"))) {
10311
+ if (!existsSync20(join24(workspace, "train.py"))) {
10003
10312
  return {
10004
10313
  success: true,
10005
10314
  output: `Autoresearch workspace not initialized at ${workspace}.
@@ -10022,7 +10331,7 @@ Run autoresearch(action="setup") to begin.`,
10022
10331
  } catch {
10023
10332
  output.push("GPU: not detected");
10024
10333
  }
10025
- const lastResultPath = join23(workspace, ".last-result.json");
10334
+ const lastResultPath = join24(workspace, ".last-result.json");
10026
10335
  if (existsSync20(lastResultPath)) {
10027
10336
  try {
10028
10337
  const last = JSON.parse(readFileSync15(lastResultPath, "utf-8"));
@@ -10030,20 +10339,20 @@ Run autoresearch(action="setup") to begin.`,
10030
10339
  } catch {
10031
10340
  }
10032
10341
  }
10033
- const tsvPath = join23(workspace, "results.tsv");
10342
+ const tsvPath = join24(workspace, "results.tsv");
10034
10343
  if (existsSync20(tsvPath)) {
10035
10344
  const lines = readFileSync15(tsvPath, "utf-8").trim().split("\n");
10036
10345
  output.push(`Experiments recorded: ${lines.length - 1}`);
10037
10346
  }
10038
- const cacheDir = join23(process.env["HOME"] ?? "~", ".cache", "autoresearch");
10347
+ const cacheDir = join24(process.env["HOME"] ?? "~", ".cache", "autoresearch");
10039
10348
  output.push(`Data cache: ${existsSync20(cacheDir) ? "present" : "not found"} (${cacheDir})`);
10040
10349
  return { success: true, output: output.join("\n"), durationMs: Date.now() - start };
10041
10350
  }
10042
10351
  // ── Keep / Discard ─────────────────────────────────────────────────────
10043
10352
  keepExperiment(workspace, args, start) {
10044
10353
  const desc = String(args["description"] ?? "experiment");
10045
- const tsvPath = join23(workspace, "results.tsv");
10046
- const lastResultPath = join23(workspace, ".last-result.json");
10354
+ const tsvPath = join24(workspace, "results.tsv");
10355
+ const lastResultPath = join24(workspace, ".last-result.json");
10047
10356
  let valBpb = args["val_bpb"];
10048
10357
  let memGb = args["memory_gb"];
10049
10358
  if ((valBpb === void 0 || memGb === void 0) && existsSync20(lastResultPath)) {
@@ -10081,8 +10390,8 @@ Branch advanced. Ready for next experiment.`,
10081
10390
  }
10082
10391
  discardExperiment(workspace, args, start) {
10083
10392
  const desc = String(args["description"] ?? "experiment");
10084
- const tsvPath = join23(workspace, "results.tsv");
10085
- const lastResultPath = join23(workspace, ".last-result.json");
10393
+ const tsvPath = join24(workspace, "results.tsv");
10394
+ const lastResultPath = join24(workspace, ".last-result.json");
10086
10395
  let valBpb = args["val_bpb"];
10087
10396
  let memGb = args["memory_gb"];
10088
10397
  if ((valBpb === void 0 || memGb === void 0) && existsSync20(lastResultPath)) {
@@ -10129,8 +10438,8 @@ train.py reverted to last kept state. Ready for next experiment.`,
10129
10438
  // packages/execution/dist/tools/scheduler.js
10130
10439
  import { execSync as execSync18, exec as execCb } from "node:child_process";
10131
10440
  import { readFile as readFile9, writeFile as writeFile8, mkdir as mkdir4 } from "node:fs/promises";
10132
- import { resolve as resolve21, join as join24 } from "node:path";
10133
- import { randomBytes as randomBytes2 } from "node:crypto";
10441
+ import { resolve as resolve21, join as join25 } from "node:path";
10442
+ import { randomBytes as randomBytes3 } from "node:crypto";
10134
10443
  function isValidCron(expr) {
10135
10444
  const parts = expr.trim().split(/\s+/);
10136
10445
  if (parts.length !== 5)
@@ -10213,7 +10522,7 @@ function installCronJob(task, workingDir) {
10213
10522
  const lines = getCurrentCrontab();
10214
10523
  const oaBin = findOaBinary();
10215
10524
  const logDir = resolve21(workingDir, ".oa", "scheduled", "logs");
10216
- const logFile = join24(logDir, `${task.id}.log`);
10525
+ const logFile = join25(logDir, `${task.id}.log`);
10217
10526
  const storeFile = resolve21(workingDir, ".oa", "scheduled", "tasks.json");
10218
10527
  const taskEscaped = task.task.replace(/'/g, "'\\''");
10219
10528
  const taskId = task.id;
@@ -10255,9 +10564,9 @@ async function loadStore(workingDir) {
10255
10564
  async function saveStore(workingDir, store) {
10256
10565
  const dir = resolve21(workingDir, ".oa", "scheduled");
10257
10566
  await mkdir4(dir, { recursive: true });
10258
- await mkdir4(join24(dir, "logs"), { recursive: true });
10567
+ await mkdir4(join25(dir, "logs"), { recursive: true });
10259
10568
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
10260
- await writeFile8(join24(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
10569
+ await writeFile8(join25(dir, "tasks.json"), JSON.stringify(store, null, 2), "utf-8");
10261
10570
  }
10262
10571
  var SCHEDULE_PRESETS, CRON_MARKER, SchedulerTool;
10263
10572
  var init_scheduler = __esm({
@@ -10368,7 +10677,7 @@ var init_scheduler = __esm({
10368
10677
  durationMs: performance.now() - start
10369
10678
  };
10370
10679
  }
10371
- const id = `sched-${randomBytes2(4).toString("hex")}`;
10680
+ const id = `sched-${randomBytes3(4).toString("hex")}`;
10372
10681
  const oneShot = Boolean(args["one_shot"]);
10373
10682
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : void 0;
10374
10683
  const newTask = {
@@ -10491,8 +10800,8 @@ ${truncated}`, durationMs: performance.now() - start };
10491
10800
 
10492
10801
  // packages/execution/dist/tools/reminder.js
10493
10802
  import { readFile as readFile10, writeFile as writeFile9, mkdir as mkdir5 } from "node:fs/promises";
10494
- import { resolve as resolve22, join as join25 } from "node:path";
10495
- import { randomBytes as randomBytes3 } from "node:crypto";
10803
+ import { resolve as resolve22, join as join26 } from "node:path";
10804
+ import { randomBytes as randomBytes4 } from "node:crypto";
10496
10805
  function parseDueTime(due) {
10497
10806
  const lower = due.toLowerCase().trim();
10498
10807
  const now = /* @__PURE__ */ new Date();
@@ -10543,7 +10852,7 @@ function parseDueTime(due) {
10543
10852
  async function getStorePath(workingDir) {
10544
10853
  const dir = resolve22(workingDir, ".oa", "scheduled");
10545
10854
  await mkdir5(dir, { recursive: true });
10546
- return join25(dir, STORE_FILE);
10855
+ return join26(dir, STORE_FILE);
10547
10856
  }
10548
10857
  async function loadReminderStore(workingDir) {
10549
10858
  const storePath = await getStorePath(workingDir);
@@ -10689,7 +10998,7 @@ var init_reminder = __esm({
10689
10998
  dueAt = parsed.isoDate;
10690
10999
  dueDescription = parsed.description;
10691
11000
  }
10692
- const id = `rem-${randomBytes3(4).toString("hex")}`;
11001
+ const id = `rem-${randomBytes4(4).toString("hex")}`;
10693
11002
  const entry = {
10694
11003
  id,
10695
11004
  message,
@@ -10804,8 +11113,8 @@ var init_reminder = __esm({
10804
11113
 
10805
11114
  // packages/execution/dist/tools/agenda.js
10806
11115
  import { readFile as readFile11, writeFile as writeFile10, mkdir as mkdir6 } from "node:fs/promises";
10807
- import { resolve as resolve23, join as join26 } from "node:path";
10808
- import { randomBytes as randomBytes4 } from "node:crypto";
11116
+ import { resolve as resolve23, join as join27 } from "node:path";
11117
+ import { randomBytes as randomBytes5 } from "node:crypto";
10809
11118
  async function loadAttentionStore(workingDir) {
10810
11119
  const storePath = resolve23(workingDir, ".oa", "scheduled", "attention.json");
10811
11120
  try {
@@ -10819,7 +11128,7 @@ async function saveAttentionStore(workingDir, store) {
10819
11128
  const dir = resolve23(workingDir, ".oa", "scheduled");
10820
11129
  await mkdir6(dir, { recursive: true });
10821
11130
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
10822
- await writeFile10(join26(dir, "attention.json"), JSON.stringify(store, null, 2), "utf-8");
11131
+ await writeFile10(join27(dir, "attention.json"), JSON.stringify(store, null, 2), "utf-8");
10823
11132
  }
10824
11133
  async function getActiveAttentionItems(workingDir) {
10825
11134
  const store = await loadAttentionStore(workingDir);
@@ -11008,7 +11317,7 @@ ${sections.join("\n")}`,
11008
11317
  expiresAt = target.toISOString();
11009
11318
  }
11010
11319
  }
11011
- const id = `attn-${randomBytes4(4).toString("hex")}`;
11320
+ const id = `attn-${randomBytes5(4).toString("hex")}`;
11012
11321
  const item = {
11013
11322
  id,
11014
11323
  title,
@@ -11127,9 +11436,9 @@ ${sections.join("\n")}`,
11127
11436
  });
11128
11437
 
11129
11438
  // packages/execution/dist/tools/opencode.js
11130
- import { execSync as execSync19, spawn as spawn9 } from "node:child_process";
11439
+ import { execSync as execSync19, spawn as spawn10 } from "node:child_process";
11131
11440
  import { existsSync as existsSync21 } from "node:fs";
11132
- import { join as join27, resolve as resolve24 } from "node:path";
11441
+ import { join as join28, resolve as resolve24 } from "node:path";
11133
11442
  function findOpencode() {
11134
11443
  for (const cmd of ["opencode"]) {
11135
11444
  try {
@@ -11141,8 +11450,8 @@ function findOpencode() {
11141
11450
  }
11142
11451
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
11143
11452
  const candidates = [
11144
- join27(homeDir, ".opencode", "bin", "opencode"),
11145
- join27(homeDir, "bin", "opencode"),
11453
+ join28(homeDir, ".opencode", "bin", "opencode"),
11454
+ join28(homeDir, "bin", "opencode"),
11146
11455
  "/usr/local/bin/opencode"
11147
11456
  ];
11148
11457
  for (const p of candidates) {
@@ -11315,7 +11624,7 @@ var init_opencode = __esm({
11315
11624
  let output = "";
11316
11625
  const maxOutput = 5e5;
11317
11626
  let timedOut = false;
11318
- const child = spawn9(binary, cmdArgs, {
11627
+ const child = spawn10(binary, cmdArgs, {
11319
11628
  cwd: dir,
11320
11629
  env: { ...process.env, CI: "true", NONINTERACTIVE: "1" },
11321
11630
  stdio: ["ignore", "pipe", "pipe"]
@@ -11401,9 +11710,9 @@ var init_opencode = __esm({
11401
11710
  });
11402
11711
 
11403
11712
  // packages/execution/dist/tools/factory.js
11404
- import { execSync as execSync20, spawn as spawn10 } from "node:child_process";
11713
+ import { execSync as execSync20, spawn as spawn11 } from "node:child_process";
11405
11714
  import { existsSync as existsSync22 } from "node:fs";
11406
- import { join as join28 } from "node:path";
11715
+ import { join as join29 } from "node:path";
11407
11716
  function findDroid() {
11408
11717
  for (const cmd of ["droid"]) {
11409
11718
  try {
@@ -11415,8 +11724,8 @@ function findDroid() {
11415
11724
  }
11416
11725
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
11417
11726
  const candidates = [
11418
- join28(homeDir, ".factory", "bin", "droid"),
11419
- join28(homeDir, "bin", "droid"),
11727
+ join29(homeDir, ".factory", "bin", "droid"),
11728
+ join29(homeDir, "bin", "droid"),
11420
11729
  "/usr/local/bin/droid"
11421
11730
  ];
11422
11731
  for (const p of candidates) {
@@ -11620,7 +11929,7 @@ var init_factory = __esm({
11620
11929
  let output = "";
11621
11930
  const maxOutput = 5e5;
11622
11931
  let timedOut = false;
11623
- const child = spawn10(binary, cmdArgs, {
11932
+ const child = spawn11(binary, cmdArgs, {
11624
11933
  cwd: dir,
11625
11934
  env: { ...process.env },
11626
11935
  stdio: ["ignore", "pipe", "pipe"]
@@ -11712,8 +12021,8 @@ var init_factory = __esm({
11712
12021
  // packages/execution/dist/tools/cron-agent.js
11713
12022
  import { execSync as execSync21 } from "node:child_process";
11714
12023
  import { readFile as readFile12, writeFile as writeFile11, mkdir as mkdir7 } from "node:fs/promises";
11715
- import { resolve as resolve25, join as join29 } from "node:path";
11716
- import { randomBytes as randomBytes5 } from "node:crypto";
12024
+ import { resolve as resolve25, join as join30 } from "node:path";
12025
+ import { randomBytes as randomBytes6 } from "node:crypto";
11717
12026
  function isValidCron2(expr) {
11718
12027
  const parts = expr.trim().split(/\s+/);
11719
12028
  if (parts.length !== 5)
@@ -11798,7 +12107,7 @@ function installCronAgentJob(job, workingDir) {
11798
12107
  const lines = getCurrentCrontab2();
11799
12108
  const oaBin = findOaBinary2();
11800
12109
  const logDir = resolve25(workingDir, ".oa", "cron-agents", "logs");
11801
- const logFile = join29(logDir, `${job.id}.log`);
12110
+ const logFile = join30(logDir, `${job.id}.log`);
11802
12111
  const storeFile = resolve25(workingDir, ".oa", "cron-agents", "store.json");
11803
12112
  const taskEscaped = job.task.replace(/'/g, "'\\''");
11804
12113
  const jobId = job.id;
@@ -11837,9 +12146,9 @@ async function loadStore2(workingDir) {
11837
12146
  async function saveStore2(workingDir, store) {
11838
12147
  const dir = resolve25(workingDir, ".oa", "cron-agents");
11839
12148
  await mkdir7(dir, { recursive: true });
11840
- await mkdir7(join29(dir, "logs"), { recursive: true });
12149
+ await mkdir7(join30(dir, "logs"), { recursive: true });
11841
12150
  store.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
11842
- await writeFile11(join29(dir, "store.json"), JSON.stringify(store, null, 2), "utf-8");
12151
+ await writeFile11(join30(dir, "store.json"), JSON.stringify(store, null, 2), "utf-8");
11843
12152
  }
11844
12153
  var LONG_HORIZON_PRESETS, CRON_AGENT_MARKER, CronAgentTool;
11845
12154
  var init_cron_agent = __esm({
@@ -11973,7 +12282,7 @@ var init_cron_agent = __esm({
11973
12282
  durationMs: performance.now() - start
11974
12283
  };
11975
12284
  }
11976
- const id = `cron-${randomBytes5(4).toString("hex")}`;
12285
+ const id = `cron-${randomBytes6(4).toString("hex")}`;
11977
12286
  const verifyCommand = args["verify_command"] ? String(args["verify_command"]) : void 0;
11978
12287
  const maxRuns = typeof args["max_runs"] === "number" ? args["max_runs"] : 0;
11979
12288
  const tags = Array.isArray(args["tags"]) ? args["tags"] : [];
@@ -12177,9 +12486,9 @@ ${truncated}`, durationMs: performance.now() - start };
12177
12486
  // packages/execution/dist/tools/nexus.js
12178
12487
  import { readFile as readFile13, writeFile as writeFile12, mkdir as mkdir8, chmod, unlink, readdir as readdir3, open as fsOpen } from "node:fs/promises";
12179
12488
  import { existsSync as existsSync23, readFileSync as readFileSync16, watch as fsWatchLocal } from "node:fs";
12180
- import { resolve as resolve26, join as join30 } from "node:path";
12181
- import { randomBytes as randomBytes6, createCipheriv, createDecipheriv, scryptSync, createHash } from "node:crypto";
12182
- import { execSync as execSync22, spawn as spawn11 } from "node:child_process";
12489
+ import { resolve as resolve26, join as join31 } from "node:path";
12490
+ import { randomBytes as randomBytes7, createCipheriv, createDecipheriv, scryptSync, createHash } from "node:crypto";
12491
+ import { execSync as execSync22, spawn as spawn12 } from "node:child_process";
12183
12492
  import { hostname, userInfo } from "node:os";
12184
12493
  function containsKeyMaterial(input) {
12185
12494
  for (const pattern of KEY_PATTERNS) {
@@ -14270,7 +14579,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14270
14579
  // Daemon management
14271
14580
  // =========================================================================
14272
14581
  getDaemonPid() {
14273
- const pidFile = join30(this.nexusDir, "daemon.pid");
14582
+ const pidFile = join31(this.nexusDir, "daemon.pid");
14274
14583
  if (!existsSync23(pidFile))
14275
14584
  return null;
14276
14585
  try {
@@ -14295,9 +14604,9 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14295
14604
  if (!pid)
14296
14605
  throw new Error("Nexus daemon not running. Use action 'connect' first.");
14297
14606
  }
14298
- const cmdId = randomBytes6(8).toString("hex");
14299
- const cmdFile = join30(this.nexusDir, "cmd.json");
14300
- const respFile = join30(this.nexusDir, "resp.json");
14607
+ const cmdId = randomBytes7(8).toString("hex");
14608
+ const cmdFile = join31(this.nexusDir, "cmd.json");
14609
+ const respFile = join31(this.nexusDir, "resp.json");
14301
14610
  if (existsSync23(respFile))
14302
14611
  await unlink(respFile).catch(() => {
14303
14612
  });
@@ -14381,7 +14690,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14381
14690
  const currentScriptHash = createHash("sha256").update(DAEMON_SCRIPT).digest("hex").slice(0, 16);
14382
14691
  const existingPid = this.getDaemonPid();
14383
14692
  if (existingPid) {
14384
- const daemonPath2 = join30(this.nexusDir, "nexus-daemon.mjs");
14693
+ const daemonPath2 = join31(this.nexusDir, "nexus-daemon.mjs");
14385
14694
  let needsRestart = true;
14386
14695
  if (existsSync23(daemonPath2)) {
14387
14696
  try {
@@ -14405,13 +14714,13 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14405
14714
  } catch {
14406
14715
  }
14407
14716
  for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
14408
- const p = join30(this.nexusDir, f);
14717
+ const p = join31(this.nexusDir, f);
14409
14718
  if (existsSync23(p))
14410
14719
  await unlink(p).catch(() => {
14411
14720
  });
14412
14721
  }
14413
14722
  } else {
14414
- const statusFile2 = join30(this.nexusDir, "status.json");
14723
+ const statusFile2 = join31(this.nexusDir, "status.json");
14415
14724
  if (existsSync23(statusFile2)) {
14416
14725
  try {
14417
14726
  const status = JSON.parse(await readFile13(statusFile2, "utf8"));
@@ -14430,7 +14739,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14430
14739
  }
14431
14740
  }
14432
14741
  for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
14433
- const p = join30(this.nexusDir, f);
14742
+ const p = join31(this.nexusDir, f);
14434
14743
  if (existsSync23(p))
14435
14744
  await unlink(p).catch(() => {
14436
14745
  });
@@ -14448,7 +14757,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14448
14757
  });
14449
14758
  });
14450
14759
  try {
14451
- const nexusPkg = join30(nodeModulesDir, "open-agents-nexus", "package.json");
14760
+ const nexusPkg = join31(nodeModulesDir, "open-agents-nexus", "package.json");
14452
14761
  if (existsSync23(nexusPkg)) {
14453
14762
  nexusResolved = true;
14454
14763
  try {
@@ -14459,7 +14768,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14459
14768
  } else {
14460
14769
  try {
14461
14770
  const globalDir = await execAsync2("npm root -g", { timeout: 5e3 });
14462
- const globalPkg = join30(globalDir, "open-agents-nexus", "package.json");
14771
+ const globalPkg = join31(globalDir, "open-agents-nexus", "package.json");
14463
14772
  if (existsSync23(globalPkg)) {
14464
14773
  nexusResolved = true;
14465
14774
  try {
@@ -14504,7 +14813,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14504
14813
  }
14505
14814
  }
14506
14815
  await this.ensureWallet();
14507
- const daemonPath = join30(this.nexusDir, "nexus-daemon.mjs");
14816
+ const daemonPath = join31(this.nexusDir, "nexus-daemon.mjs");
14508
14817
  await writeFile12(daemonPath, DAEMON_SCRIPT);
14509
14818
  const agentName = args.agent_name || "open-agents-node";
14510
14819
  const agentType = args.agent_type || "general";
@@ -14515,11 +14824,11 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14515
14824
  } catch {
14516
14825
  }
14517
14826
  const { openSync: openSync2, closeSync: closeSync2 } = await import("node:fs");
14518
- const daemonLogPath = join30(this.nexusDir, "daemon.log");
14519
- const daemonErrPath = join30(this.nexusDir, "daemon.err");
14827
+ const daemonLogPath = join31(this.nexusDir, "daemon.log");
14828
+ const daemonErrPath = join31(this.nexusDir, "daemon.err");
14520
14829
  const outFd = openSync2(daemonLogPath, "w");
14521
14830
  const errFd = openSync2(daemonErrPath, "w");
14522
- const child = spawn11("node", [daemonPath, this.nexusDir, agentName, agentType], {
14831
+ const child = spawn12("node", [daemonPath, this.nexusDir, agentName, agentType], {
14523
14832
  detached: true,
14524
14833
  stdio: ["ignore", outFd, errFd],
14525
14834
  cwd: this.repoRoot,
@@ -14534,7 +14843,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14534
14843
  closeSync2(errFd);
14535
14844
  } catch {
14536
14845
  }
14537
- const statusFile = join30(this.nexusDir, "status.json");
14846
+ const statusFile = join31(this.nexusDir, "status.json");
14538
14847
  for (let i = 0; i < 40; i++) {
14539
14848
  await new Promise((r) => setTimeout(r, 500));
14540
14849
  if (existsSync23(statusFile)) {
@@ -14593,7 +14902,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14593
14902
  } catch {
14594
14903
  }
14595
14904
  for (const f of ["daemon.pid", "status.json", "cmd.json", "resp.json"]) {
14596
- const p = join30(this.nexusDir, f);
14905
+ const p = join31(this.nexusDir, f);
14597
14906
  if (existsSync23(p))
14598
14907
  await unlink(p).catch(() => {
14599
14908
  });
@@ -14604,7 +14913,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14604
14913
  const pid = this.getDaemonPid();
14605
14914
  if (!pid)
14606
14915
  return "Nexus daemon not running. Use action 'connect' to start.";
14607
- const statusFile = join30(this.nexusDir, "status.json");
14916
+ const statusFile = join31(this.nexusDir, "status.json");
14608
14917
  if (!existsSync23(statusFile))
14609
14918
  return `Daemon running (pid: ${pid}) but no status yet.`;
14610
14919
  try {
@@ -14619,7 +14928,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14619
14928
  ` Capabilities: ${(status.capabilities || []).length ? (status.capabilities || []).join(", ") : "none"}`,
14620
14929
  ` Blocked peers: ${(status.blockedPeers || []).length || 0}`
14621
14930
  ];
14622
- const walletPath = join30(this.nexusDir, "wallet.enc");
14931
+ const walletPath = join31(this.nexusDir, "wallet.enc");
14623
14932
  if (existsSync23(walletPath)) {
14624
14933
  try {
14625
14934
  const w = JSON.parse(await readFile13(walletPath, "utf8"));
@@ -14630,14 +14939,14 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14630
14939
  } else {
14631
14940
  lines.push(` Wallet: not configured`);
14632
14941
  }
14633
- const inboxDir = join30(this.nexusDir, "inbox");
14942
+ const inboxDir = join31(this.nexusDir, "inbox");
14634
14943
  if (existsSync23(inboxDir)) {
14635
14944
  try {
14636
14945
  const roomDirs = await readdir3(inboxDir);
14637
14946
  let totalMsgs = 0;
14638
14947
  for (const rd of roomDirs) {
14639
14948
  try {
14640
- totalMsgs += (await readdir3(join30(inboxDir, rd))).length;
14949
+ totalMsgs += (await readdir3(join31(inboxDir, rd))).length;
14641
14950
  } catch {
14642
14951
  }
14643
14952
  }
@@ -14684,9 +14993,9 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14684
14993
  }
14685
14994
  async doReadMessages(args) {
14686
14995
  const roomId = args.room_id;
14687
- const inboxDir = join30(this.nexusDir, "inbox");
14996
+ const inboxDir = join31(this.nexusDir, "inbox");
14688
14997
  if (roomId) {
14689
- const roomInbox = join30(inboxDir, roomId);
14998
+ const roomInbox = join31(inboxDir, roomId);
14690
14999
  if (!existsSync23(roomInbox))
14691
15000
  return `No messages in room: ${roomId}`;
14692
15001
  const files = (await readdir3(roomInbox)).sort().slice(-20);
@@ -14695,7 +15004,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14695
15004
  const messages = [`Messages in ${roomId} (last ${files.length}):`];
14696
15005
  for (const f of files) {
14697
15006
  try {
14698
- const msg = JSON.parse(await readFile13(join30(roomInbox, f), "utf8"));
15007
+ const msg = JSON.parse(await readFile13(join31(roomInbox, f), "utf8"));
14699
15008
  const sender = (msg.sender || "unknown").slice(0, 12);
14700
15009
  messages.push(` [${new Date(msg.timestamp).toLocaleTimeString()}] ${sender}...: ${msg.content}`);
14701
15010
  } catch {
@@ -14711,7 +15020,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14711
15020
  const lines = ["Inbox:"];
14712
15021
  for (const rd of roomDirs) {
14713
15022
  try {
14714
- const count = (await readdir3(join30(inboxDir, rd))).length;
15023
+ const count = (await readdir3(join31(inboxDir, rd))).length;
14715
15024
  lines.push(` ${rd}: ${count} message(s)`);
14716
15025
  } catch {
14717
15026
  }
@@ -14723,7 +15032,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14723
15032
  // ---------------------------------------------------------------------------
14724
15033
  async doWalletStatus() {
14725
15034
  await this.ensureDir();
14726
- const walletPath = join30(this.nexusDir, "wallet.enc");
15035
+ const walletPath = join31(this.nexusDir, "wallet.enc");
14727
15036
  if (!existsSync23(walletPath)) {
14728
15037
  return "No wallet configured. Use wallet_create to set one up.";
14729
15038
  }
@@ -14762,7 +15071,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14762
15071
  }
14763
15072
  async doWalletCreate(args) {
14764
15073
  await this.ensureDir();
14765
- const walletPath = join30(this.nexusDir, "wallet.enc");
15074
+ const walletPath = join31(this.nexusDir, "wallet.enc");
14766
15075
  if (existsSync23(walletPath))
14767
15076
  return "Wallet already exists. Delete wallet.enc to create a new one.";
14768
15077
  const userAddress = args.wallet_address;
@@ -14791,24 +15100,24 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14791
15100
  let privKeyHex;
14792
15101
  try {
14793
15102
  const { privateKeyToAccount } = await import("viem/accounts");
14794
- const privKey = randomBytes6(32);
15103
+ const privKey = randomBytes7(32);
14795
15104
  privKeyHex = privKey.toString("hex");
14796
15105
  const account = privateKeyToAccount(`0x${privKeyHex}`);
14797
15106
  address = account.address;
14798
15107
  privKey.fill(0);
14799
15108
  } catch {
14800
- const privKey = randomBytes6(32);
15109
+ const privKey = randomBytes7(32);
14801
15110
  privKeyHex = privKey.toString("hex");
14802
15111
  address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
14803
15112
  privKey.fill(0);
14804
15113
  }
14805
- const salt = randomBytes6(32);
15114
+ const salt = randomBytes7(32);
14806
15115
  const key = scryptSync(`${hostname()}:${userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
14807
- const iv = randomBytes6(16);
15116
+ const iv = randomBytes7(16);
14808
15117
  const cipher = createCipheriv("aes-256-gcm", key, iv);
14809
15118
  let enc = cipher.update(privKeyHex, "utf8", "hex");
14810
15119
  enc += cipher.final("hex");
14811
- const x402KeyPath = join30(this.nexusDir, "x402-wallet.key");
15120
+ const x402KeyPath = join31(this.nexusDir, "x402-wallet.key");
14812
15121
  const x402Fh = await fsOpen(x402KeyPath, "w", 384);
14813
15122
  await x402Fh.writeFile("0x" + privKeyHex);
14814
15123
  await x402Fh.close();
@@ -14846,31 +15155,31 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14846
15155
  * Silent — no user output, just ensures the files exist.
14847
15156
  */
14848
15157
  async ensureWallet() {
14849
- const walletPath = join30(this.nexusDir, "wallet.enc");
15158
+ const walletPath = join31(this.nexusDir, "wallet.enc");
14850
15159
  if (existsSync23(walletPath))
14851
15160
  return;
14852
15161
  let address;
14853
15162
  let privKeyHex;
14854
15163
  try {
14855
15164
  const { privateKeyToAccount } = await import("viem/accounts");
14856
- const privKey = randomBytes6(32);
15165
+ const privKey = randomBytes7(32);
14857
15166
  privKeyHex = privKey.toString("hex");
14858
15167
  const account = privateKeyToAccount(`0x${privKeyHex}`);
14859
15168
  address = account.address;
14860
15169
  privKey.fill(0);
14861
15170
  } catch {
14862
- const privKey = randomBytes6(32);
15171
+ const privKey = randomBytes7(32);
14863
15172
  privKeyHex = privKey.toString("hex");
14864
15173
  address = "0x" + createHash("sha256").update(privKey).digest("hex").slice(0, 40);
14865
15174
  privKey.fill(0);
14866
15175
  }
14867
- const salt = randomBytes6(32);
15176
+ const salt = randomBytes7(32);
14868
15177
  const key = scryptSync(`${hostname()}:${userInfo().username}:nexus-wallet`, salt, 32, { N: 16384, r: 8, p: 1 });
14869
- const iv = randomBytes6(16);
15178
+ const iv = randomBytes7(16);
14870
15179
  const cipher = createCipheriv("aes-256-gcm", key, iv);
14871
15180
  let enc = cipher.update(privKeyHex, "utf8", "hex");
14872
15181
  enc += cipher.final("hex");
14873
- const x402KeyPath = join30(this.nexusDir, "x402-wallet.key");
15182
+ const x402KeyPath = join31(this.nexusDir, "x402-wallet.key");
14874
15183
  const x402Fh = await fsOpen(x402KeyPath, "w", 384);
14875
15184
  await x402Fh.writeFile("0x" + privKeyHex);
14876
15185
  await x402Fh.close();
@@ -14930,7 +15239,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14930
15239
  // ---------------------------------------------------------------------------
14931
15240
  async doLedgerStatus() {
14932
15241
  await this.ensureDir();
14933
- const ledgerPath = join30(this.nexusDir, "ledger.jsonl");
15242
+ const ledgerPath = join31(this.nexusDir, "ledger.jsonl");
14934
15243
  if (!existsSync23(ledgerPath)) {
14935
15244
  return "No ledger entries. Earnings and spending will be tracked here after x402 transactions.";
14936
15245
  }
@@ -14972,7 +15281,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14972
15281
  }
14973
15282
  }
14974
15283
  async getLedgerSummary() {
14975
- const ledgerPath = join30(this.nexusDir, "ledger.jsonl");
15284
+ const ledgerPath = join31(this.nexusDir, "ledger.jsonl");
14976
15285
  if (!existsSync23(ledgerPath))
14977
15286
  return null;
14978
15287
  try {
@@ -14997,7 +15306,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
14997
15306
  }
14998
15307
  async appendLedger(entry) {
14999
15308
  await this.ensureDir();
15000
- const ledgerPath = join30(this.nexusDir, "ledger.jsonl");
15309
+ const ledgerPath = join31(this.nexusDir, "ledger.jsonl");
15001
15310
  const line = JSON.stringify(entry) + "\n";
15002
15311
  await writeFile12(ledgerPath, existsSync23(ledgerPath) ? await readFile13(ledgerPath, "utf8") + line : line);
15003
15312
  }
@@ -15005,7 +15314,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15005
15314
  // Step 4: Budget Policy — Spending limits and auto-approve thresholds
15006
15315
  // ---------------------------------------------------------------------------
15007
15316
  async loadBudget() {
15008
- const budgetPath = join30(this.nexusDir, "budget.json");
15317
+ const budgetPath = join31(this.nexusDir, "budget.json");
15009
15318
  if (!existsSync23(budgetPath))
15010
15319
  return null;
15011
15320
  try {
@@ -15015,7 +15324,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15015
15324
  }
15016
15325
  }
15017
15326
  async ensureDefaultBudget() {
15018
- const budgetPath = join30(this.nexusDir, "budget.json");
15327
+ const budgetPath = join31(this.nexusDir, "budget.json");
15019
15328
  if (existsSync23(budgetPath))
15020
15329
  return;
15021
15330
  const defaultBudget = {
@@ -15085,12 +15394,12 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15085
15394
  if (changes.length === 0) {
15086
15395
  return "No budget parameters provided. Use daily_limit, per_invoke_max, or auto_approve_below.";
15087
15396
  }
15088
- const budgetPath = join30(this.nexusDir, "budget.json");
15397
+ const budgetPath = join31(this.nexusDir, "budget.json");
15089
15398
  await writeFile12(budgetPath, JSON.stringify(budget, null, 2));
15090
15399
  return `Budget updated: ${changes.join(", ")}`;
15091
15400
  }
15092
15401
  async getTodaySpending() {
15093
- const ledgerPath = join30(this.nexusDir, "ledger.jsonl");
15402
+ const ledgerPath = join31(this.nexusDir, "ledger.jsonl");
15094
15403
  if (!existsSync23(ledgerPath))
15095
15404
  return 0;
15096
15405
  try {
@@ -15134,7 +15443,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15134
15443
  if (todaySpent + amountUsdc > budget.dailyLimitUsdc) {
15135
15444
  return { allowed: false, reason: `Would exceed daily limit ($${((todaySpent + amountUsdc) / 1e6).toFixed(6)} > $${(budget.dailyLimitUsdc / 1e6).toFixed(6)})` };
15136
15445
  }
15137
- const walletPath = join30(this.nexusDir, "wallet.enc");
15446
+ const walletPath = join31(this.nexusDir, "wallet.enc");
15138
15447
  if (existsSync23(walletPath)) {
15139
15448
  try {
15140
15449
  const w = JSON.parse(await readFile13(walletPath, "utf8"));
@@ -15165,7 +15474,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15165
15474
  const budgetResult = await this.checkBudget(amountSmallest, "transfer:direct", targetAddress);
15166
15475
  if (!budgetResult.allowed)
15167
15476
  return `BLOCKED by budget policy: ${budgetResult.reason}`;
15168
- const walletPath = join30(this.nexusDir, "wallet.enc");
15477
+ const walletPath = join31(this.nexusDir, "wallet.enc");
15169
15478
  if (!existsSync23(walletPath))
15170
15479
  throw new Error("No wallet. Use wallet_create first.");
15171
15480
  const w = JSON.parse(await readFile13(walletPath, "utf8"));
@@ -15180,7 +15489,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15180
15489
  try {
15181
15490
  const { privateKeyToAccount } = await import("viem/accounts");
15182
15491
  const account = privateKeyToAccount(`0x${privKeyHex}`);
15183
- const nonce = "0x" + randomBytes6(32).toString("hex");
15492
+ const nonce = "0x" + randomBytes7(32).toString("hex");
15184
15493
  const now = Math.floor(Date.now() / 1e3);
15185
15494
  const validAfter = now - 60;
15186
15495
  const validBefore = now + 3600;
@@ -15226,7 +15535,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15226
15535
  capability: "transfer:direct",
15227
15536
  note: "signed, awaiting submission"
15228
15537
  });
15229
- const proofFile = join30(this.nexusDir, "pending-transfer.json");
15538
+ const proofFile = join31(this.nexusDir, "pending-transfer.json");
15230
15539
  const proof = {
15231
15540
  from: account.address,
15232
15541
  to: targetAddress,
@@ -15268,7 +15577,7 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15268
15577
  throw new Error("prompt is required");
15269
15578
  const estimatedTokens = Math.ceil(prompt.length / 4) + 1e3;
15270
15579
  let estimatedCostSmallest = 0;
15271
- const pricingPath = join30(this.nexusDir, "pricing.json");
15580
+ const pricingPath = join31(this.nexusDir, "pricing.json");
15272
15581
  if (existsSync23(pricingPath)) {
15273
15582
  try {
15274
15583
  const pricing = JSON.parse(await readFile13(pricingPath, "utf8"));
@@ -15383,12 +15692,12 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15383
15692
  } catch {
15384
15693
  }
15385
15694
  }
15386
- const nonce = randomBytes6(16).toString("hex");
15695
+ const nonce = randomBytes7(16).toString("hex");
15387
15696
  const hash = createHash("sha256").update(`${modelName}:${nonce}:${Date.now()}`).digest("hex");
15388
15697
  const bar = (s) => "\u2588".repeat(Math.round(s / 5)) + "\u2591".repeat(20 - Math.round(s / 5));
15389
15698
  const mem = vramMb > 24e3 ? 95 : vramMb > 16e3 ? 80 : vramMb > 8e3 ? 60 : vramMb > 0 ? 40 : 20;
15390
15699
  await this.ensureDir();
15391
- await writeFile12(join30(this.nexusDir, "inference-proof.json"), JSON.stringify({
15700
+ await writeFile12(join31(this.nexusDir, "inference-proof.json"), JSON.stringify({
15392
15701
  modelName,
15393
15702
  gpuName,
15394
15703
  vramMb,
@@ -15411,14 +15720,14 @@ process.on('SIGINT', () => process.emit('SIGTERM'));
15411
15720
  });
15412
15721
 
15413
15722
  // packages/execution/dist/shellRunner.js
15414
- import { spawn as spawn12 } from "node:child_process";
15723
+ import { spawn as spawn13 } from "node:child_process";
15415
15724
  async function runShell(options) {
15416
15725
  const { command, args = [], cwd: cwd4, env, timeoutMs = DEFAULT_TIMEOUT_MS } = options;
15417
15726
  const mergedEnv = env ? { ...process.env, ...env } : process.env;
15418
15727
  return new Promise((resolve32) => {
15419
15728
  const start = Date.now();
15420
15729
  let timedOut = false;
15421
- const child = spawn12(command, args, {
15730
+ const child = spawn13(command, args, {
15422
15731
  cwd: cwd4,
15423
15732
  env: mergedEnv
15424
15733
  // Do NOT use shell:true — we pass command + args separately
@@ -15517,7 +15826,7 @@ var init_gitWorktree = __esm({
15517
15826
  // packages/execution/dist/patchApplier.js
15518
15827
  import { readFileSync as readFileSync17, writeFileSync as writeFileSync7, existsSync as existsSync24, mkdirSync as mkdirSync7 } from "node:fs";
15519
15828
  import { dirname as dirname11 } from "node:path";
15520
- import { spawn as spawn13 } from "node:child_process";
15829
+ import { spawn as spawn14 } from "node:child_process";
15521
15830
  async function applyPatch(patch) {
15522
15831
  switch (patch.type) {
15523
15832
  case "block-replace":
@@ -15567,7 +15876,7 @@ async function applyUnifiedDiff(patch) {
15567
15876
  function runWithStdin(options) {
15568
15877
  const { command, args, cwd: cwd4, stdin } = options;
15569
15878
  return new Promise((resolve32) => {
15570
- const child = spawn13(command, args, {
15879
+ const child = spawn14(command, args, {
15571
15880
  cwd: cwd4,
15572
15881
  stdio: ["pipe", "pipe", "pipe"]
15573
15882
  });
@@ -16051,6 +16360,7 @@ __export(dist_exports, {
16051
16360
  OpenCodeTool: () => OpenCodeTool,
16052
16361
  PdfToTextTool: () => PdfToTextTool,
16053
16362
  ReminderTool: () => ReminderTool,
16363
+ ReplTool: () => ReplTool,
16054
16364
  SchedulerTool: () => SchedulerTool,
16055
16365
  ScreenshotTool: () => ScreenshotTool,
16056
16366
  ShellTool: () => ShellTool,
@@ -16135,6 +16445,7 @@ var init_dist2 = __esm({
16135
16445
  init_transcribe_tool();
16136
16446
  init_structured_file();
16137
16447
  init_code_sandbox();
16448
+ init_repl();
16138
16449
  init_structured_read();
16139
16450
  init_vision();
16140
16451
  init_desktop_click();
@@ -16835,12 +17146,12 @@ var init_dist3 = __esm({
16835
17146
 
16836
17147
  // packages/orchestrator/dist/promptLoader.js
16837
17148
  import { readFileSync as readFileSync18, existsSync as existsSync25 } from "node:fs";
16838
- import { join as join31, dirname as dirname12 } from "node:path";
17149
+ import { join as join32, dirname as dirname12 } from "node:path";
16839
17150
  import { fileURLToPath as fileURLToPath7 } from "node:url";
16840
17151
  function loadPrompt(promptPath, vars) {
16841
17152
  let content = cache.get(promptPath);
16842
17153
  if (content === void 0) {
16843
- const fullPath = join31(PROMPTS_DIR, promptPath);
17154
+ const fullPath = join32(PROMPTS_DIR, promptPath);
16844
17155
  if (!existsSync25(fullPath)) {
16845
17156
  throw new Error(`Prompt file not found: ${fullPath}`);
16846
17157
  }
@@ -16857,7 +17168,7 @@ var init_promptLoader = __esm({
16857
17168
  "use strict";
16858
17169
  __filename = fileURLToPath7(import.meta.url);
16859
17170
  __dirname4 = dirname12(__filename);
16860
- PROMPTS_DIR = join31(__dirname4, "..", "prompts");
17171
+ PROMPTS_DIR = join32(__dirname4, "..", "prompts");
16861
17172
  cache = /* @__PURE__ */ new Map();
16862
17173
  }
16863
17174
  });
@@ -17237,7 +17548,7 @@ var init_code_retriever = __esm({
17237
17548
  import { execFile as execFile5 } from "node:child_process";
17238
17549
  import { promisify as promisify4 } from "node:util";
17239
17550
  import { readFile as readFile14, readdir as readdir4, stat as stat3 } from "node:fs/promises";
17240
- import { join as join32, extname as extname7 } from "node:path";
17551
+ import { join as join33, extname as extname7 } from "node:path";
17241
17552
  async function searchByPath(pathPattern, options) {
17242
17553
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
17243
17554
  const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
@@ -17379,7 +17690,7 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
17379
17690
  continue;
17380
17691
  if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
17381
17692
  continue;
17382
- const absPath = join32(dir, entry.name);
17693
+ const absPath = join33(dir, entry.name);
17383
17694
  if (entry.isDirectory()) {
17384
17695
  await walkForFiles(rootDir, absPath, excludeGlobs, results);
17385
17696
  } else if (entry.isFile()) {
@@ -17686,7 +17997,7 @@ var init_graphExpand = __esm({
17686
17997
 
17687
17998
  // packages/retrieval/dist/snippetPacker.js
17688
17999
  import { readFile as readFile15 } from "node:fs/promises";
17689
- import { join as join33 } from "node:path";
18000
+ import { join as join34 } from "node:path";
17690
18001
  async function packSnippets(requests, opts = {}) {
17691
18002
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
17692
18003
  const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
@@ -17712,7 +18023,7 @@ async function packSnippets(requests, opts = {}) {
17712
18023
  return { packed, dropped, totalTokens };
17713
18024
  }
17714
18025
  async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
17715
- const absPath = req.filePath.startsWith("/") ? req.filePath : join33(repoRoot, req.filePath);
18026
+ const absPath = req.filePath.startsWith("/") ? req.filePath : join34(repoRoot, req.filePath);
17716
18027
  let content;
17717
18028
  try {
17718
18029
  content = await readFile15(absPath, "utf-8");
@@ -20253,8 +20564,8 @@ ${marker}` : marker);
20253
20564
  return;
20254
20565
  try {
20255
20566
  const { mkdirSync: mkdirSync21, writeFileSync: writeFileSync20 } = __require("node:fs");
20256
- const { join: join57 } = __require("node:path");
20257
- const sessionDir = join57(this._workingDirectory, ".oa", "session", this._sessionId);
20567
+ const { join: join58 } = __require("node:path");
20568
+ const sessionDir = join58(this._workingDirectory, ".oa", "session", this._sessionId);
20258
20569
  mkdirSync21(sessionDir, { recursive: true });
20259
20570
  const checkpoint = {
20260
20571
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -20267,7 +20578,7 @@ ${marker}` : marker);
20267
20578
  memexEntryCount: this._memexArchive.size,
20268
20579
  fileRegistrySize: this._fileRegistry.size
20269
20580
  };
20270
- writeFileSync20(join57(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
20581
+ writeFileSync20(join58(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
20271
20582
  } catch {
20272
20583
  }
20273
20584
  }
@@ -21533,11 +21844,11 @@ ${transcript}`
21533
21844
  });
21534
21845
 
21535
21846
  // packages/orchestrator/dist/nexusBackend.js
21536
- import { existsSync as existsSync26, statSync as statSync9, openSync, readSync, closeSync, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "node:fs";
21847
+ import { existsSync as existsSync26, statSync as statSync9, openSync, readSync, closeSync, unlinkSync as unlinkSync4, writeFileSync as writeFileSync8 } from "node:fs";
21537
21848
  import { watch as fsWatch } from "node:fs";
21538
- import { join as join34 } from "node:path";
21539
- import { tmpdir as tmpdir6 } from "node:os";
21540
- import { randomBytes as randomBytes7 } from "node:crypto";
21849
+ import { join as join35 } from "node:path";
21850
+ import { tmpdir as tmpdir7 } from "node:os";
21851
+ import { randomBytes as randomBytes8 } from "node:crypto";
21541
21852
  var NexusAgenticBackend;
21542
21853
  var init_nexusBackend = __esm({
21543
21854
  "packages/orchestrator/dist/nexusBackend.js"() {
@@ -21685,7 +21996,7 @@ var init_nexusBackend = __esm({
21685
21996
  * Falls back to unary + word-split if streaming setup fails.
21686
21997
  */
21687
21998
  async *chatCompletionStream(request) {
21688
- const streamFile = join34(tmpdir6(), `nexus-stream-${randomBytes7(6).toString("hex")}.jsonl`);
21999
+ const streamFile = join35(tmpdir7(), `nexus-stream-${randomBytes8(6).toString("hex")}.jsonl`);
21689
22000
  writeFileSync8(streamFile, "", "utf8");
21690
22001
  const daemonArgs = {
21691
22002
  model: this.model,
@@ -21706,7 +22017,7 @@ var init_nexusBackend = __esm({
21706
22017
  } catch (sendErr) {
21707
22018
  this.consecutiveFailures++;
21708
22019
  try {
21709
- unlinkSync3(streamFile);
22020
+ unlinkSync4(streamFile);
21710
22021
  } catch {
21711
22022
  }
21712
22023
  throw sendErr;
@@ -21721,7 +22032,7 @@ var init_nexusBackend = __esm({
21721
22032
  }
21722
22033
  if (!isStreaming) {
21723
22034
  try {
21724
- unlinkSync3(streamFile);
22035
+ unlinkSync4(streamFile);
21725
22036
  } catch {
21726
22037
  }
21727
22038
  let parsed;
@@ -21877,7 +22188,7 @@ var init_nexusBackend = __esm({
21877
22188
  }
21878
22189
  } finally {
21879
22190
  try {
21880
- unlinkSync3(streamFile);
22191
+ unlinkSync4(streamFile);
21881
22192
  } catch {
21882
22193
  }
21883
22194
  }
@@ -22720,9 +23031,9 @@ __export(listen_exports, {
22720
23031
  isVideoPath: () => isVideoPath,
22721
23032
  waitForTranscribeCli: () => waitForTranscribeCli
22722
23033
  });
22723
- import { spawn as spawn14, execSync as execSync23 } from "node:child_process";
23034
+ import { spawn as spawn15, execSync as execSync23 } from "node:child_process";
22724
23035
  import { existsSync as existsSync27, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9, readdirSync as readdirSync6 } from "node:fs";
22725
- import { join as join35, dirname as dirname13 } from "node:path";
23036
+ import { join as join36, dirname as dirname13 } from "node:path";
22726
23037
  import { homedir as homedir8 } from "node:os";
22727
23038
  import { fileURLToPath as fileURLToPath8 } from "node:url";
22728
23039
  import { EventEmitter } from "node:events";
@@ -22808,12 +23119,12 @@ function findMicCaptureCommand() {
22808
23119
  function findLiveWhisperScript() {
22809
23120
  const thisDir = dirname13(fileURLToPath8(import.meta.url));
22810
23121
  const candidates = [
22811
- join35(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
22812
- join35(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
22813
- join35(thisDir, "../../execution/scripts/live-whisper.py"),
23122
+ join36(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
23123
+ join36(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
23124
+ join36(thisDir, "../../execution/scripts/live-whisper.py"),
22814
23125
  // npm install layout — scripts bundled alongside dist
22815
- join35(thisDir, "../scripts/live-whisper.py"),
22816
- join35(thisDir, "../../scripts/live-whisper.py")
23126
+ join36(thisDir, "../scripts/live-whisper.py"),
23127
+ join36(thisDir, "../../scripts/live-whisper.py")
22817
23128
  ];
22818
23129
  for (const p of candidates) {
22819
23130
  if (existsSync27(p))
@@ -22826,8 +23137,8 @@ function findLiveWhisperScript() {
22826
23137
  stdio: ["pipe", "pipe", "pipe"]
22827
23138
  }).trim();
22828
23139
  const candidates2 = [
22829
- join35(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
22830
- join35(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
23140
+ join36(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
23141
+ join36(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
22831
23142
  ];
22832
23143
  for (const p of candidates2) {
22833
23144
  if (existsSync27(p))
@@ -22835,11 +23146,11 @@ function findLiveWhisperScript() {
22835
23146
  }
22836
23147
  } catch {
22837
23148
  }
22838
- const nvmBase = join35(homedir8(), ".nvm", "versions", "node");
23149
+ const nvmBase = join36(homedir8(), ".nvm", "versions", "node");
22839
23150
  if (existsSync27(nvmBase)) {
22840
23151
  try {
22841
23152
  for (const ver of readdirSync6(nvmBase)) {
22842
- const p = join35(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
23153
+ const p = join36(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
22843
23154
  if (existsSync27(p))
22844
23155
  return p;
22845
23156
  }
@@ -22858,7 +23169,7 @@ function ensureTranscribeCliBackground() {
22858
23169
  timeout: 5e3,
22859
23170
  stdio: ["pipe", "pipe", "pipe"]
22860
23171
  }).trim();
22861
- if (existsSync27(join35(globalRoot, "transcribe-cli", "dist", "index.js"))) {
23172
+ if (existsSync27(join36(globalRoot, "transcribe-cli", "dist", "index.js"))) {
22862
23173
  return true;
22863
23174
  }
22864
23175
  } catch {
@@ -22930,7 +23241,7 @@ var init_listen = __esm({
22930
23241
  const timeout = setTimeout(() => {
22931
23242
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
22932
23243
  }, 3e5);
22933
- this.process = spawn14("python3", [
23244
+ this.process = spawn15("python3", [
22934
23245
  this.scriptPath,
22935
23246
  "--model",
22936
23247
  this.model,
@@ -23081,24 +23392,24 @@ var init_listen = __esm({
23081
23392
  timeout: 5e3,
23082
23393
  stdio: ["pipe", "pipe", "pipe"]
23083
23394
  }).trim();
23084
- const tcPath = join35(globalRoot, "transcribe-cli");
23085
- if (existsSync27(join35(tcPath, "dist", "index.js"))) {
23395
+ const tcPath = join36(globalRoot, "transcribe-cli");
23396
+ if (existsSync27(join36(tcPath, "dist", "index.js"))) {
23086
23397
  const { createRequire: createRequire4 } = await import("node:module");
23087
23398
  const req = createRequire4(import.meta.url);
23088
- return req(join35(tcPath, "dist", "index.js"));
23399
+ return req(join36(tcPath, "dist", "index.js"));
23089
23400
  }
23090
23401
  } catch {
23091
23402
  }
23092
- const nvmBase = join35(homedir8(), ".nvm", "versions", "node");
23403
+ const nvmBase = join36(homedir8(), ".nvm", "versions", "node");
23093
23404
  if (existsSync27(nvmBase)) {
23094
23405
  try {
23095
23406
  const { readdirSync: readdirSync17 } = await import("node:fs");
23096
23407
  for (const ver of readdirSync17(nvmBase)) {
23097
- const tcPath = join35(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
23098
- if (existsSync27(join35(tcPath, "dist", "index.js"))) {
23408
+ const tcPath = join36(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
23409
+ if (existsSync27(join36(tcPath, "dist", "index.js"))) {
23099
23410
  const { createRequire: createRequire4 } = await import("node:module");
23100
23411
  const req = createRequire4(import.meta.url);
23101
- return req(join35(tcPath, "dist", "index.js"));
23412
+ return req(join36(tcPath, "dist", "index.js"));
23102
23413
  }
23103
23414
  }
23104
23415
  } catch {
@@ -23212,7 +23523,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
23212
23523
  return `Failed to start live transcription: ${msg}${tcHint}`;
23213
23524
  }
23214
23525
  }
23215
- this.micProcess = spawn14(micCmd.cmd, micCmd.args, {
23526
+ this.micProcess = spawn15(micCmd.cmd, micCmd.args, {
23216
23527
  stdio: ["pipe", "pipe", "pipe"],
23217
23528
  env: { ...process.env }
23218
23529
  });
@@ -23380,9 +23691,9 @@ transcribe-cli error: ${transcribeCliError}` : "";
23380
23691
  });
23381
23692
  if (outputDir) {
23382
23693
  const { basename: basename16 } = await import("node:path");
23383
- const transcriptDir = join35(outputDir, ".oa", "transcripts");
23694
+ const transcriptDir = join36(outputDir, ".oa", "transcripts");
23384
23695
  mkdirSync8(transcriptDir, { recursive: true });
23385
- const outFile = join35(transcriptDir, `${basename16(filePath)}.txt`);
23696
+ const outFile = join36(transcriptDir, `${basename16(filePath)}.txt`);
23386
23697
  writeFileSync9(outFile, result.text, "utf-8");
23387
23698
  }
23388
23699
  return {
@@ -25631,7 +25942,7 @@ var require_websocket = __commonJS({
25631
25942
  var http = __require("http");
25632
25943
  var net = __require("net");
25633
25944
  var tls = __require("tls");
25634
- var { randomBytes: randomBytes11, createHash: createHash5 } = __require("crypto");
25945
+ var { randomBytes: randomBytes12, createHash: createHash5 } = __require("crypto");
25635
25946
  var { Duplex, Readable } = __require("stream");
25636
25947
  var { URL: URL3 } = __require("url");
25637
25948
  var PerMessageDeflate = require_permessage_deflate();
@@ -26161,7 +26472,7 @@ var require_websocket = __commonJS({
26161
26472
  }
26162
26473
  }
26163
26474
  const defaultPort = isSecure ? 443 : 80;
26164
- const key = randomBytes11(16).toString("base64");
26475
+ const key = randomBytes12(16).toString("base64");
26165
26476
  const request = isSecure ? https.request : http.request;
26166
26477
  const protocolSet = /* @__PURE__ */ new Set();
26167
26478
  let perMessageDeflate;
@@ -28005,8 +28316,8 @@ var init_render = __esm({
28005
28316
  });
28006
28317
 
28007
28318
  // packages/cli/dist/tui/voice-session.js
28008
- import { createServer } from "node:http";
28009
- import { spawn as spawn15, execSync as execSync24 } from "node:child_process";
28319
+ import { createServer as createServer2 } from "node:http";
28320
+ import { spawn as spawn16, execSync as execSync24 } from "node:child_process";
28010
28321
  import { EventEmitter as EventEmitter2 } from "node:events";
28011
28322
  function generateFrontendHTML() {
28012
28323
  return `<!DOCTYPE html>
@@ -28432,7 +28743,7 @@ var init_voice_session = __esm({
28432
28743
  return "Voice session already active.";
28433
28744
  const port = await this.findFreePort();
28434
28745
  this.state.localPort = port;
28435
- this.server = createServer((req, res) => this.handleHTTP(req, res));
28746
+ this.server = createServer2((req, res) => this.handleHTTP(req, res));
28436
28747
  this.server.timeout = 0;
28437
28748
  this.server.keepAliveTimeout = 0;
28438
28749
  this.wss = new import_websocket_server.default({ server: this.server, path: "/ws" });
@@ -28660,7 +28971,7 @@ var init_voice_session = __esm({
28660
28971
  const timeout = setTimeout(() => {
28661
28972
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
28662
28973
  }, 3e4);
28663
- this.cloudflaredProcess = spawn15("cloudflared", [
28974
+ this.cloudflaredProcess = spawn16("cloudflared", [
28664
28975
  "tunnel",
28665
28976
  "--url",
28666
28977
  `http://127.0.0.1:${port}`
@@ -28715,7 +29026,7 @@ var init_voice_session = __esm({
28715
29026
  // ── Helpers ───────────────────────────────────────────────────────────
28716
29027
  findFreePort() {
28717
29028
  return new Promise((resolve32, reject) => {
28718
- const srv = createServer();
29029
+ const srv = createServer2();
28719
29030
  srv.listen(0, "127.0.0.1", () => {
28720
29031
  const addr = srv.address();
28721
29032
  if (addr && typeof addr === "object") {
@@ -28733,14 +29044,14 @@ var init_voice_session = __esm({
28733
29044
  });
28734
29045
 
28735
29046
  // packages/cli/dist/tui/expose.js
28736
- import { createServer as createServer2, request as httpRequest } from "node:http";
28737
- import { spawn as spawn16, exec } from "node:child_process";
29047
+ import { createServer as createServer3, request as httpRequest } from "node:http";
29048
+ import { spawn as spawn17, exec } from "node:child_process";
28738
29049
  import { EventEmitter as EventEmitter3 } from "node:events";
28739
- import { randomBytes as randomBytes8 } from "node:crypto";
29050
+ import { randomBytes as randomBytes9 } from "node:crypto";
28740
29051
  import { URL as URL2 } from "node:url";
28741
29052
  import { loadavg, cpus, totalmem, freemem } from "node:os";
28742
- import { existsSync as existsSync28, readFileSync as readFileSync19, writeFileSync as writeFileSync10, unlinkSync as unlinkSync4, mkdirSync as mkdirSync9, readdirSync as readdirSync7, statSync as statSync10 } from "node:fs";
28743
- import { join as join36 } from "node:path";
29053
+ import { existsSync as existsSync28, readFileSync as readFileSync19, writeFileSync as writeFileSync10, unlinkSync as unlinkSync5, mkdirSync as mkdirSync9, readdirSync as readdirSync7, statSync as statSync10 } from "node:fs";
29054
+ import { join as join37 } from "node:path";
28744
29055
  function cleanForwardHeaders(raw, targetHost) {
28745
29056
  const out = {};
28746
29057
  for (const [key, value] of Object.entries(raw)) {
@@ -28768,7 +29079,7 @@ function fmtTokens(n) {
28768
29079
  }
28769
29080
  function readExposeState(stateDir) {
28770
29081
  try {
28771
- const path = join36(stateDir, STATE_FILE_NAME);
29082
+ const path = join37(stateDir, STATE_FILE_NAME);
28772
29083
  if (!existsSync28(path))
28773
29084
  return null;
28774
29085
  const raw = readFileSync19(path, "utf8");
@@ -28783,13 +29094,13 @@ function readExposeState(stateDir) {
28783
29094
  function writeExposeState(stateDir, state) {
28784
29095
  try {
28785
29096
  mkdirSync9(stateDir, { recursive: true });
28786
- writeFileSync10(join36(stateDir, STATE_FILE_NAME), JSON.stringify(state, null, 2));
29097
+ writeFileSync10(join37(stateDir, STATE_FILE_NAME), JSON.stringify(state, null, 2));
28787
29098
  } catch {
28788
29099
  }
28789
29100
  }
28790
29101
  function removeExposeState(stateDir) {
28791
29102
  try {
28792
- unlinkSync4(join36(stateDir, STATE_FILE_NAME));
29103
+ unlinkSync5(join37(stateDir, STATE_FILE_NAME));
28793
29104
  } catch {
28794
29105
  }
28795
29106
  }
@@ -28878,7 +29189,7 @@ async function collectSystemMetricsAsync() {
28878
29189
  }
28879
29190
  function readP2PExposeState(stateDir) {
28880
29191
  try {
28881
- const path = join36(stateDir, P2P_STATE_FILE_NAME);
29192
+ const path = join37(stateDir, P2P_STATE_FILE_NAME);
28882
29193
  if (!existsSync28(path))
28883
29194
  return null;
28884
29195
  const raw = readFileSync19(path, "utf8");
@@ -28893,13 +29204,13 @@ function readP2PExposeState(stateDir) {
28893
29204
  function writeP2PExposeState(stateDir, state) {
28894
29205
  try {
28895
29206
  mkdirSync9(stateDir, { recursive: true });
28896
- writeFileSync10(join36(stateDir, P2P_STATE_FILE_NAME), JSON.stringify(state, null, 2));
29207
+ writeFileSync10(join37(stateDir, P2P_STATE_FILE_NAME), JSON.stringify(state, null, 2));
28897
29208
  } catch {
28898
29209
  }
28899
29210
  }
28900
29211
  function removeP2PExposeState(stateDir) {
28901
29212
  try {
28902
- unlinkSync4(join36(stateDir, P2P_STATE_FILE_NAME));
29213
+ unlinkSync5(join37(stateDir, P2P_STATE_FILE_NAME));
28903
29214
  } catch {
28904
29215
  }
28905
29216
  }
@@ -28981,7 +29292,7 @@ var init_expose = __esm({
28981
29292
  this._stateDir = options.stateDir ?? null;
28982
29293
  this._fullAccess = options.fullAccess ?? false;
28983
29294
  if (options.authKey === void 0 || options.authKey === "") {
28984
- this._authKey = randomBytes8(24).toString("base64url");
29295
+ this._authKey = randomBytes9(24).toString("base64url");
28985
29296
  } else {
28986
29297
  this._authKey = options.authKey;
28987
29298
  }
@@ -29124,7 +29435,7 @@ var init_expose = __esm({
29124
29435
  // ── Proxy server ────────────────────────────────────────────────────────
29125
29436
  createProxyServer(localPort) {
29126
29437
  const target = new URL2(this._targetUrl);
29127
- const server = createServer2((req, res) => {
29438
+ const server = createServer3((req, res) => {
29128
29439
  res.on("error", () => {
29129
29440
  });
29130
29441
  const authHeader = req.headers.authorization;
@@ -29319,8 +29630,10 @@ var init_expose = __esm({
29319
29630
  if (responseTail.length > 2048) {
29320
29631
  responseTail = responseTail.slice(-2048);
29321
29632
  }
29322
- if (isStreaming)
29633
+ if (isStreaming) {
29323
29634
  this.emit("token_flash");
29635
+ this.emit("stream_data", { content: text, model: requestModel, peer: userIp });
29636
+ }
29324
29637
  });
29325
29638
  if (isStreaming) {
29326
29639
  if (proxyRes.statusCode !== 200) {
@@ -29398,7 +29711,7 @@ var init_expose = __esm({
29398
29711
  const timeout = setTimeout(() => {
29399
29712
  reject(new Error("Cloudflared tunnel start timeout (30s)"));
29400
29713
  }, 3e4);
29401
- this.cloudflaredProcess = spawn16("cloudflared", [
29714
+ this.cloudflaredProcess = spawn17("cloudflared", [
29402
29715
  "tunnel",
29403
29716
  "--url",
29404
29717
  `http://127.0.0.1:${port}`,
@@ -29513,7 +29826,7 @@ ${this.formatConnectionInfo()}`);
29513
29826
  // ── Helpers ─────────────────────────────────────────────────────────────
29514
29827
  findFreePort() {
29515
29828
  return new Promise((resolve32, reject) => {
29516
- const srv = createServer2();
29829
+ const srv = createServer3();
29517
29830
  srv.listen(0, "127.0.0.1", () => {
29518
29831
  const addr = srv.address();
29519
29832
  if (addr && typeof addr === "object") {
@@ -29689,7 +30002,7 @@ ${this.formatConnectionInfo()}`);
29689
30002
  this._onInfo = options.onInfo;
29690
30003
  this._onError = options.onError;
29691
30004
  if (options.authKey === void 0 || options.authKey === "") {
29692
- this._authKey = randomBytes8(24).toString("base64url");
30005
+ this._authKey = randomBytes9(24).toString("base64url");
29693
30006
  } else {
29694
30007
  this._authKey = options.authKey;
29695
30008
  }
@@ -29727,7 +30040,7 @@ ${this.formatConnectionInfo()}`);
29727
30040
  throw new Error(`Expose failed: ${exposeResult.error}`);
29728
30041
  }
29729
30042
  const nexusDir = this._nexusTool.getNexusDir();
29730
- const statusPath = join36(nexusDir, "status.json");
30043
+ const statusPath = join37(nexusDir, "status.json");
29731
30044
  for (let i = 0; i < 80; i++) {
29732
30045
  try {
29733
30046
  const raw = readFileSync19(statusPath, "utf8");
@@ -29761,7 +30074,7 @@ ${this.formatConnectionInfo()}`);
29761
30074
  });
29762
30075
  }
29763
30076
  try {
29764
- const invocDir = join36(nexusDir, "invocations");
30077
+ const invocDir = join37(nexusDir, "invocations");
29765
30078
  if (existsSync28(invocDir)) {
29766
30079
  this._prevInvocCount = readdirSync7(invocDir).filter((f) => f.endsWith(".json")).length;
29767
30080
  this._stats.totalRequests = this._prevInvocCount;
@@ -29791,7 +30104,7 @@ ${this.formatConnectionInfo()}`);
29791
30104
  if (!state)
29792
30105
  return null;
29793
30106
  const nexusDir = nexusTool.getNexusDir();
29794
- const statusPath = join36(nexusDir, "status.json");
30107
+ const statusPath = join37(nexusDir, "status.json");
29795
30108
  try {
29796
30109
  if (!existsSync28(statusPath)) {
29797
30110
  removeP2PExposeState(stateDir);
@@ -29850,7 +30163,7 @@ ${this.formatConnectionInfo()}`);
29850
30163
  let lastMeteringLineCount = 0;
29851
30164
  this._activityPollTimer = setInterval(() => {
29852
30165
  try {
29853
- const invocDir = join36(nexusDir, "invocations");
30166
+ const invocDir = join37(nexusDir, "invocations");
29854
30167
  if (!existsSync28(invocDir))
29855
30168
  return;
29856
30169
  const files = readdirSync7(invocDir).filter((f) => f.endsWith(".json"));
@@ -29866,13 +30179,13 @@ ${this.formatConnectionInfo()}`);
29866
30179
  let recentActive = 0;
29867
30180
  for (const f of files.slice(-10)) {
29868
30181
  try {
29869
- const st = statSync10(join36(invocDir, f));
30182
+ const st = statSync10(join37(invocDir, f));
29870
30183
  if (now - st.mtimeMs < 1e4)
29871
30184
  recentActive++;
29872
30185
  } catch {
29873
30186
  }
29874
30187
  }
29875
- const meteringFile = join36(nexusDir, "metering.jsonl");
30188
+ const meteringFile = join37(nexusDir, "metering.jsonl");
29876
30189
  let meteringLines = lastMeteringLineCount;
29877
30190
  try {
29878
30191
  if (existsSync28(meteringFile)) {
@@ -29902,7 +30215,7 @@ ${this.formatConnectionInfo()}`);
29902
30215
  this._activityPollTimer.unref();
29903
30216
  this._pollTimer = setInterval(() => {
29904
30217
  try {
29905
- const statusPath = join36(nexusDir, "status.json");
30218
+ const statusPath = join37(nexusDir, "status.json");
29906
30219
  if (existsSync28(statusPath)) {
29907
30220
  const status = JSON.parse(readFileSync19(statusPath, "utf8"));
29908
30221
  if (status.peerId && !this._peerId) {
@@ -29913,7 +30226,7 @@ ${this.formatConnectionInfo()}`);
29913
30226
  } catch {
29914
30227
  }
29915
30228
  try {
29916
- const invocDir = join36(nexusDir, "invocations");
30229
+ const invocDir = join37(nexusDir, "invocations");
29917
30230
  if (existsSync28(invocDir)) {
29918
30231
  const files = readdirSync7(invocDir);
29919
30232
  const invocCount = files.filter((f) => f.endsWith(".json")).length;
@@ -29925,7 +30238,7 @@ ${this.formatConnectionInfo()}`);
29925
30238
  } catch {
29926
30239
  }
29927
30240
  try {
29928
- const meteringFile = join36(nexusDir, "metering.jsonl");
30241
+ const meteringFile = join37(nexusDir, "metering.jsonl");
29929
30242
  if (existsSync28(meteringFile)) {
29930
30243
  const content = readFileSync19(meteringFile, "utf8");
29931
30244
  if (content.length > lastMeteringSize) {
@@ -30135,9 +30448,9 @@ var init_types = __esm({
30135
30448
  });
30136
30449
 
30137
30450
  // packages/cli/dist/tui/p2p/secret-vault.js
30138
- import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes9, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
30451
+ import { createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes10, scryptSync as scryptSync2, createHash as createHash2 } from "node:crypto";
30139
30452
  import { readFileSync as readFileSync20, writeFileSync as writeFileSync11, existsSync as existsSync29, mkdirSync as mkdirSync10 } from "node:fs";
30140
- import { join as join37, dirname as dirname14 } from "node:path";
30453
+ import { join as join38, dirname as dirname14 } from "node:path";
30141
30454
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
30142
30455
  var init_secret_vault = __esm({
30143
30456
  "packages/cli/dist/tui/p2p/secret-vault.js"() {
@@ -30341,9 +30654,9 @@ var init_secret_vault = __esm({
30341
30654
  minTrust: s.minTrust,
30342
30655
  createdAt: s.createdAt
30343
30656
  })));
30344
- const salt = randomBytes9(SALT_LEN);
30657
+ const salt = randomBytes10(SALT_LEN);
30345
30658
  const key = scryptSync2(passphrase, salt, KEY_LEN);
30346
- const iv = randomBytes9(IV_LEN);
30659
+ const iv = randomBytes10(IV_LEN);
30347
30660
  const cipher = createCipheriv2(CIPHER_ALGO, key, iv);
30348
30661
  const encrypted = Buffer.concat([cipher.update(data, "utf8"), cipher.final()]);
30349
30662
  const tag = cipher.getAuthTag();
@@ -30400,8 +30713,8 @@ var init_secret_vault = __esm({
30400
30713
 
30401
30714
  // packages/cli/dist/tui/p2p/peer-mesh.js
30402
30715
  import { EventEmitter as EventEmitter4 } from "node:events";
30403
- import { createServer as createServer3 } from "node:http";
30404
- import { randomBytes as randomBytes10, createHash as createHash3, generateKeyPairSync } from "node:crypto";
30716
+ import { createServer as createServer4 } from "node:http";
30717
+ import { randomBytes as randomBytes11, createHash as createHash3, generateKeyPairSync } from "node:crypto";
30405
30718
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
30406
30719
  var init_peer_mesh = __esm({
30407
30720
  "packages/cli/dist/tui/p2p/peer-mesh.js"() {
@@ -30453,14 +30766,14 @@ var init_peer_mesh = __esm({
30453
30766
  this.peerId = createHash3("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
30454
30767
  this.capabilities = options.capabilities;
30455
30768
  this.displayName = options.displayName;
30456
- this._authKey = options.authKey ?? randomBytes10(24).toString("base64url");
30769
+ this._authKey = options.authKey ?? randomBytes11(24).toString("base64url");
30457
30770
  }
30458
30771
  // ── Lifecycle ───────────────────────────────────────────────────────────
30459
30772
  /** Start the mesh node — creates WS server and connects to bootstrap peers */
30460
30773
  async start() {
30461
30774
  const port = await this.findFreePort();
30462
30775
  this._port = port;
30463
- this.server = createServer3();
30776
+ this.server = createServer4();
30464
30777
  this.wss = new import_websocket_server.default({ server: this.server });
30465
30778
  this.wss.on("connection", (ws, req) => {
30466
30779
  this.handleInboundConnection(ws, req.url ?? "");
@@ -30617,7 +30930,7 @@ var init_peer_mesh = __esm({
30617
30930
  if (!ws || ws.readyState !== import_websocket.default.OPEN) {
30618
30931
  throw new Error(`Peer ${peerId} not connected`);
30619
30932
  }
30620
- const msgId = randomBytes10(8).toString("hex");
30933
+ const msgId = randomBytes11(8).toString("hex");
30621
30934
  return new Promise((resolve32, reject) => {
30622
30935
  const timeout = setTimeout(() => {
30623
30936
  this.pendingRequests.delete(msgId);
@@ -30838,7 +31151,7 @@ var init_peer_mesh = __esm({
30838
31151
  const msg = {
30839
31152
  type,
30840
31153
  from: this.peerId,
30841
- msgId: msgId ?? randomBytes10(8).toString("hex"),
31154
+ msgId: msgId ?? randomBytes11(8).toString("hex"),
30842
31155
  ts: (/* @__PURE__ */ new Date()).toISOString(),
30843
31156
  payload
30844
31157
  };
@@ -30846,7 +31159,7 @@ var init_peer_mesh = __esm({
30846
31159
  }
30847
31160
  findFreePort() {
30848
31161
  return new Promise((resolve32, reject) => {
30849
- const srv = createServer3();
31162
+ const srv = createServer4();
30850
31163
  srv.listen(0, "127.0.0.1", () => {
30851
31164
  const addr = srv.address();
30852
31165
  if (addr && typeof addr === "object") {
@@ -31474,13 +31787,13 @@ async function fetchPeerModels(peerId, authKey) {
31474
31787
  try {
31475
31788
  const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist2(), dist_exports));
31476
31789
  const { existsSync: existsSync45, readFileSync: readFileSync33 } = await import("node:fs");
31477
- const { join: join57 } = await import("node:path");
31790
+ const { join: join58 } = await import("node:path");
31478
31791
  const cwd4 = process.cwd();
31479
31792
  const nexusTool = new NexusTool2(cwd4);
31480
31793
  const nexusDir = nexusTool.getNexusDir();
31481
31794
  let isLocalPeer = false;
31482
31795
  try {
31483
- const statusPath = join57(nexusDir, "status.json");
31796
+ const statusPath = join58(nexusDir, "status.json");
31484
31797
  if (existsSync45(statusPath)) {
31485
31798
  const status = JSON.parse(readFileSync33(statusPath, "utf8"));
31486
31799
  if (status.peerId === peerId)
@@ -31489,7 +31802,7 @@ async function fetchPeerModels(peerId, authKey) {
31489
31802
  } catch {
31490
31803
  }
31491
31804
  if (isLocalPeer) {
31492
- const pricingPath = join57(nexusDir, "pricing.json");
31805
+ const pricingPath = join58(nexusDir, "pricing.json");
31493
31806
  if (existsSync45(pricingPath)) {
31494
31807
  try {
31495
31808
  const pricing = JSON.parse(readFileSync33(pricingPath, "utf8"));
@@ -31506,7 +31819,7 @@ async function fetchPeerModels(peerId, authKey) {
31506
31819
  }
31507
31820
  }
31508
31821
  }
31509
- const cachePath = join57(nexusDir, "peer-models-cache.json");
31822
+ const cachePath = join58(nexusDir, "peer-models-cache.json");
31510
31823
  if (existsSync45(cachePath)) {
31511
31824
  try {
31512
31825
  const cache4 = JSON.parse(readFileSync33(cachePath, "utf8"));
@@ -31624,7 +31937,7 @@ async function fetchPeerModels(peerId, authKey) {
31624
31937
  } catch {
31625
31938
  }
31626
31939
  if (isLocalPeer) {
31627
- const pricingPath = join57(nexusDir, "pricing.json");
31940
+ const pricingPath = join58(nexusDir, "pricing.json");
31628
31941
  if (existsSync45(pricingPath)) {
31629
31942
  try {
31630
31943
  const pricing = JSON.parse(readFileSync33(pricingPath, "utf8"));
@@ -31897,12 +32210,12 @@ var init_render2 = __esm({
31897
32210
 
31898
32211
  // packages/prompts/dist/promptLoader.js
31899
32212
  import { readFileSync as readFileSync21, existsSync as existsSync30 } from "node:fs";
31900
- import { join as join38, dirname as dirname15 } from "node:path";
32213
+ import { join as join39, dirname as dirname15 } from "node:path";
31901
32214
  import { fileURLToPath as fileURLToPath9 } from "node:url";
31902
32215
  function loadPrompt2(promptPath, vars) {
31903
32216
  let content = cache2.get(promptPath);
31904
32217
  if (content === void 0) {
31905
- const fullPath = join38(PROMPTS_DIR2, promptPath);
32218
+ const fullPath = join39(PROMPTS_DIR2, promptPath);
31906
32219
  if (!existsSync30(fullPath)) {
31907
32220
  throw new Error(`Prompt file not found: ${fullPath}`);
31908
32221
  }
@@ -31919,8 +32232,8 @@ var init_promptLoader2 = __esm({
31919
32232
  "use strict";
31920
32233
  __filename2 = fileURLToPath9(import.meta.url);
31921
32234
  __dirname5 = dirname15(__filename2);
31922
- devPath = join38(__dirname5, "..", "templates");
31923
- publishedPath = join38(__dirname5, "..", "prompts", "templates");
32235
+ devPath = join39(__dirname5, "..", "templates");
32236
+ publishedPath = join39(__dirname5, "..", "prompts", "templates");
31924
32237
  PROMPTS_DIR2 = existsSync30(devPath) ? devPath : publishedPath;
31925
32238
  cache2 = /* @__PURE__ */ new Map();
31926
32239
  }
@@ -32032,7 +32345,7 @@ var init_task_templates = __esm({
32032
32345
  });
32033
32346
 
32034
32347
  // packages/prompts/dist/index.js
32035
- import { join as join39, dirname as dirname16 } from "node:path";
32348
+ import { join as join40, dirname as dirname16 } from "node:path";
32036
32349
  import { fileURLToPath as fileURLToPath10 } from "node:url";
32037
32350
  var _dir, _packageRoot;
32038
32351
  var init_dist6 = __esm({
@@ -32043,21 +32356,21 @@ var init_dist6 = __esm({
32043
32356
  init_task_templates();
32044
32357
  init_render2();
32045
32358
  _dir = dirname16(fileURLToPath10(import.meta.url));
32046
- _packageRoot = join39(_dir, "..");
32359
+ _packageRoot = join40(_dir, "..");
32047
32360
  }
32048
32361
  });
32049
32362
 
32050
32363
  // packages/cli/dist/tui/oa-directory.js
32051
- import { existsSync as existsSync31, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync12, readdirSync as readdirSync8, statSync as statSync11, unlinkSync as unlinkSync5 } from "node:fs";
32052
- import { join as join40, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
32364
+ import { existsSync as existsSync31, mkdirSync as mkdirSync11, readFileSync as readFileSync22, writeFileSync as writeFileSync12, readdirSync as readdirSync8, statSync as statSync11, unlinkSync as unlinkSync6 } from "node:fs";
32365
+ import { join as join41, relative as relative2, basename as basename9, extname as extname8 } from "node:path";
32053
32366
  import { homedir as homedir9 } from "node:os";
32054
32367
  function initOaDirectory(repoRoot) {
32055
- const oaPath = join40(repoRoot, OA_DIR);
32368
+ const oaPath = join41(repoRoot, OA_DIR);
32056
32369
  for (const sub of SUBDIRS) {
32057
- mkdirSync11(join40(oaPath, sub), { recursive: true });
32370
+ mkdirSync11(join41(oaPath, sub), { recursive: true });
32058
32371
  }
32059
32372
  try {
32060
- const gitignorePath = join40(repoRoot, ".gitignore");
32373
+ const gitignorePath = join41(repoRoot, ".gitignore");
32061
32374
  const settingsPattern = ".oa/settings.json";
32062
32375
  if (existsSync31(gitignorePath)) {
32063
32376
  const content = readFileSync22(gitignorePath, "utf-8");
@@ -32070,10 +32383,10 @@ function initOaDirectory(repoRoot) {
32070
32383
  return oaPath;
32071
32384
  }
32072
32385
  function hasOaDirectory(repoRoot) {
32073
- return existsSync31(join40(repoRoot, OA_DIR, "index"));
32386
+ return existsSync31(join41(repoRoot, OA_DIR, "index"));
32074
32387
  }
32075
32388
  function loadProjectSettings(repoRoot) {
32076
- const settingsPath = join40(repoRoot, OA_DIR, "settings.json");
32389
+ const settingsPath = join41(repoRoot, OA_DIR, "settings.json");
32077
32390
  try {
32078
32391
  if (existsSync31(settingsPath)) {
32079
32392
  return JSON.parse(readFileSync22(settingsPath, "utf-8"));
@@ -32083,14 +32396,14 @@ function loadProjectSettings(repoRoot) {
32083
32396
  return {};
32084
32397
  }
32085
32398
  function saveProjectSettings(repoRoot, settings) {
32086
- const oaPath = join40(repoRoot, OA_DIR);
32399
+ const oaPath = join41(repoRoot, OA_DIR);
32087
32400
  mkdirSync11(oaPath, { recursive: true });
32088
32401
  const existing = loadProjectSettings(repoRoot);
32089
32402
  const merged = { ...existing, ...settings };
32090
- writeFileSync12(join40(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
32403
+ writeFileSync12(join41(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
32091
32404
  }
32092
32405
  function loadGlobalSettings() {
32093
- const settingsPath = join40(homedir9(), ".open-agents", "settings.json");
32406
+ const settingsPath = join41(homedir9(), ".open-agents", "settings.json");
32094
32407
  try {
32095
32408
  if (existsSync31(settingsPath)) {
32096
32409
  return JSON.parse(readFileSync22(settingsPath, "utf-8"));
@@ -32100,11 +32413,11 @@ function loadGlobalSettings() {
32100
32413
  return {};
32101
32414
  }
32102
32415
  function saveGlobalSettings(settings) {
32103
- const dir = join40(homedir9(), ".open-agents");
32416
+ const dir = join41(homedir9(), ".open-agents");
32104
32417
  mkdirSync11(dir, { recursive: true });
32105
32418
  const existing = loadGlobalSettings();
32106
32419
  const merged = { ...existing, ...settings };
32107
- writeFileSync12(join40(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
32420
+ writeFileSync12(join41(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
32108
32421
  }
32109
32422
  function resolveSettings(repoRoot) {
32110
32423
  const global = loadGlobalSettings();
@@ -32119,7 +32432,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
32119
32432
  while (dir && !visited.has(dir)) {
32120
32433
  visited.add(dir);
32121
32434
  for (const name of CONTEXT_FILES) {
32122
- const filePath = join40(dir, name);
32435
+ const filePath = join41(dir, name);
32123
32436
  const normalizedName = name.toLowerCase();
32124
32437
  if (existsSync31(filePath) && !seen.has(filePath)) {
32125
32438
  seen.add(filePath);
@@ -32138,7 +32451,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
32138
32451
  }
32139
32452
  }
32140
32453
  }
32141
- const projectMap = join40(dir, OA_DIR, "context", "project-map.md");
32454
+ const projectMap = join41(dir, OA_DIR, "context", "project-map.md");
32142
32455
  if (existsSync31(projectMap) && !seen.has(projectMap)) {
32143
32456
  seen.add(projectMap);
32144
32457
  try {
@@ -32154,7 +32467,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
32154
32467
  } catch {
32155
32468
  }
32156
32469
  }
32157
- const parent = join40(dir, "..");
32470
+ const parent = join41(dir, "..");
32158
32471
  if (parent === dir)
32159
32472
  break;
32160
32473
  dir = parent;
@@ -32172,7 +32485,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
32172
32485
  return found;
32173
32486
  }
32174
32487
  function readIndexMeta(repoRoot) {
32175
- const metaPath = join40(repoRoot, OA_DIR, "index", "meta.json");
32488
+ const metaPath = join41(repoRoot, OA_DIR, "index", "meta.json");
32176
32489
  try {
32177
32490
  return JSON.parse(readFileSync22(metaPath, "utf-8"));
32178
32491
  } catch {
@@ -32225,28 +32538,28 @@ ${tree}\`\`\`
32225
32538
  sections.push("");
32226
32539
  }
32227
32540
  const content = sections.join("\n");
32228
- const contextDir = join40(repoRoot, OA_DIR, "context");
32541
+ const contextDir = join41(repoRoot, OA_DIR, "context");
32229
32542
  mkdirSync11(contextDir, { recursive: true });
32230
- writeFileSync12(join40(contextDir, "project-map.md"), content, "utf-8");
32543
+ writeFileSync12(join41(contextDir, "project-map.md"), content, "utf-8");
32231
32544
  return content;
32232
32545
  }
32233
32546
  function saveSession(repoRoot, session) {
32234
- const historyDir = join40(repoRoot, OA_DIR, "history");
32547
+ const historyDir = join41(repoRoot, OA_DIR, "history");
32235
32548
  mkdirSync11(historyDir, { recursive: true });
32236
- writeFileSync12(join40(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
32549
+ writeFileSync12(join41(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
32237
32550
  }
32238
32551
  function loadRecentSessions(repoRoot, limit = 5) {
32239
- const historyDir = join40(repoRoot, OA_DIR, "history");
32552
+ const historyDir = join41(repoRoot, OA_DIR, "history");
32240
32553
  if (!existsSync31(historyDir))
32241
32554
  return [];
32242
32555
  try {
32243
32556
  const files = readdirSync8(historyDir).filter((f) => f.endsWith(".json") && f !== "pending-task.json").map((f) => {
32244
- const stat5 = statSync11(join40(historyDir, f));
32557
+ const stat5 = statSync11(join41(historyDir, f));
32245
32558
  return { file: f, mtime: stat5.mtimeMs };
32246
32559
  }).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
32247
32560
  return files.map((f) => {
32248
32561
  try {
32249
- return JSON.parse(readFileSync22(join40(historyDir, f.file), "utf-8"));
32562
+ return JSON.parse(readFileSync22(join41(historyDir, f.file), "utf-8"));
32250
32563
  } catch {
32251
32564
  return null;
32252
32565
  }
@@ -32256,18 +32569,18 @@ function loadRecentSessions(repoRoot, limit = 5) {
32256
32569
  }
32257
32570
  }
32258
32571
  function savePendingTask(repoRoot, task) {
32259
- const historyDir = join40(repoRoot, OA_DIR, "history");
32572
+ const historyDir = join41(repoRoot, OA_DIR, "history");
32260
32573
  mkdirSync11(historyDir, { recursive: true });
32261
- writeFileSync12(join40(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
32574
+ writeFileSync12(join41(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
32262
32575
  }
32263
32576
  function loadPendingTask(repoRoot) {
32264
- const filePath = join40(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
32577
+ const filePath = join41(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
32265
32578
  try {
32266
32579
  if (!existsSync31(filePath))
32267
32580
  return null;
32268
32581
  const data = JSON.parse(readFileSync22(filePath, "utf-8"));
32269
32582
  try {
32270
- unlinkSync5(filePath);
32583
+ unlinkSync6(filePath);
32271
32584
  } catch {
32272
32585
  }
32273
32586
  return data;
@@ -32276,9 +32589,9 @@ function loadPendingTask(repoRoot) {
32276
32589
  }
32277
32590
  }
32278
32591
  function saveSessionContext(repoRoot, entry) {
32279
- const contextDir = join40(repoRoot, OA_DIR, "context");
32592
+ const contextDir = join41(repoRoot, OA_DIR, "context");
32280
32593
  mkdirSync11(contextDir, { recursive: true });
32281
- const filePath = join40(contextDir, CONTEXT_SAVE_FILE);
32594
+ const filePath = join41(contextDir, CONTEXT_SAVE_FILE);
32282
32595
  let ctx;
32283
32596
  try {
32284
32597
  if (existsSync31(filePath)) {
@@ -32297,7 +32610,7 @@ function saveSessionContext(repoRoot, entry) {
32297
32610
  writeFileSync12(filePath, JSON.stringify(ctx, null, 2) + "\n", "utf-8");
32298
32611
  }
32299
32612
  function loadSessionContext(repoRoot) {
32300
- const filePath = join40(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
32613
+ const filePath = join41(repoRoot, OA_DIR, "context", CONTEXT_SAVE_FILE);
32301
32614
  try {
32302
32615
  if (!existsSync31(filePath))
32303
32616
  return null;
@@ -32348,7 +32661,7 @@ function detectManifests(repoRoot) {
32348
32661
  { file: "docker-compose.yaml", type: "Docker Compose" }
32349
32662
  ];
32350
32663
  for (const check of checks) {
32351
- const filePath = join40(repoRoot, check.file);
32664
+ const filePath = join41(repoRoot, check.file);
32352
32665
  if (existsSync31(filePath)) {
32353
32666
  let name;
32354
32667
  if (check.nameField) {
@@ -32382,7 +32695,7 @@ function findKeyFiles(repoRoot) {
32382
32695
  { pattern: "CLAUDE.md", description: "Claude Code context" }
32383
32696
  ];
32384
32697
  for (const check of checks) {
32385
- if (existsSync31(join40(repoRoot, check.pattern))) {
32698
+ if (existsSync31(join41(repoRoot, check.pattern))) {
32386
32699
  keyFiles.push({ path: check.pattern, description: check.description });
32387
32700
  }
32388
32701
  }
@@ -32408,12 +32721,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
32408
32721
  if (entry.isDirectory()) {
32409
32722
  let fileCount = 0;
32410
32723
  try {
32411
- fileCount = readdirSync8(join40(root, entry.name)).filter((f) => !f.startsWith(".")).length;
32724
+ fileCount = readdirSync8(join41(root, entry.name)).filter((f) => !f.startsWith(".")).length;
32412
32725
  } catch {
32413
32726
  }
32414
32727
  result += `${prefix}${connector}${entry.name}/ (${fileCount})
32415
32728
  `;
32416
- result += buildDirTree(join40(root, entry.name), maxDepth, childPrefix, depth + 1);
32729
+ result += buildDirTree(join41(root, entry.name), maxDepth, childPrefix, depth + 1);
32417
32730
  } else if (depth < maxDepth) {
32418
32731
  result += `${prefix}${connector}${entry.name}
32419
32732
  `;
@@ -32433,7 +32746,7 @@ function loadUsageFile(filePath) {
32433
32746
  return { records: [] };
32434
32747
  }
32435
32748
  function saveUsageFile(filePath, data) {
32436
- const dir = join40(filePath, "..");
32749
+ const dir = join41(filePath, "..");
32437
32750
  mkdirSync11(dir, { recursive: true });
32438
32751
  writeFileSync12(filePath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
32439
32752
  }
@@ -32463,15 +32776,15 @@ function recordUsage(kind, value, opts) {
32463
32776
  }
32464
32777
  saveUsageFile(filePath, data);
32465
32778
  };
32466
- update(join40(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
32779
+ update(join41(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
32467
32780
  if (opts?.repoRoot) {
32468
- update(join40(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
32781
+ update(join41(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
32469
32782
  }
32470
32783
  }
32471
32784
  function loadUsageHistory(kind, repoRoot) {
32472
- const globalPath = join40(homedir9(), ".open-agents", USAGE_HISTORY_FILE);
32785
+ const globalPath = join41(homedir9(), ".open-agents", USAGE_HISTORY_FILE);
32473
32786
  const globalData = loadUsageFile(globalPath);
32474
- const localData = repoRoot ? loadUsageFile(join40(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
32787
+ const localData = repoRoot ? loadUsageFile(join41(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
32475
32788
  const map = /* @__PURE__ */ new Map();
32476
32789
  for (const r of globalData.records) {
32477
32790
  if (r.kind !== kind)
@@ -32502,9 +32815,9 @@ function deleteUsageRecord(kind, value, repoRoot) {
32502
32815
  saveUsageFile(filePath, data);
32503
32816
  }
32504
32817
  };
32505
- remove(join40(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
32818
+ remove(join41(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
32506
32819
  if (repoRoot) {
32507
- remove(join40(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
32820
+ remove(join41(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
32508
32821
  }
32509
32822
  }
32510
32823
  var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
@@ -32552,10 +32865,10 @@ var init_oa_directory = __esm({
32552
32865
 
32553
32866
  // packages/cli/dist/tui/setup.js
32554
32867
  import * as readline from "node:readline";
32555
- import { execSync as execSync25, spawn as spawn17, exec as exec2 } from "node:child_process";
32868
+ import { execSync as execSync25, spawn as spawn18, exec as exec2 } from "node:child_process";
32556
32869
  import { promisify as promisify5 } from "node:util";
32557
32870
  import { existsSync as existsSync32, writeFileSync as writeFileSync13, readFileSync as readFileSync23, appendFileSync as appendFileSync2, mkdirSync as mkdirSync12 } from "node:fs";
32558
- import { join as join41 } from "node:path";
32871
+ import { join as join42 } from "node:path";
32559
32872
  import { homedir as homedir10, platform } from "node:os";
32560
32873
  function detectSystemSpecs() {
32561
32874
  let totalRamGB = 0;
@@ -32950,7 +33263,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
32950
33263
  process.stdout.write(` ${c2.cyan("\u25CF")} Starting ollama serve...
32951
33264
  `);
32952
33265
  try {
32953
- const child = spawn17("ollama", ["serve"], { stdio: "ignore", detached: true });
33266
+ const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
32954
33267
  child.unref();
32955
33268
  } catch {
32956
33269
  process.stdout.write(` ${c2.yellow("\u26A0")} Could not start ollama serve.
@@ -33418,7 +33731,7 @@ async function doSetup(config, rl) {
33418
33731
  ${c2.cyan("\u25CF")} Ollama is installed but not running. Starting automatically...
33419
33732
  `);
33420
33733
  try {
33421
- const child = spawn17("ollama", ["serve"], { stdio: "ignore", detached: true });
33734
+ const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
33422
33735
  child.unref();
33423
33736
  await new Promise((resolve32) => setTimeout(resolve32, 3e3));
33424
33737
  try {
@@ -33446,7 +33759,7 @@ async function doSetup(config, rl) {
33446
33759
  ${c2.cyan("\u25CF")} Starting ollama serve...
33447
33760
  `);
33448
33761
  try {
33449
- const child = spawn17("ollama", ["serve"], { stdio: "ignore", detached: true });
33762
+ const child = spawn18("ollama", ["serve"], { stdio: "ignore", detached: true });
33450
33763
  child.unref();
33451
33764
  await new Promise((resolve32) => setTimeout(resolve32, 3e3));
33452
33765
  try {
@@ -33596,9 +33909,9 @@ async function doSetup(config, rl) {
33596
33909
  `PARAMETER num_predict ${numPredict}`,
33597
33910
  `PARAMETER stop "<|endoftext|>"`
33598
33911
  ].join("\n");
33599
- const modelDir2 = join41(homedir10(), ".open-agents", "models");
33912
+ const modelDir2 = join42(homedir10(), ".open-agents", "models");
33600
33913
  mkdirSync12(modelDir2, { recursive: true });
33601
- const modelfilePath = join41(modelDir2, `Modelfile.${customName}`);
33914
+ const modelfilePath = join42(modelDir2, `Modelfile.${customName}`);
33602
33915
  writeFileSync13(modelfilePath, modelfileContent + "\n", "utf8");
33603
33916
  process.stdout.write(` ${c2.dim("Creating model...")} `);
33604
33917
  execSync25(`ollama create ${customName} -f ${modelfilePath}`, {
@@ -33644,7 +33957,7 @@ async function isModelAvailable(config) {
33644
33957
  }
33645
33958
  function isFirstRun() {
33646
33959
  try {
33647
- return !existsSync32(join41(homedir10(), ".open-agents", "config.json"));
33960
+ return !existsSync32(join42(homedir10(), ".open-agents", "config.json"));
33648
33961
  } catch {
33649
33962
  return true;
33650
33963
  }
@@ -33681,7 +33994,7 @@ function detectPkgManager() {
33681
33994
  return null;
33682
33995
  }
33683
33996
  function getVenvDir() {
33684
- return join41(homedir10(), ".open-agents", "venv");
33997
+ return join42(homedir10(), ".open-agents", "venv");
33685
33998
  }
33686
33999
  function hasVenvModule() {
33687
34000
  try {
@@ -33693,7 +34006,7 @@ function hasVenvModule() {
33693
34006
  }
33694
34007
  function ensureVenv(log) {
33695
34008
  const venvDir = getVenvDir();
33696
- const venvPip = join41(venvDir, "bin", "pip");
34009
+ const venvPip = join42(venvDir, "bin", "pip");
33697
34010
  if (existsSync32(venvPip))
33698
34011
  return venvDir;
33699
34012
  log("Creating Python venv for vision deps...");
@@ -33706,9 +34019,9 @@ function ensureVenv(log) {
33706
34019
  return null;
33707
34020
  }
33708
34021
  try {
33709
- mkdirSync12(join41(homedir10(), ".open-agents"), { recursive: true });
34022
+ mkdirSync12(join42(homedir10(), ".open-agents"), { recursive: true });
33710
34023
  execSync25(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
33711
- execSync25(`"${join41(venvDir, "bin", "pip")}" install --upgrade pip`, {
34024
+ execSync25(`"${join42(venvDir, "bin", "pip")}" install --upgrade pip`, {
33712
34025
  stdio: "pipe",
33713
34026
  timeout: 6e4
33714
34027
  });
@@ -33899,11 +34212,11 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
33899
34212
  }
33900
34213
  }
33901
34214
  const venvDir = getVenvDir();
33902
- const venvBin = join41(venvDir, "bin");
33903
- const venvMoondream = join41(venvBin, "moondream-station");
34215
+ const venvBin = join42(venvDir, "bin");
34216
+ const venvMoondream = join42(venvBin, "moondream-station");
33904
34217
  const venv = ensureVenv(log);
33905
34218
  if (venv && !hasCmd("moondream-station") && !existsSync32(venvMoondream)) {
33906
- const venvPip = join41(venvBin, "pip");
34219
+ const venvPip = join42(venvBin, "pip");
33907
34220
  log("Installing moondream-station in ~/.open-agents/venv...");
33908
34221
  try {
33909
34222
  execSync25(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
@@ -33924,8 +34237,8 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
33924
34237
  }
33925
34238
  }
33926
34239
  if (venv) {
33927
- const venvPython = join41(venvBin, "python");
33928
- const venvPip2 = join41(venvBin, "pip");
34240
+ const venvPython = join42(venvBin, "python");
34241
+ const venvPip2 = join42(venvBin, "pip");
33929
34242
  let ocrStackInstalled = false;
33930
34243
  try {
33931
34244
  execSync25(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
@@ -34069,9 +34382,9 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
34069
34382
  `PARAMETER num_predict ${numPredict}`,
34070
34383
  `PARAMETER stop "<|endoftext|>"`
34071
34384
  ].join("\n");
34072
- const modelDir2 = join41(homedir10(), ".open-agents", "models");
34385
+ const modelDir2 = join42(homedir10(), ".open-agents", "models");
34073
34386
  mkdirSync12(modelDir2, { recursive: true });
34074
- const modelfilePath = join41(modelDir2, `Modelfile.${customName}`);
34387
+ const modelfilePath = join42(modelDir2, `Modelfile.${customName}`);
34075
34388
  writeFileSync13(modelfilePath, modelfileContent + "\n", "utf8");
34076
34389
  await execAsync(`ollama create ${customName} -f ${modelfilePath}`, {
34077
34390
  timeout: 12e4
@@ -34146,8 +34459,8 @@ async function ensureNeovim() {
34146
34459
  const platform5 = process.platform;
34147
34460
  const arch = process.arch;
34148
34461
  if (platform5 === "linux") {
34149
- const binDir = join41(homedir10(), ".local", "bin");
34150
- const nvimDest = join41(binDir, "nvim");
34462
+ const binDir = join42(homedir10(), ".local", "bin");
34463
+ const nvimDest = join42(binDir, "nvim");
34151
34464
  try {
34152
34465
  mkdirSync12(binDir, { recursive: true });
34153
34466
  } catch {
@@ -34218,7 +34531,7 @@ async function ensureNeovim() {
34218
34531
  }
34219
34532
  function ensurePathInShellRc(binDir) {
34220
34533
  const shell = process.env.SHELL ?? "";
34221
- const rcFile = shell.includes("zsh") ? join41(homedir10(), ".zshrc") : join41(homedir10(), ".bashrc");
34534
+ const rcFile = shell.includes("zsh") ? join42(homedir10(), ".zshrc") : join42(homedir10(), ".bashrc");
34222
34535
  try {
34223
34536
  const rcContent = existsSync32(rcFile) ? readFileSync23(rcFile, "utf8") : "";
34224
34537
  if (rcContent.includes(binDir))
@@ -34988,9 +35301,9 @@ var init_drop_panel = __esm({
34988
35301
  });
34989
35302
 
34990
35303
  // packages/cli/dist/tui/neovim-mode.js
34991
- import { existsSync as existsSync34, unlinkSync as unlinkSync6 } from "node:fs";
34992
- import { tmpdir as tmpdir7 } from "node:os";
34993
- import { join as join42 } from "node:path";
35304
+ import { existsSync as existsSync34, unlinkSync as unlinkSync7 } from "node:fs";
35305
+ import { tmpdir as tmpdir8 } from "node:os";
35306
+ import { join as join43 } from "node:path";
34994
35307
  import { execSync as execSync26 } from "node:child_process";
34995
35308
  function isNeovimActive() {
34996
35309
  return _state !== null && !_state.cleanedUp;
@@ -35038,10 +35351,10 @@ async function startNeovimMode(opts) {
35038
35351
  );
35039
35352
  } catch {
35040
35353
  }
35041
- const socketPath = join42(tmpdir7(), `oa-nvim-${process.pid}-${Date.now()}.sock`);
35354
+ const socketPath = join43(tmpdir8(), `oa-nvim-${process.pid}-${Date.now()}.sock`);
35042
35355
  try {
35043
35356
  if (existsSync34(socketPath))
35044
- unlinkSync6(socketPath);
35357
+ unlinkSync7(socketPath);
35045
35358
  } catch {
35046
35359
  }
35047
35360
  const ptyCols = opts.cols;
@@ -35334,7 +35647,7 @@ function doCleanup(state) {
35334
35647
  }
35335
35648
  try {
35336
35649
  if (existsSync34(state.socketPath))
35337
- unlinkSync6(state.socketPath);
35650
+ unlinkSync7(state.socketPath);
35338
35651
  } catch {
35339
35652
  }
35340
35653
  if (state.stdinHandler) {
@@ -35389,9 +35702,9 @@ __export(voice_exports, {
35389
35702
  registerCustomOnnxModel: () => registerCustomOnnxModel,
35390
35703
  resetNarrationContext: () => resetNarrationContext
35391
35704
  });
35392
- import { existsSync as existsSync35, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync24, unlinkSync as unlinkSync7, readdirSync as readdirSync9, renameSync, statSync as statSync12 } from "node:fs";
35393
- import { join as join43 } from "node:path";
35394
- import { homedir as homedir11, tmpdir as tmpdir8, platform as platform2 } from "node:os";
35705
+ import { existsSync as existsSync35, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, readFileSync as readFileSync24, unlinkSync as unlinkSync8, readdirSync as readdirSync9, renameSync, statSync as statSync12 } from "node:fs";
35706
+ import { join as join44 } from "node:path";
35707
+ import { homedir as homedir11, tmpdir as tmpdir9, platform as platform2 } from "node:os";
35395
35708
  import { execSync as execSync27, spawn as nodeSpawn } from "node:child_process";
35396
35709
  import { createRequire } from "node:module";
35397
35710
  function registerCustomOnnxModel(id, label) {
@@ -35412,34 +35725,34 @@ function listVoiceModels() {
35412
35725
  }));
35413
35726
  }
35414
35727
  function voiceDir() {
35415
- return join43(homedir11(), ".open-agents", "voice");
35728
+ return join44(homedir11(), ".open-agents", "voice");
35416
35729
  }
35417
35730
  function modelsDir() {
35418
- return join43(voiceDir(), "models");
35731
+ return join44(voiceDir(), "models");
35419
35732
  }
35420
35733
  function modelDir(id) {
35421
- return join43(modelsDir(), id);
35734
+ return join44(modelsDir(), id);
35422
35735
  }
35423
35736
  function modelOnnxPath(id) {
35424
- return join43(modelDir(id), "model.onnx");
35737
+ return join44(modelDir(id), "model.onnx");
35425
35738
  }
35426
35739
  function modelConfigPath(id) {
35427
- return join43(modelDir(id), "config.json");
35740
+ return join44(modelDir(id), "config.json");
35428
35741
  }
35429
35742
  function luxttsVenvDir() {
35430
- return join43(voiceDir(), "luxtts-venv");
35743
+ return join44(voiceDir(), "luxtts-venv");
35431
35744
  }
35432
35745
  function luxttsVenvPy() {
35433
- return platform2() === "win32" ? join43(luxttsVenvDir(), "Scripts", "python.exe") : join43(luxttsVenvDir(), "bin", "python3");
35746
+ return platform2() === "win32" ? join44(luxttsVenvDir(), "Scripts", "python.exe") : join44(luxttsVenvDir(), "bin", "python3");
35434
35747
  }
35435
35748
  function luxttsRepoDir() {
35436
- return join43(voiceDir(), "LuxTTS");
35749
+ return join44(voiceDir(), "LuxTTS");
35437
35750
  }
35438
35751
  function luxttsCloneRefsDir() {
35439
- return join43(voiceDir(), "clone-refs");
35752
+ return join44(voiceDir(), "clone-refs");
35440
35753
  }
35441
35754
  function luxttsInferScript() {
35442
- return join43(voiceDir(), "luxtts-infer.py");
35755
+ return join44(voiceDir(), "luxtts-infer.py");
35443
35756
  }
35444
35757
  function emotionToPitchBias(emotion, stark = false, autist = false) {
35445
35758
  if (autist)
@@ -36247,7 +36560,7 @@ var init_voice = __esm({
36247
36560
  const refsDir = luxttsCloneRefsDir();
36248
36561
  const targets = ["glados", "overwatch"];
36249
36562
  for (const modelId of targets) {
36250
- const refFile = join43(refsDir, `${modelId}-ref.wav`);
36563
+ const refFile = join44(refsDir, `${modelId}-ref.wav`);
36251
36564
  if (existsSync35(refFile))
36252
36565
  continue;
36253
36566
  try {
@@ -36327,7 +36640,7 @@ var init_voice = __esm({
36327
36640
  }
36328
36641
  p = p.replace(/\\ /g, " ");
36329
36642
  if (p.startsWith("~/") || p === "~") {
36330
- p = join43(homedir11(), p.slice(1));
36643
+ p = join44(homedir11(), p.slice(1));
36331
36644
  }
36332
36645
  if (!existsSync35(p)) {
36333
36646
  return `File not found: ${p}
@@ -36341,7 +36654,7 @@ var init_voice = __esm({
36341
36654
  const srcName = (audioPath.split("/").pop() ?? "clone").replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]/g, "-");
36342
36655
  const ts = Date.now().toString(36);
36343
36656
  const destFilename = `clone-${srcName}-${ts}.${ext}`;
36344
- const destPath = join43(refsDir, destFilename);
36657
+ const destPath = join44(refsDir, destFilename);
36345
36658
  try {
36346
36659
  const data = readFileSync24(audioPath);
36347
36660
  writeFileSync14(destPath, data);
@@ -36386,7 +36699,7 @@ var init_voice = __esm({
36386
36699
  const refsDir = luxttsCloneRefsDir();
36387
36700
  if (!existsSync35(refsDir))
36388
36701
  mkdirSync13(refsDir, { recursive: true });
36389
- const destPath = join43(refsDir, `${sourceModelId}-ref.wav`);
36702
+ const destPath = join44(refsDir, `${sourceModelId}-ref.wav`);
36390
36703
  const sampleRate = this.config?.audio?.sample_rate ?? 22050;
36391
36704
  this.writeWav(audioData, sampleRate, destPath);
36392
36705
  this.luxttsCloneRef = destPath;
@@ -36402,7 +36715,7 @@ var init_voice = __esm({
36402
36715
  // -------------------------------------------------------------------------
36403
36716
  /** Metadata file for friendly names of clone refs */
36404
36717
  static cloneMetaFile() {
36405
- return join43(luxttsCloneRefsDir(), "meta.json");
36718
+ return join44(luxttsCloneRefsDir(), "meta.json");
36406
36719
  }
36407
36720
  loadCloneMeta() {
36408
36721
  const p = _VoiceEngine.cloneMetaFile();
@@ -36436,7 +36749,7 @@ var init_voice = __esm({
36436
36749
  return _VoiceEngine.AUDIO_EXTS.has(ext);
36437
36750
  });
36438
36751
  return files.map((f) => {
36439
- const p = join43(dir, f);
36752
+ const p = join44(dir, f);
36440
36753
  let size = 0;
36441
36754
  try {
36442
36755
  size = statSync12(p).size;
@@ -36453,11 +36766,11 @@ var init_voice = __esm({
36453
36766
  }
36454
36767
  /** Delete a clone reference file by filename. Returns true if deleted. */
36455
36768
  deleteCloneRef(filename) {
36456
- const p = join43(luxttsCloneRefsDir(), filename);
36769
+ const p = join44(luxttsCloneRefsDir(), filename);
36457
36770
  if (!existsSync35(p))
36458
36771
  return false;
36459
36772
  try {
36460
- unlinkSync7(p);
36773
+ unlinkSync8(p);
36461
36774
  const meta = this.loadCloneMeta();
36462
36775
  delete meta[filename];
36463
36776
  this.saveCloneMeta(meta);
@@ -36478,7 +36791,7 @@ var init_voice = __esm({
36478
36791
  }
36479
36792
  /** Set the active clone reference by filename. */
36480
36793
  setActiveCloneRef(filename) {
36481
- const p = join43(luxttsCloneRefsDir(), filename);
36794
+ const p = join44(luxttsCloneRefsDir(), filename);
36482
36795
  if (!existsSync35(p))
36483
36796
  return `File not found: ${filename}`;
36484
36797
  this.luxttsCloneRef = p;
@@ -36764,11 +37077,11 @@ var init_voice = __esm({
36764
37077
  }
36765
37078
  this.onPCMOutput(Buffer.from(int16.buffer), sampleRate);
36766
37079
  }
36767
- const wavPath = join43(tmpdir8(), `oa-voice-${Date.now()}.wav`);
37080
+ const wavPath = join44(tmpdir9(), `oa-voice-${Date.now()}.wav`);
36768
37081
  this.writeWav(audioData, sampleRate, wavPath);
36769
37082
  await this.playWav(wavPath);
36770
37083
  try {
36771
- unlinkSync7(wavPath);
37084
+ unlinkSync8(wavPath);
36772
37085
  } catch {
36773
37086
  }
36774
37087
  }
@@ -37013,7 +37326,7 @@ var init_voice = __esm({
37013
37326
  return new Promise((resolve32, reject) => {
37014
37327
  const proc = nodeSpawn("sh", ["-c", command], {
37015
37328
  stdio: ["ignore", "pipe", "pipe"],
37016
- cwd: tmpdir8()
37329
+ cwd: tmpdir9()
37017
37330
  });
37018
37331
  let stdout = "";
37019
37332
  let stderr = "";
@@ -37107,7 +37420,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37107
37420
  const mlxModelId = model.mlxModelId ?? "mlx-community/Kokoro-82M-bf16";
37108
37421
  const mlxVoice = model.mlxVoice ?? "af_heart";
37109
37422
  const mlxLangCode = model.mlxLangCode ?? "a";
37110
- const wavPath = join43(tmpdir8(), `oa-mlx-${Date.now()}.wav`);
37423
+ const wavPath = join44(tmpdir9(), `oa-mlx-${Date.now()}.wav`);
37111
37424
  const pyScript = [
37112
37425
  "import sys, json",
37113
37426
  "from mlx_audio.tts import generate as tts_gen",
@@ -37115,11 +37428,11 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37115
37428
  `tts_gen.main(["--model", ${JSON.stringify(mlxModelId)}, "--text", text, "--voice", ${JSON.stringify(mlxVoice)}, "--lang_code", ${JSON.stringify(mlxLangCode)}, "--audio_path", ${JSON.stringify(wavPath)}])`
37116
37429
  ].join("; ");
37117
37430
  try {
37118
- execSync27(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir8() });
37431
+ execSync27(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
37119
37432
  } catch (err) {
37120
37433
  try {
37121
37434
  const safeText = cleaned.replace(/'/g, "'\\''");
37122
- execSync27(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir8() });
37435
+ execSync27(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
37123
37436
  } catch (err2) {
37124
37437
  return;
37125
37438
  }
@@ -37154,7 +37467,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37154
37467
  }
37155
37468
  await this.playWav(wavPath);
37156
37469
  try {
37157
- unlinkSync7(wavPath);
37470
+ unlinkSync8(wavPath);
37158
37471
  } catch {
37159
37472
  }
37160
37473
  }
@@ -37175,7 +37488,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37175
37488
  const mlxModelId = model.mlxModelId ?? "mlx-community/Kokoro-82M-bf16";
37176
37489
  const mlxVoice = model.mlxVoice ?? "af_heart";
37177
37490
  const mlxLangCode = model.mlxLangCode ?? "a";
37178
- const wavPath = join43(tmpdir8(), `oa-mlx-buf-${Date.now()}.wav`);
37491
+ const wavPath = join44(tmpdir9(), `oa-mlx-buf-${Date.now()}.wav`);
37179
37492
  const pyScript = [
37180
37493
  "import sys, json",
37181
37494
  "from mlx_audio.tts import generate as tts_gen",
@@ -37183,11 +37496,11 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37183
37496
  `tts_gen.main(["--model", ${JSON.stringify(mlxModelId)}, "--text", text, "--voice", ${JSON.stringify(mlxVoice)}, "--lang_code", ${JSON.stringify(mlxLangCode)}, "--audio_path", ${JSON.stringify(wavPath)}])`
37184
37497
  ].join("; ");
37185
37498
  try {
37186
- execSync27(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir8() });
37499
+ execSync27(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
37187
37500
  } catch {
37188
37501
  try {
37189
37502
  const safeText = cleaned.replace(/'/g, "'\\''");
37190
- execSync27(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir8() });
37503
+ execSync27(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
37191
37504
  } catch {
37192
37505
  return null;
37193
37506
  }
@@ -37196,7 +37509,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37196
37509
  return null;
37197
37510
  try {
37198
37511
  const data = readFileSync24(wavPath);
37199
- unlinkSync7(wavPath);
37512
+ unlinkSync8(wavPath);
37200
37513
  return data;
37201
37514
  } catch {
37202
37515
  return null;
@@ -37286,7 +37599,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37286
37599
  }
37287
37600
  }
37288
37601
  const repoDir = luxttsRepoDir();
37289
- if (!existsSync35(join43(repoDir, "zipvoice", "luxvoice.py"))) {
37602
+ if (!existsSync35(join44(repoDir, "zipvoice", "luxvoice.py"))) {
37290
37603
  renderInfo(" Cloning LuxTTS repository...");
37291
37604
  try {
37292
37605
  if (existsSync35(repoDir)) {
@@ -37335,7 +37648,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
37335
37648
  if (!existsSync35(refsDir))
37336
37649
  return;
37337
37650
  for (const name of ["custom-clone.wav", "custom-clone.mp3", "glados-ref.wav", "overwatch-ref.wav"]) {
37338
- const p = join43(refsDir, name);
37651
+ const p = join44(refsDir, name);
37339
37652
  if (existsSync35(p)) {
37340
37653
  this.luxttsCloneRef = p;
37341
37654
  return;
@@ -37450,7 +37763,7 @@ if __name__ == '__main__':
37450
37763
  const env = { ...process.env, LUXTTS_REPO_PATH: luxttsRepoDir() };
37451
37764
  const daemon = nodeSpawn(venvPy, [luxttsInferScript()], {
37452
37765
  stdio: ["pipe", "pipe", "pipe"],
37453
- cwd: tmpdir8(),
37766
+ cwd: tmpdir9(),
37454
37767
  env
37455
37768
  });
37456
37769
  this._luxttsDaemon = daemon;
@@ -37532,7 +37845,7 @@ if __name__ == '__main__':
37532
37845
  const ready = await this.ensureLuxttsDaemon();
37533
37846
  if (!ready)
37534
37847
  return;
37535
- const wavPath = join43(tmpdir8(), `oa-luxtts-${Date.now()}.wav`);
37848
+ const wavPath = join44(tmpdir9(), `oa-luxtts-${Date.now()}.wav`);
37536
37849
  try {
37537
37850
  await this.luxttsRequest({
37538
37851
  action: "synthesize",
@@ -37589,7 +37902,7 @@ if __name__ == '__main__':
37589
37902
  }
37590
37903
  await this.playWav(wavPath);
37591
37904
  try {
37592
- unlinkSync7(wavPath);
37905
+ unlinkSync8(wavPath);
37593
37906
  } catch {
37594
37907
  }
37595
37908
  }
@@ -37606,7 +37919,7 @@ if __name__ == '__main__':
37606
37919
  const ready = await this.ensureLuxttsDaemon();
37607
37920
  if (!ready)
37608
37921
  return null;
37609
- const wavPath = join43(tmpdir8(), `oa-luxtts-buf-${Date.now()}.wav`);
37922
+ const wavPath = join44(tmpdir9(), `oa-luxtts-buf-${Date.now()}.wav`);
37610
37923
  try {
37611
37924
  await this.luxttsRequest({
37612
37925
  action: "synthesize",
@@ -37622,7 +37935,7 @@ if __name__ == '__main__':
37622
37935
  return null;
37623
37936
  try {
37624
37937
  const data = readFileSync24(wavPath);
37625
- unlinkSync7(wavPath);
37938
+ unlinkSync8(wavPath);
37626
37939
  return data;
37627
37940
  } catch {
37628
37941
  return null;
@@ -37636,7 +37949,7 @@ if __name__ == '__main__':
37636
37949
  return;
37637
37950
  const arch = process.arch;
37638
37951
  mkdirSync13(voiceDir(), { recursive: true });
37639
- const pkgPath = join43(voiceDir(), "package.json");
37952
+ const pkgPath = join44(voiceDir(), "package.json");
37640
37953
  const expectedDeps = {
37641
37954
  "onnxruntime-node": "^1.21.0",
37642
37955
  "phonemizer": "^1.2.1"
@@ -37658,17 +37971,17 @@ if __name__ == '__main__':
37658
37971
  dependencies: expectedDeps
37659
37972
  }, null, 2));
37660
37973
  }
37661
- const voiceRequire = createRequire(join43(voiceDir(), "index.js"));
37974
+ const voiceRequire = createRequire(join44(voiceDir(), "index.js"));
37662
37975
  const probeOnnx = () => {
37663
37976
  try {
37664
- const result = execSync27(`node -e "try { require('onnxruntime-node'); console.log('OK'); } catch(e) { console.log('FAIL:' + e.message); }"`, { cwd: voiceDir(), stdio: "pipe", timeout: 15e3, env: { ...process.env, NODE_PATH: join43(voiceDir(), "node_modules") } });
37977
+ const result = execSync27(`node -e "try { require('onnxruntime-node'); console.log('OK'); } catch(e) { console.log('FAIL:' + e.message); }"`, { cwd: voiceDir(), stdio: "pipe", timeout: 15e3, env: { ...process.env, NODE_PATH: join44(voiceDir(), "node_modules") } });
37665
37978
  const output = result.toString().trim();
37666
37979
  return output === "OK";
37667
37980
  } catch {
37668
37981
  return false;
37669
37982
  }
37670
37983
  };
37671
- const onnxNodeModules = join43(voiceDir(), "node_modules", "onnxruntime-node");
37984
+ const onnxNodeModules = join44(voiceDir(), "node_modules", "onnxruntime-node");
37672
37985
  const onnxInstalled = existsSync35(onnxNodeModules);
37673
37986
  if (onnxInstalled && !probeOnnx()) {
37674
37987
  throw new Error(`Voice synthesis unavailable: ONNX runtime crashes on this CPU (${process.platform}-${arch}). This is a known issue with some ARM SoCs where the CPU vendor is not recognized. Voice feedback will be disabled but all other features work normally.`);
@@ -40012,8 +40325,8 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
40012
40325
  if (models.length > 0) {
40013
40326
  try {
40014
40327
  const { writeFileSync: writeFileSync20, mkdirSync: mkdirSync21 } = await import("node:fs");
40015
- const { join: join57, dirname: dirname20 } = await import("node:path");
40016
- const cachePath = join57(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
40328
+ const { join: join58, dirname: dirname20 } = await import("node:path");
40329
+ const cachePath = join58(ctx.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
40017
40330
  mkdirSync21(dirname20(cachePath), { recursive: true });
40018
40331
  writeFileSync20(cachePath, JSON.stringify({
40019
40332
  peerId,
@@ -40166,8 +40479,8 @@ Environment="OLLAMA_NUM_PARALLEL=${n}"
40166
40479
  }
40167
40480
  await new Promise((r) => setTimeout(r, 1e3));
40168
40481
  process.env.OLLAMA_NUM_PARALLEL = String(n);
40169
- const { spawn: spawn19 } = await import("node:child_process");
40170
- const child = spawn19("ollama", ["serve"], {
40482
+ const { spawn: spawn20 } = await import("node:child_process");
40483
+ const child = spawn20("ollama", ["serve"], {
40171
40484
  stdio: "ignore",
40172
40485
  detached: true,
40173
40486
  env: { ...process.env, OLLAMA_NUM_PARALLEL: String(n) }
@@ -40214,14 +40527,14 @@ async function handleUpdate(subcommand, ctx) {
40214
40527
  try {
40215
40528
  const { createRequire: createRequire4 } = await import("node:module");
40216
40529
  const { fileURLToPath: fileURLToPath14 } = await import("node:url");
40217
- const { dirname: dirname20, join: join57 } = await import("node:path");
40530
+ const { dirname: dirname20, join: join58 } = await import("node:path");
40218
40531
  const { existsSync: existsSync45 } = await import("node:fs");
40219
40532
  const req = createRequire4(import.meta.url);
40220
40533
  const thisDir = dirname20(fileURLToPath14(import.meta.url));
40221
40534
  const candidates = [
40222
- join57(thisDir, "..", "package.json"),
40223
- join57(thisDir, "..", "..", "package.json"),
40224
- join57(thisDir, "..", "..", "..", "package.json")
40535
+ join58(thisDir, "..", "package.json"),
40536
+ join58(thisDir, "..", "..", "package.json"),
40537
+ join58(thisDir, "..", "..", "..", "package.json")
40225
40538
  ];
40226
40539
  for (const pkgPath of candidates) {
40227
40540
  if (existsSync45(pkgPath)) {
@@ -40661,28 +40974,78 @@ async function showExposeDashboard(gateway, rl, ctx) {
40661
40974
  }
40662
40975
  return;
40663
40976
  }
40977
+ const cols = () => process.stdout.columns ?? 80;
40978
+ const rows = () => process.stdout.rows ?? 24;
40664
40979
  const peerLedColor = (peerIdx) => {
40665
40980
  const stops = [51, 81, 111, 141, 171, 201];
40666
40981
  const code = stops[Math.min(peerIdx, stops.length - 1)] ?? 51;
40667
40982
  return `\x1B[38;5;${code}m\u25CF\x1B[0m`;
40668
40983
  };
40669
- while (true) {
40984
+ const streamLog = [];
40985
+ const MAX_STREAM_ENTRIES = 200;
40986
+ function extractStreamContent(raw) {
40987
+ let result = "";
40988
+ const lines = raw.split("\n");
40989
+ for (const line of lines) {
40990
+ if (!line.startsWith("data: "))
40991
+ continue;
40992
+ const json = line.slice(6).trim();
40993
+ if (json === "[DONE]")
40994
+ continue;
40995
+ try {
40996
+ const obj = JSON.parse(json);
40997
+ if (obj.response)
40998
+ result += obj.response;
40999
+ else if (obj.message?.content)
41000
+ result += obj.message.content;
41001
+ else if (obj.choices?.[0]?.delta?.content)
41002
+ result += obj.choices[0].delta.content;
41003
+ } catch {
41004
+ }
41005
+ }
41006
+ return result;
41007
+ }
41008
+ const onStreamData = (data) => {
41009
+ const tokens = extractStreamContent(data.content);
41010
+ if (!tokens)
41011
+ return;
41012
+ streamLog.push({ time: Date.now(), model: data.model, peer: data.peer, content: tokens });
41013
+ if (streamLog.length > MAX_STREAM_ENTRIES)
41014
+ streamLog.splice(0, streamLog.length - MAX_STREAM_ENTRIES);
41015
+ scheduleRender();
41016
+ };
41017
+ let renderTimer = null;
41018
+ let refreshTimer = null;
41019
+ let stopped = false;
41020
+ function scheduleRender() {
41021
+ if (stopped)
41022
+ return;
41023
+ if (renderTimer)
41024
+ return;
41025
+ renderTimer = setTimeout(() => {
41026
+ renderTimer = null;
41027
+ renderDashboard();
41028
+ }, 50);
41029
+ }
41030
+ function renderDashboard() {
41031
+ if (stopped)
41032
+ return;
40670
41033
  const s = gateway.stats ?? gateway._stats;
40671
41034
  const now = Date.now();
41035
+ const w = cols();
41036
+ const h = rows();
40672
41037
  const uptime = s ? fmtUptime(now - (s.startedAt || now)) : "0s";
40673
- const statusColor = !s ? c2.dim : s.status === "active" ? c2.green : s.status === "error" ? c2.red : c2.yellow;
41038
+ const lines = [];
41039
+ const statusDot = !s ? c2.dim("\u25CF") : s.status === "active" ? c2.green("\u25CF") : s.status === "error" ? c2.red("\u25CF") : c2.yellow("\u25CF");
40674
41040
  const statusLabel = s?.status || "unknown";
40675
- const items = [];
40676
- const skipKeys = [];
40677
- items.push({ key: "hdr_status", label: selectColors.dim(`\u2500\u2500\u2500 ${statusColor("\u25CF")} ${statusLabel} uptime ${uptime} \u2500\u2500\u2500`), kind: "header" });
40678
- skipKeys.push("hdr_status");
41041
+ lines.push("");
41042
+ lines.push(` ${c2.bold("Expose Dashboard")} ${statusDot} ${statusLabel} ${c2.dim("uptime")} ${uptime} ${c2.dim((/* @__PURE__ */ new Date()).toLocaleTimeString())}`);
40679
41043
  const isTunnel = !!gateway.tunnelUrl;
40680
41044
  const isP2P = !!gateway.peerId;
40681
41045
  const endpointId = isTunnel ? gateway.tunnelUrl : isP2P ? gateway.peerId : null;
40682
41046
  const authKey = gateway.authKey ?? "";
40683
41047
  if (endpointId) {
40684
- const endpointCmd = `/endpoint ${endpointId} --auth ${authKey}`;
40685
- items.push({ key: "endpoint", label: "\u{1F517} Endpoint", detail: endpointCmd, kind: "action" });
41048
+ lines.push(` ${c2.dim("Endpoint:")} ${c2.cyan(`/endpoint ${endpointId} --auth ${authKey}`)}`);
40686
41049
  }
40687
41050
  if (s) {
40688
41051
  const totalReqs = s.totalRequests || 0;
@@ -40690,23 +41053,22 @@ async function showExposeDashboard(gateway, rl, ctx) {
40690
41053
  const tokIn = s.totalTokensIn || 0;
40691
41054
  const tokOut = s.totalTokensOut || 0;
40692
41055
  const errors = s.errors || 0;
40693
- const statsLine = `Req: ${totalReqs} Active: ${activeConns} Err: ${errors} Tok \u2191${fmtDashTokens(tokIn)} \u2193${fmtDashTokens(tokOut)}`;
40694
- items.push({ key: "info_stats", label: c2.dim(statsLine), kind: "info" });
40695
- skipKeys.push("info_stats");
41056
+ const activeDot = activeConns > 0 ? c2.green(`\u25CF ${activeConns}`) : c2.dim("0");
41057
+ lines.push("");
41058
+ lines.push(` ${c2.dim("Req")} ${c2.bold(String(totalReqs))} ${c2.dim("Active")} ${activeDot} ${c2.dim("Err")} ${errors > 0 ? c2.red(String(errors)) : c2.dim("0")} ${c2.dim("Tok")} \u2191${c2.cyan(fmtDashTokens(tokIn))} \u2193${c2.cyan(fmtDashTokens(tokOut))}`);
40696
41059
  if (s.budgetTokensTotal > 0) {
40697
41060
  const pct = Math.round(s.budgetTokensRemaining / s.budgetTokensTotal * 100);
40698
41061
  const budgetColor = pct > 50 ? c2.green : pct > 20 ? c2.yellow : c2.red;
40699
41062
  const barLen = 20;
40700
41063
  const filledLen = Math.round(pct / 100 * barLen);
40701
41064
  const bar = budgetColor("\u2588".repeat(filledLen)) + c2.dim("\u2591".repeat(barLen - filledLen));
40702
- items.push({ key: "info_budget", label: ` Budget ${bar} ${budgetColor(`${pct}%`)}`, kind: "info" });
40703
- skipKeys.push("info_budget");
41065
+ lines.push(` ${c2.dim("Budget")} ${bar} ${budgetColor(`${pct}%`)}`);
40704
41066
  }
40705
41067
  }
40706
41068
  const modelEntries = s?.modelUsage ? Array.from(s.modelUsage.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40707
41069
  if (modelEntries.length > 0) {
40708
- items.push({ key: "hdr_models", label: selectColors.dim(`\u2500\u2500\u2500 Models (${modelEntries.length}) \u2500\u2500\u2500`), kind: "header" });
40709
- skipKeys.push("hdr_models");
41070
+ lines.push("");
41071
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Models (" + modelEntries.length + ") \u2500\u2500\u2500")}`);
40710
41072
  for (const [model, count] of modelEntries) {
40711
41073
  let mIn = 0, mOut = 0;
40712
41074
  if (s?.users) {
@@ -40718,19 +41080,14 @@ async function showExposeDashboard(gateway, rl, ctx) {
40718
41080
  }
40719
41081
  }
40720
41082
  }
40721
- const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 10))) : "";
40722
- items.push({
40723
- key: `model_${model}`,
40724
- label: `${model}`,
40725
- detail: `${count} req \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`,
40726
- kind: "model"
40727
- });
41083
+ const bar = count > 0 ? c2.green("\u25AE".repeat(Math.min(count, 20))) : "";
41084
+ lines.push(` ${c2.cyan(model)} ${c2.dim(`${count}req`)} \u2191${fmtDashTokens(mIn)} \u2193${fmtDashTokens(mOut)} ${bar}`);
40728
41085
  }
40729
41086
  }
40730
41087
  const users = s?.users ? Array.from(s.users.values()) : [];
40731
41088
  if (users.length > 0) {
40732
- items.push({ key: "hdr_peers", label: selectColors.dim(`\u2500\u2500\u2500 Peers (${users.length}) \u2500\u2500\u2500`), kind: "header" });
40733
- skipKeys.push("hdr_peers");
41089
+ lines.push("");
41090
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Peers (" + users.length + ") \u2500\u2500\u2500")}`);
40734
41091
  for (let i = 0; i < users.length; i++) {
40735
41092
  const user = users[i];
40736
41093
  const ageSec = Math.floor((now - (user.firstSeen || now)) / 1e3);
@@ -40740,90 +41097,134 @@ async function showExposeDashboard(gateway, rl, ctx) {
40740
41097
  const activeFlag = (user.activeRequests || 0) > 0 ? ` ${c2.green(`\u25CF ${user.activeRequests} active`)}` : "";
40741
41098
  const led = peerLedColor(i);
40742
41099
  const peerTok = `\u2191${fmtDashTokens(user.tokensIn || 0)} \u2193${fmtDashTokens(user.tokensOut || 0)}`;
40743
- items.push({
40744
- key: `peer_${user.ip || i}`,
40745
- label: `${led} ${user.ip || "unknown"}${activeFlag}`,
40746
- detail: `${user.requests || 0}req ${peerTok} ${c2.dim(ageStr)} last: ${lastStr}`,
40747
- kind: "peer"
40748
- });
41100
+ lines.push(` ${led} ${user.ip || "unknown"}${activeFlag} ${c2.dim(`${user.requests || 0}req`)} ${peerTok} ${c2.dim(ageStr)} ${c2.dim("last:")} ${lastStr}`);
40749
41101
  }
40750
41102
  }
40751
41103
  const sys = getLocalSystemMetrics();
40752
- items.push({ key: "hdr_system", label: selectColors.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500"), kind: "header" });
40753
- skipKeys.push("hdr_system");
41104
+ lines.push("");
41105
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 System \u2500\u2500\u2500")}`);
40754
41106
  const cpuColor = sys.cpuUtil > 80 ? c2.red : sys.cpuUtil > 50 ? c2.yellow : c2.green;
40755
41107
  const memColor = sys.memUtil > 80 ? c2.red : sys.memUtil > 50 ? c2.yellow : c2.green;
40756
- let sysLine = `CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
41108
+ let sysLine = ` CPU ${cpuColor(sys.cpuUtil + "%")} (${sys.cpuCores}c) RAM ${memColor(sys.memUtil + "%")} (${sys.memUsedGB}/${sys.memTotalGB}GB)`;
40757
41109
  if (sys.gpuAvailable) {
40758
41110
  const gpuColor = sys.gpuUtil > 80 ? c2.red : sys.gpuUtil > 50 ? c2.yellow : c2.green;
40759
41111
  const vramColor = sys.vramUtil > 80 ? c2.red : sys.vramUtil > 50 ? c2.yellow : c2.green;
40760
41112
  sysLine += ` GPU ${gpuColor(sys.gpuUtil + "%")} VRAM ${vramColor(sys.vramUtil + "%")} (${sys.vramUsedMB}/${sys.vramTotalMB}MB)`;
40761
41113
  }
40762
- items.push({ key: "info_system", label: c2.dim(sysLine), kind: "info" });
40763
- skipKeys.push("info_system");
40764
- items.push({ key: "hdr_actions", label: selectColors.dim("\u2500\u2500\u2500 Actions \u2500\u2500\u2500"), kind: "header" });
40765
- skipKeys.push("hdr_actions");
40766
- items.push({ key: "refresh", label: "\u{1F504} Refresh", detail: "Rebuild dashboard with latest data", kind: "action" });
40767
- items.push({ key: "stop", label: "\u{1F6D1} Stop Gateway", detail: "Shut down the expose gateway", kind: "action" });
40768
- const result = await tuiSelect({
40769
- items,
40770
- title: "Expose Dashboard",
40771
- rl,
40772
- skipKeys,
40773
- availableRows: ctx?.availableContentRows?.()
40774
- });
40775
- if (!result.confirmed || !result.key)
40776
- break;
40777
- switch (result.key) {
40778
- case "endpoint": {
40779
- const id = isTunnel ? gateway.tunnelUrl : gateway.peerId;
40780
- const cmd = `/endpoint ${id} --auth ${authKey}`;
40781
- if (process.stdout.isTTY && id) {
40782
- const b64 = Buffer.from(cmd).toString("base64");
40783
- process.stdout.write(`\x1B]52;c;${b64}\x07`);
40784
- }
40785
- process.stdout.write(`
40786
- ${c2.bold("Endpoint command")} ${c2.dim("(copied to clipboard)")}
40787
- ${c2.cyan(cmd)}
40788
-
40789
- `);
40790
- await new Promise((resolve32) => {
40791
- const onData = () => {
40792
- process.stdin.removeListener("data", onData);
40793
- resolve32();
40794
- };
40795
- process.stdin.once("data", onData);
40796
- });
40797
- continue;
41114
+ lines.push(` ${c2.dim(sysLine)}`);
41115
+ const metricsLines = lines.length;
41116
+ const streamAreaHeight = Math.max(3, h - metricsLines - 3);
41117
+ lines.push("");
41118
+ lines.push(` ${c2.dim("\u2500\u2500\u2500 Live Token Stream \u2500\u2500\u2500")}`);
41119
+ if (streamLog.length === 0) {
41120
+ lines.push(` ${c2.dim("Waiting for streaming requests...")}`);
41121
+ for (let i = 1; i < streamAreaHeight - 1; i++)
41122
+ lines.push("");
41123
+ } else {
41124
+ const maxContentW = Math.max(20, w - 6);
41125
+ const recentEntries = [];
41126
+ for (let i = streamLog.length - 1; i >= 0 && recentEntries.length < streamAreaHeight - 1; i--) {
41127
+ const entry = streamLog[i];
41128
+ const clean = entry.content.replace(/\n/g, "\u23CE").replace(/[\x00-\x1F\x7F]/g, "");
41129
+ if (!clean)
41130
+ continue;
41131
+ const truncated = clean.length > maxContentW ? clean.slice(0, maxContentW - 1) + "\u2026" : clean;
41132
+ recentEntries.unshift(` \x1B[38;5;245m${truncated}\x1B[0m`);
41133
+ }
41134
+ while (recentEntries.length < streamAreaHeight - 1)
41135
+ recentEntries.unshift("");
41136
+ const visible = recentEntries.slice(-(streamAreaHeight - 1));
41137
+ lines.push(...visible);
41138
+ }
41139
+ const footerLine = ` ${c2.dim("q")} exit ${c2.dim("s")} stop gateway ${c2.dim("c")} copy endpoint ${c2.dim("auto-refresh 1s")}`;
41140
+ lines.push(footerLine);
41141
+ const frame = "\x1B[H\x1B[2J" + lines.join("\n") + "\n";
41142
+ overlayWrite(frame);
41143
+ }
41144
+ const onStats = () => scheduleRender();
41145
+ gateway.on("stats", onStats);
41146
+ gateway.on("stream_data", onStreamData);
41147
+ const savedRlListeners = [];
41148
+ if (rl) {
41149
+ rl.pause();
41150
+ for (const event of ["keypress", "data"]) {
41151
+ const listeners = process.stdin.listeners(event);
41152
+ for (const fn of listeners) {
41153
+ savedRlListeners.push({ event, fn });
41154
+ process.stdin.removeListener(event, fn);
41155
+ }
41156
+ }
41157
+ }
41158
+ const hadRawMode = process.stdin.isRaw;
41159
+ if (typeof process.stdin.setRawMode === "function") {
41160
+ process.stdin.setRawMode(true);
41161
+ }
41162
+ process.stdin.resume();
41163
+ enterOverlay();
41164
+ overlayWrite("\x1B[?1049h\x1B[?25l");
41165
+ renderDashboard();
41166
+ refreshTimer = setInterval(() => {
41167
+ renderDashboard();
41168
+ }, 1e3);
41169
+ let stopGateway = false;
41170
+ await new Promise((resolve32) => {
41171
+ const onData = (data) => {
41172
+ const key = data.toString();
41173
+ if (key === "q" || key === "Q" || key === "\x1B" || key === "") {
41174
+ resolve32();
41175
+ return;
40798
41176
  }
40799
- case "refresh":
40800
- continue;
40801
- // Loop rebuilds items with fresh data
40802
- case "stop":
40803
- await ctx?.exposeStop?.();
40804
- renderInfo("Expose gateway stopped.");
41177
+ if (key === "s" || key === "S") {
41178
+ stopGateway = true;
41179
+ resolve32();
40805
41180
  return;
40806
- default:
40807
- if (result.key.startsWith("peer_")) {
40808
- const peerId = result.key.slice(5);
40809
- const user = users.find((u) => (u.ip || String(users.indexOf(u))) === peerId);
40810
- if (user) {
40811
- const userModels = user.models ? Array.from(user.models.entries()).filter(([m]) => !DASH_INTERNAL.has(m)) : [];
40812
- if (userModels.length > 0) {
40813
- process.stdout.write(`
40814
- ${c2.bold(user.ip || "unknown")} \u2014 model usage:
40815
- `);
40816
- for (const [m, mm] of userModels) {
40817
- process.stdout.write(` ${c2.cyan(m)} ${c2.dim(`${mm.requests}req \u2191${fmtDashTokens(mm.tokensIn)} \u2193${fmtDashTokens(mm.tokensOut)}`)}
40818
- `);
40819
- }
40820
- process.stdout.write("\n");
40821
- }
40822
- }
40823
- continue;
41181
+ }
41182
+ if (key === "c" || key === "C") {
41183
+ const id = gateway.tunnelUrl ?? gateway.peerId ?? null;
41184
+ if (id) {
41185
+ const cmd = `/endpoint ${id} --auth ${gateway.authKey ?? ""}`;
41186
+ const b64 = Buffer.from(cmd).toString("base64");
41187
+ overlayWrite(`\x1B]52;c;${b64}\x07`);
41188
+ overlayWrite(`\x1B[${rows()}H\x1B[2K ${c2.green("\u2713 Copied to clipboard")}`);
41189
+ setTimeout(() => scheduleRender(), 1500);
40824
41190
  }
40825
- continue;
41191
+ }
41192
+ };
41193
+ process.stdin.on("data", onData);
41194
+ const cleanup = () => {
41195
+ stopped = true;
41196
+ process.stdin.removeListener("data", onData);
41197
+ };
41198
+ const origResolve = resolve32;
41199
+ resolve32 = (() => {
41200
+ cleanup();
41201
+ origResolve();
41202
+ });
41203
+ });
41204
+ if (renderTimer) {
41205
+ clearTimeout(renderTimer);
41206
+ renderTimer = null;
41207
+ }
41208
+ if (refreshTimer) {
41209
+ clearInterval(refreshTimer);
41210
+ refreshTimer = null;
41211
+ }
41212
+ gateway.removeListener("stats", onStats);
41213
+ gateway.removeListener("stream_data", onStreamData);
41214
+ overlayWrite("\x1B[?25h\x1B[?1049l");
41215
+ leaveOverlay();
41216
+ if (typeof process.stdin.setRawMode === "function") {
41217
+ process.stdin.setRawMode(hadRawMode ?? false);
41218
+ }
41219
+ if (rl) {
41220
+ for (const { event, fn } of savedRlListeners) {
41221
+ process.stdin.on(event, fn);
40826
41222
  }
41223
+ rl.resume();
41224
+ }
41225
+ if (stopGateway) {
41226
+ await ctx?.exposeStop?.();
41227
+ renderInfo("Expose gateway stopped.");
40827
41228
  }
40828
41229
  }
40829
41230
  var DASH_INTERNAL;
@@ -40842,6 +41243,7 @@ var init_commands = __esm({
40842
41243
  init_listen();
40843
41244
  init_dist();
40844
41245
  init_tui_select();
41246
+ init_overlay_lock();
40845
41247
  init_drop_panel();
40846
41248
  init_neovim_mode();
40847
41249
  DASH_INTERNAL = /* @__PURE__ */ new Set(["system_metrics", "__list_capabilities"]);
@@ -40850,7 +41252,7 @@ var init_commands = __esm({
40850
41252
 
40851
41253
  // packages/cli/dist/tui/project-context.js
40852
41254
  import { existsSync as existsSync36, readFileSync as readFileSync25, readdirSync as readdirSync10 } from "node:fs";
40853
- import { join as join44, basename as basename10 } from "node:path";
41255
+ import { join as join45, basename as basename10 } from "node:path";
40854
41256
  import { execSync as execSync28 } from "node:child_process";
40855
41257
  import { homedir as homedir12, platform as platform3, release } from "node:os";
40856
41258
  function getModelTier(modelName) {
@@ -40885,7 +41287,7 @@ function loadProjectMap(repoRoot) {
40885
41287
  if (!hasOaDirectory(repoRoot)) {
40886
41288
  initOaDirectory(repoRoot);
40887
41289
  }
40888
- const mapPath = join44(repoRoot, OA_DIR, "context", "project-map.md");
41290
+ const mapPath = join45(repoRoot, OA_DIR, "context", "project-map.md");
40889
41291
  if (existsSync36(mapPath)) {
40890
41292
  try {
40891
41293
  const content = readFileSync25(mapPath, "utf-8");
@@ -40929,17 +41331,17 @@ ${log}`);
40929
41331
  }
40930
41332
  function loadMemoryContext(repoRoot) {
40931
41333
  const sections = [];
40932
- const oaMemDir = join44(repoRoot, OA_DIR, "memory");
41334
+ const oaMemDir = join45(repoRoot, OA_DIR, "memory");
40933
41335
  const oaEntries = loadMemoryDir(oaMemDir, "project");
40934
41336
  if (oaEntries)
40935
41337
  sections.push(oaEntries);
40936
- const legacyMemDir = join44(repoRoot, ".open-agents", "memory");
41338
+ const legacyMemDir = join45(repoRoot, ".open-agents", "memory");
40937
41339
  if (legacyMemDir !== oaMemDir && existsSync36(legacyMemDir)) {
40938
41340
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
40939
41341
  if (legacyEntries)
40940
41342
  sections.push(legacyEntries);
40941
41343
  }
40942
- const globalMemDir = join44(homedir12(), ".open-agents", "memory");
41344
+ const globalMemDir = join45(homedir12(), ".open-agents", "memory");
40943
41345
  const globalEntries = loadMemoryDir(globalMemDir, "global");
40944
41346
  if (globalEntries)
40945
41347
  sections.push(globalEntries);
@@ -40953,7 +41355,7 @@ function loadMemoryDir(memDir, scope) {
40953
41355
  const files = readdirSync10(memDir).filter((f) => f.endsWith(".json"));
40954
41356
  for (const file of files.slice(0, 10)) {
40955
41357
  try {
40956
- const raw = readFileSync25(join44(memDir, file), "utf-8");
41358
+ const raw = readFileSync25(join45(memDir, file), "utf-8");
40957
41359
  const entries = JSON.parse(raw);
40958
41360
  const topic = basename10(file, ".json");
40959
41361
  const keys = Object.keys(entries);
@@ -41977,9 +42379,9 @@ var init_carousel = __esm({
41977
42379
 
41978
42380
  // packages/cli/dist/tui/carousel-descriptors.js
41979
42381
  import { existsSync as existsSync37, readFileSync as readFileSync26, writeFileSync as writeFileSync15, mkdirSync as mkdirSync14, readdirSync as readdirSync11 } from "node:fs";
41980
- import { join as join45, basename as basename11 } from "node:path";
42382
+ import { join as join46, basename as basename11 } from "node:path";
41981
42383
  function loadToolProfile(repoRoot) {
41982
- const filePath = join45(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
42384
+ const filePath = join46(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
41983
42385
  try {
41984
42386
  if (!existsSync37(filePath))
41985
42387
  return null;
@@ -41989,9 +42391,9 @@ function loadToolProfile(repoRoot) {
41989
42391
  }
41990
42392
  }
41991
42393
  function saveToolProfile(repoRoot, profile) {
41992
- const contextDir = join45(repoRoot, OA_DIR, "context");
42394
+ const contextDir = join46(repoRoot, OA_DIR, "context");
41993
42395
  mkdirSync14(contextDir, { recursive: true });
41994
- writeFileSync15(join45(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
42396
+ writeFileSync15(join46(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
41995
42397
  }
41996
42398
  function categorizeToolCall(toolName) {
41997
42399
  for (const cat of TOOL_CATEGORIES) {
@@ -42049,7 +42451,7 @@ function weightedColor(profile) {
42049
42451
  return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
42050
42452
  }
42051
42453
  function loadCachedDescriptors(repoRoot) {
42052
- const filePath = join45(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
42454
+ const filePath = join46(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
42053
42455
  try {
42054
42456
  if (!existsSync37(filePath))
42055
42457
  return null;
@@ -42060,14 +42462,14 @@ function loadCachedDescriptors(repoRoot) {
42060
42462
  }
42061
42463
  }
42062
42464
  function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
42063
- const contextDir = join45(repoRoot, OA_DIR, "context");
42465
+ const contextDir = join46(repoRoot, OA_DIR, "context");
42064
42466
  mkdirSync14(contextDir, { recursive: true });
42065
42467
  const cached = {
42066
42468
  phrases,
42067
42469
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
42068
42470
  sourceHash
42069
42471
  };
42070
- writeFileSync15(join45(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
42472
+ writeFileSync15(join46(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
42071
42473
  }
42072
42474
  function generateDescriptors(repoRoot) {
42073
42475
  const profile = loadToolProfile(repoRoot);
@@ -42115,7 +42517,7 @@ function generateDescriptors(repoRoot) {
42115
42517
  return phrases;
42116
42518
  }
42117
42519
  function extractFromPackageJson(repoRoot, tags) {
42118
- const pkgPath = join45(repoRoot, "package.json");
42520
+ const pkgPath = join46(repoRoot, "package.json");
42119
42521
  try {
42120
42522
  if (!existsSync37(pkgPath))
42121
42523
  return;
@@ -42163,7 +42565,7 @@ function extractFromManifests(repoRoot, tags) {
42163
42565
  { file: ".github/workflows", tag: "ci/cd" }
42164
42566
  ];
42165
42567
  for (const check of manifestChecks) {
42166
- if (existsSync37(join45(repoRoot, check.file))) {
42568
+ if (existsSync37(join46(repoRoot, check.file))) {
42167
42569
  tags.push(check.tag);
42168
42570
  }
42169
42571
  }
@@ -42185,7 +42587,7 @@ function extractFromSessions(repoRoot, tags) {
42185
42587
  }
42186
42588
  }
42187
42589
  function extractFromMemory(repoRoot, tags) {
42188
- const memoryDir = join45(repoRoot, OA_DIR, "memory");
42590
+ const memoryDir = join46(repoRoot, OA_DIR, "memory");
42189
42591
  try {
42190
42592
  if (!existsSync37(memoryDir))
42191
42593
  return;
@@ -42194,7 +42596,7 @@ function extractFromMemory(repoRoot, tags) {
42194
42596
  const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
42195
42597
  tags.push(topic);
42196
42598
  try {
42197
- const data = JSON.parse(readFileSync26(join45(memoryDir, file), "utf-8"));
42599
+ const data = JSON.parse(readFileSync26(join46(memoryDir, file), "utf-8"));
42198
42600
  if (data && typeof data === "object") {
42199
42601
  const keys = Object.keys(data).slice(0, 3);
42200
42602
  for (const key of keys) {
@@ -42817,10 +43219,10 @@ var init_stream_renderer = __esm({
42817
43219
 
42818
43220
  // packages/cli/dist/tui/edit-history.js
42819
43221
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync15 } from "node:fs";
42820
- import { join as join46 } from "node:path";
43222
+ import { join as join47 } from "node:path";
42821
43223
  function createEditHistoryLogger(repoRoot, sessionId) {
42822
- const historyDir = join46(repoRoot, ".oa", "history");
42823
- const logPath = join46(historyDir, "edits.jsonl");
43224
+ const historyDir = join47(repoRoot, ".oa", "history");
43225
+ const logPath = join47(historyDir, "edits.jsonl");
42824
43226
  try {
42825
43227
  mkdirSync15(historyDir, { recursive: true });
42826
43228
  } catch {
@@ -42932,12 +43334,12 @@ var init_edit_history = __esm({
42932
43334
 
42933
43335
  // packages/cli/dist/tui/promptLoader.js
42934
43336
  import { readFileSync as readFileSync27, existsSync as existsSync38 } from "node:fs";
42935
- import { join as join47, dirname as dirname17 } from "node:path";
43337
+ import { join as join48, dirname as dirname17 } from "node:path";
42936
43338
  import { fileURLToPath as fileURLToPath11 } from "node:url";
42937
43339
  function loadPrompt3(promptPath, vars) {
42938
43340
  let content = cache3.get(promptPath);
42939
43341
  if (content === void 0) {
42940
- const fullPath = join47(PROMPTS_DIR3, promptPath);
43342
+ const fullPath = join48(PROMPTS_DIR3, promptPath);
42941
43343
  if (!existsSync38(fullPath)) {
42942
43344
  throw new Error(`Prompt file not found: ${fullPath}`);
42943
43345
  }
@@ -42954,8 +43356,8 @@ var init_promptLoader3 = __esm({
42954
43356
  "use strict";
42955
43357
  __filename3 = fileURLToPath11(import.meta.url);
42956
43358
  __dirname6 = dirname17(__filename3);
42957
- devPath2 = join47(__dirname6, "..", "..", "prompts");
42958
- publishedPath2 = join47(__dirname6, "..", "prompts");
43359
+ devPath2 = join48(__dirname6, "..", "..", "prompts");
43360
+ publishedPath2 = join48(__dirname6, "..", "prompts");
42959
43361
  PROMPTS_DIR3 = existsSync38(devPath2) ? devPath2 : publishedPath2;
42960
43362
  cache3 = /* @__PURE__ */ new Map();
42961
43363
  }
@@ -42963,10 +43365,10 @@ var init_promptLoader3 = __esm({
42963
43365
 
42964
43366
  // packages/cli/dist/tui/dream-engine.js
42965
43367
  import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync16, readFileSync as readFileSync28, existsSync as existsSync39, cpSync, rmSync, readdirSync as readdirSync12 } from "node:fs";
42966
- import { join as join48, basename as basename12 } from "node:path";
43368
+ import { join as join49, basename as basename12 } from "node:path";
42967
43369
  import { execSync as execSync29 } from "node:child_process";
42968
43370
  function loadAutoresearchMemory(repoRoot) {
42969
- const memoryPath = join48(repoRoot, ".oa", "memory", "autoresearch.json");
43371
+ const memoryPath = join49(repoRoot, ".oa", "memory", "autoresearch.json");
42970
43372
  if (!existsSync39(memoryPath))
42971
43373
  return "";
42972
43374
  try {
@@ -43160,12 +43562,12 @@ var init_dream_engine = __esm({
43160
43562
  const content = String(args["content"] ?? "");
43161
43563
  if (!rawPath)
43162
43564
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
43163
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join48(this.autoresearchDir, basename12(rawPath)) : join48(this.autoresearchDir, rawPath);
43565
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join49(this.autoresearchDir, basename12(rawPath)) : join49(this.autoresearchDir, rawPath);
43164
43566
  if (!targetPath.startsWith(this.autoresearchDir)) {
43165
43567
  return { success: false, output: "", error: "Autoresearch mode: writes are confined to .oa/autoresearch/", durationMs: Date.now() - start };
43166
43568
  }
43167
43569
  try {
43168
- const dir = join48(targetPath, "..");
43570
+ const dir = join49(targetPath, "..");
43169
43571
  mkdirSync16(dir, { recursive: true });
43170
43572
  writeFileSync16(targetPath, content, "utf-8");
43171
43573
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -43195,7 +43597,7 @@ var init_dream_engine = __esm({
43195
43597
  const rawPath = String(args["path"] ?? "");
43196
43598
  const oldStr = String(args["old_string"] ?? "");
43197
43599
  const newStr = String(args["new_string"] ?? "");
43198
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join48(this.autoresearchDir, basename12(rawPath)) : join48(this.autoresearchDir, rawPath);
43600
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/autoresearch") ? join49(this.autoresearchDir, basename12(rawPath)) : join49(this.autoresearchDir, rawPath);
43199
43601
  if (!targetPath.startsWith(this.autoresearchDir)) {
43200
43602
  return { success: false, output: "", error: "Autoresearch mode: edits are confined to .oa/autoresearch/", durationMs: Date.now() - start };
43201
43603
  }
@@ -43249,12 +43651,12 @@ var init_dream_engine = __esm({
43249
43651
  const content = String(args["content"] ?? "");
43250
43652
  if (!rawPath)
43251
43653
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
43252
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join48(this.dreamsDir, basename12(rawPath)) : join48(this.dreamsDir, rawPath);
43654
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join49(this.dreamsDir, basename12(rawPath)) : join49(this.dreamsDir, rawPath);
43253
43655
  if (!targetPath.startsWith(this.dreamsDir)) {
43254
43656
  return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
43255
43657
  }
43256
43658
  try {
43257
- const dir = join48(targetPath, "..");
43659
+ const dir = join49(targetPath, "..");
43258
43660
  mkdirSync16(dir, { recursive: true });
43259
43661
  writeFileSync16(targetPath, content, "utf-8");
43260
43662
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -43284,7 +43686,7 @@ var init_dream_engine = __esm({
43284
43686
  const rawPath = String(args["path"] ?? "");
43285
43687
  const oldStr = String(args["old_string"] ?? "");
43286
43688
  const newStr = String(args["new_string"] ?? "");
43287
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join48(this.dreamsDir, basename12(rawPath)) : join48(this.dreamsDir, rawPath);
43689
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join49(this.dreamsDir, basename12(rawPath)) : join49(this.dreamsDir, rawPath);
43288
43690
  if (!targetPath.startsWith(this.dreamsDir)) {
43289
43691
  return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
43290
43692
  }
@@ -43351,7 +43753,7 @@ var init_dream_engine = __esm({
43351
43753
  constructor(config, repoRoot) {
43352
43754
  this.config = config;
43353
43755
  this.repoRoot = repoRoot;
43354
- this.dreamsDir = join48(repoRoot, ".oa", "dreams");
43756
+ this.dreamsDir = join49(repoRoot, ".oa", "dreams");
43355
43757
  this.state = {
43356
43758
  mode: "default",
43357
43759
  active: false,
@@ -43435,7 +43837,7 @@ ${result.summary}`;
43435
43837
  if (mode !== "default" || cycle === totalCycles) {
43436
43838
  renderDreamContraction(cycle);
43437
43839
  const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
43438
- const summaryPath = join48(this.dreamsDir, `cycle-${cycle}-summary.md`);
43840
+ const summaryPath = join49(this.dreamsDir, `cycle-${cycle}-summary.md`);
43439
43841
  writeFileSync16(summaryPath, cycleSummary, "utf-8");
43440
43842
  }
43441
43843
  if (mode === "lucid" && !this.abortController.signal.aborted) {
@@ -43648,7 +44050,7 @@ After synthesis, call task_complete with the final prioritized summary.`, toolMo
43648
44050
  }
43649
44051
  /** Build role-specific tool sets for swarm agents */
43650
44052
  buildSwarmTools(role, _workspace) {
43651
- const autoresearchDir = join48(this.repoRoot, ".oa", "autoresearch");
44053
+ const autoresearchDir = join49(this.repoRoot, ".oa", "autoresearch");
43652
44054
  const taskComplete = this.createSwarmTaskCompleteTool(role);
43653
44055
  switch (role) {
43654
44056
  case "researcher": {
@@ -44012,7 +44414,7 @@ INSTRUCTIONS:
44012
44414
  2. Summarize the key learnings and next steps
44013
44415
 
44014
44416
  Call task_complete with a human-readable summary of the autoresearch session.`, workspace, onEvent);
44015
- const reportPath = join48(this.dreamsDir, `cycle-${cycleNum}-autoresearch-report.md`);
44417
+ const reportPath = join49(this.dreamsDir, `cycle-${cycleNum}-autoresearch-report.md`);
44016
44418
  const report = `# Autoresearch Swarm Report \u2014 Cycle ${cycleNum}
44017
44419
 
44018
44420
  **Date**: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -44101,7 +44503,7 @@ ${summaryResult}
44101
44503
  }
44102
44504
  /** Save workspace backup for lucid mode */
44103
44505
  saveVersionCheckpoint(cycle) {
44104
- const checkpointDir = join48(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
44506
+ const checkpointDir = join49(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
44105
44507
  try {
44106
44508
  mkdirSync16(checkpointDir, { recursive: true });
44107
44509
  try {
@@ -44120,10 +44522,10 @@ ${summaryResult}
44120
44522
  encoding: "utf-8",
44121
44523
  timeout: 5e3
44122
44524
  }).trim();
44123
- writeFileSync16(join48(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
44124
- writeFileSync16(join48(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
44125
- writeFileSync16(join48(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
44126
- writeFileSync16(join48(checkpointDir, "checkpoint.json"), JSON.stringify({
44525
+ writeFileSync16(join49(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
44526
+ writeFileSync16(join49(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
44527
+ writeFileSync16(join49(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
44528
+ writeFileSync16(join49(checkpointDir, "checkpoint.json"), JSON.stringify({
44127
44529
  cycle,
44128
44530
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
44129
44531
  gitHash,
@@ -44131,7 +44533,7 @@ ${summaryResult}
44131
44533
  }, null, 2), "utf-8");
44132
44534
  renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
44133
44535
  } catch {
44134
- writeFileSync16(join48(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
44536
+ writeFileSync16(join49(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
44135
44537
  renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
44136
44538
  }
44137
44539
  } catch (err) {
@@ -44189,14 +44591,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
44189
44591
  ---
44190
44592
  *Auto-generated by open-agents dream engine*
44191
44593
  `;
44192
- writeFileSync16(join48(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
44594
+ writeFileSync16(join49(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
44193
44595
  } catch {
44194
44596
  }
44195
44597
  }
44196
44598
  /** Save dream state for resume/inspection */
44197
44599
  saveDreamState() {
44198
44600
  try {
44199
- writeFileSync16(join48(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
44601
+ writeFileSync16(join49(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
44200
44602
  } catch {
44201
44603
  }
44202
44604
  }
@@ -44570,8 +44972,8 @@ var init_bless_engine = __esm({
44570
44972
  });
44571
44973
 
44572
44974
  // packages/cli/dist/tui/dmn-engine.js
44573
- import { existsSync as existsSync40, readFileSync as readFileSync29, writeFileSync as writeFileSync17, mkdirSync as mkdirSync17, readdirSync as readdirSync13, unlinkSync as unlinkSync8 } from "node:fs";
44574
- import { join as join49, basename as basename13 } from "node:path";
44975
+ import { existsSync as existsSync40, readFileSync as readFileSync29, writeFileSync as writeFileSync17, mkdirSync as mkdirSync17, readdirSync as readdirSync13, unlinkSync as unlinkSync9 } from "node:fs";
44976
+ import { join as join50, basename as basename13 } from "node:path";
44575
44977
  function buildDMNGatherPrompt(recentTaskSummaries, dueReminders, attentionItems, memoryTopics, capabilities, competence, reflectionBuffer) {
44576
44978
  const competenceReport = competence.length > 0 ? competence.map((c3) => {
44577
44979
  const rate = c3.attempts > 0 ? Math.round(c3.successes / c3.attempts * 100) : 0;
@@ -44684,8 +45086,8 @@ var init_dmn_engine = __esm({
44684
45086
  constructor(config, repoRoot) {
44685
45087
  this.config = config;
44686
45088
  this.repoRoot = repoRoot;
44687
- this.stateDir = join49(repoRoot, ".oa", "dmn");
44688
- this.historyDir = join49(repoRoot, ".oa", "dmn", "cycles");
45089
+ this.stateDir = join50(repoRoot, ".oa", "dmn");
45090
+ this.historyDir = join50(repoRoot, ".oa", "dmn", "cycles");
44689
45091
  mkdirSync17(this.historyDir, { recursive: true });
44690
45092
  this.loadState();
44691
45093
  }
@@ -45275,8 +45677,8 @@ OUTPUT: Call task_complete with JSON:
45275
45677
  async gatherMemoryTopics() {
45276
45678
  const topics = [];
45277
45679
  const dirs = [
45278
- join49(this.repoRoot, ".oa", "memory"),
45279
- join49(this.repoRoot, ".open-agents", "memory")
45680
+ join50(this.repoRoot, ".oa", "memory"),
45681
+ join50(this.repoRoot, ".open-agents", "memory")
45280
45682
  ];
45281
45683
  for (const dir of dirs) {
45282
45684
  if (!existsSync40(dir))
@@ -45295,7 +45697,7 @@ OUTPUT: Call task_complete with JSON:
45295
45697
  }
45296
45698
  // ── State persistence ─────────────────────────────────────────────────
45297
45699
  loadState() {
45298
- const path = join49(this.stateDir, "state.json");
45700
+ const path = join50(this.stateDir, "state.json");
45299
45701
  if (existsSync40(path)) {
45300
45702
  try {
45301
45703
  this.state = JSON.parse(readFileSync29(path, "utf-8"));
@@ -45305,19 +45707,19 @@ OUTPUT: Call task_complete with JSON:
45305
45707
  }
45306
45708
  saveState() {
45307
45709
  try {
45308
- writeFileSync17(join49(this.stateDir, "state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
45710
+ writeFileSync17(join50(this.stateDir, "state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
45309
45711
  } catch {
45310
45712
  }
45311
45713
  }
45312
45714
  saveCycleResult(result) {
45313
45715
  try {
45314
45716
  const filename = `cycle-${result.cycleNumber}-${Date.now()}.json`;
45315
- writeFileSync17(join49(this.historyDir, filename), JSON.stringify(result, null, 2) + "\n", "utf-8");
45717
+ writeFileSync17(join50(this.historyDir, filename), JSON.stringify(result, null, 2) + "\n", "utf-8");
45316
45718
  const files = readdirSync13(this.historyDir).filter((f) => f.startsWith("cycle-") && f.endsWith(".json")).sort();
45317
45719
  if (files.length > 50) {
45318
45720
  for (const old of files.slice(0, files.length - 50)) {
45319
45721
  try {
45320
- unlinkSync8(join49(this.historyDir, old));
45722
+ unlinkSync9(join50(this.historyDir, old));
45321
45723
  } catch {
45322
45724
  }
45323
45725
  }
@@ -45331,7 +45733,7 @@ OUTPUT: Call task_complete with JSON:
45331
45733
 
45332
45734
  // packages/cli/dist/tui/snr-engine.js
45333
45735
  import { existsSync as existsSync41, readdirSync as readdirSync14, readFileSync as readFileSync30 } from "node:fs";
45334
- import { join as join50, basename as basename14 } from "node:path";
45736
+ import { join as join51, basename as basename14 } from "node:path";
45335
45737
  function computeDPrime(signalScores, noiseScores) {
45336
45738
  if (signalScores.length === 0 || noiseScores.length === 0)
45337
45739
  return 0;
@@ -45571,8 +45973,8 @@ Call task_complete with the JSON array when done.`, onEvent)
45571
45973
  loadMemoryEntries(topics) {
45572
45974
  const entries = [];
45573
45975
  const dirs = [
45574
- join50(this.repoRoot, ".oa", "memory"),
45575
- join50(this.repoRoot, ".open-agents", "memory")
45976
+ join51(this.repoRoot, ".oa", "memory"),
45977
+ join51(this.repoRoot, ".open-agents", "memory")
45576
45978
  ];
45577
45979
  for (const dir of dirs) {
45578
45980
  if (!existsSync41(dir))
@@ -45584,7 +45986,7 @@ Call task_complete with the JSON array when done.`, onEvent)
45584
45986
  if (topics.length > 0 && !topics.includes(topic))
45585
45987
  continue;
45586
45988
  try {
45587
- const data = JSON.parse(readFileSync30(join50(dir, f), "utf-8"));
45989
+ const data = JSON.parse(readFileSync30(join51(dir, f), "utf-8"));
45588
45990
  for (const [key, val] of Object.entries(data)) {
45589
45991
  const value = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
45590
45992
  entries.push({ topic, key, value });
@@ -46151,8 +46553,8 @@ var init_tool_policy = __esm({
46151
46553
  });
46152
46554
 
46153
46555
  // packages/cli/dist/tui/telegram-bridge.js
46154
- import { mkdirSync as mkdirSync18, existsSync as existsSync42, unlinkSync as unlinkSync9, readdirSync as readdirSync15, statSync as statSync13 } from "node:fs";
46155
- import { join as join51, resolve as resolve28 } from "node:path";
46556
+ import { mkdirSync as mkdirSync18, existsSync as existsSync42, unlinkSync as unlinkSync10, readdirSync as readdirSync15, statSync as statSync13 } from "node:fs";
46557
+ import { join as join52, resolve as resolve28 } from "node:path";
46156
46558
  import { writeFile as writeFileAsync } from "node:fs/promises";
46157
46559
  function convertMarkdownToTelegramHTML(md) {
46158
46560
  let html = md;
@@ -46917,7 +47319,7 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
46917
47319
  return null;
46918
47320
  const buffer = Buffer.from(await res.arrayBuffer());
46919
47321
  const fileName = `${Date.now()}-${fileId.slice(0, 8)}${extension}`;
46920
- const localPath = join51(this.mediaCacheDir, fileName);
47322
+ const localPath = join52(this.mediaCacheDir, fileName);
46921
47323
  await writeFileAsync(localPath, buffer);
46922
47324
  return localPath;
46923
47325
  } catch {
@@ -47005,7 +47407,7 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
47005
47407
  for (const [key, entry] of this.mediaCache) {
47006
47408
  if (now - entry.cachedAt > MEDIA_CACHE_TTL_MS) {
47007
47409
  try {
47008
- unlinkSync9(entry.localPath);
47410
+ unlinkSync10(entry.localPath);
47009
47411
  } catch {
47010
47412
  }
47011
47413
  this.mediaCache.delete(key);
@@ -47081,11 +47483,11 @@ Telegram admin: @${msg.username}` : `Telegram ${isGroup ? "group" : "public"} ch
47081
47483
  let mimeType = "audio/wav";
47082
47484
  try {
47083
47485
  const { execSync: execSyncLocal } = await import("node:child_process");
47084
- const { tmpdir: tmpdir10 } = await import("node:os");
47486
+ const { tmpdir: tmpdir11 } = await import("node:os");
47085
47487
  const { join: joinPath } = await import("node:path");
47086
47488
  const { writeFileSync: writeFs, readFileSync: readFs, unlinkSync: unlinkFs } = await import("node:fs");
47087
- const tmpWav = joinPath(tmpdir10(), `oa-tg-voice-${Date.now()}.wav`);
47088
- const tmpOgg = joinPath(tmpdir10(), `oa-tg-voice-${Date.now()}.ogg`);
47489
+ const tmpWav = joinPath(tmpdir11(), `oa-tg-voice-${Date.now()}.wav`);
47490
+ const tmpOgg = joinPath(tmpdir11(), `oa-tg-voice-${Date.now()}.ogg`);
47089
47491
  writeFs(tmpWav, wavBuffer);
47090
47492
  execSyncLocal(`ffmpeg -i "${tmpWav}" -c:a libopus -b:a 48k -ar 48000 -ac 1 "${tmpOgg}" -y 2>/dev/null`, {
47091
47493
  timeout: 15e3,
@@ -49355,7 +49757,7 @@ var init_status_bar = __esm({
49355
49757
  import * as readline2 from "node:readline";
49356
49758
  import { Writable } from "node:stream";
49357
49759
  import { cwd } from "node:process";
49358
- import { resolve as resolve29, join as join52, dirname as dirname18, extname as extname10 } from "node:path";
49760
+ import { resolve as resolve29, join as join53, dirname as dirname18, extname as extname10 } from "node:path";
49359
49761
  import { createRequire as createRequire2 } from "node:module";
49360
49762
  import { fileURLToPath as fileURLToPath12 } from "node:url";
49361
49763
  import { readFileSync as readFileSync32, writeFileSync as writeFileSync18, appendFileSync as appendFileSync4, rmSync as rmSync2, readdirSync as readdirSync16, mkdirSync as mkdirSync19 } from "node:fs";
@@ -49379,9 +49781,9 @@ function getVersion3() {
49379
49781
  const require2 = createRequire2(import.meta.url);
49380
49782
  const thisDir = dirname18(fileURLToPath12(import.meta.url));
49381
49783
  const candidates = [
49382
- join52(thisDir, "..", "package.json"),
49383
- join52(thisDir, "..", "..", "package.json"),
49384
- join52(thisDir, "..", "..", "..", "package.json")
49784
+ join53(thisDir, "..", "package.json"),
49785
+ join53(thisDir, "..", "..", "package.json"),
49786
+ join53(thisDir, "..", "..", "..", "package.json")
49385
49787
  ];
49386
49788
  for (const pkgPath of candidates) {
49387
49789
  if (existsSync43(pkgPath)) {
@@ -49472,6 +49874,8 @@ function buildTools(repoRoot, config, contextWindowSize) {
49472
49874
  new StructuredFileTool(repoRoot),
49473
49875
  // Code sandbox (isolated code execution)
49474
49876
  new CodeSandboxTool(repoRoot),
49877
+ // Persistent Python REPL — RLM (arxiv:2512.24601)
49878
+ new ReplTool(repoRoot),
49475
49879
  // Structured file reading (CSV, JSON, Markdown, binary detection)
49476
49880
  new StructuredReadTool(repoRoot),
49477
49881
  // Vision tools (Moondream — desktop awareness + point-and-click)
@@ -49591,15 +49995,15 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
49591
49995
  function gatherMemorySnippets(root) {
49592
49996
  const snippets = [];
49593
49997
  const dirs = [
49594
- join52(root, ".oa", "memory"),
49595
- join52(root, ".open-agents", "memory")
49998
+ join53(root, ".oa", "memory"),
49999
+ join53(root, ".open-agents", "memory")
49596
50000
  ];
49597
50001
  for (const dir of dirs) {
49598
50002
  if (!existsSync43(dir))
49599
50003
  continue;
49600
50004
  try {
49601
50005
  for (const f of readdirSync16(dir).filter((f2) => f2.endsWith(".json"))) {
49602
- const data = JSON.parse(readFileSync32(join52(dir, f), "utf-8"));
50006
+ const data = JSON.parse(readFileSync32(join53(dir, f), "utf-8"));
49603
50007
  for (const val of Object.values(data)) {
49604
50008
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
49605
50009
  if (v.length > 10)
@@ -49815,6 +50219,27 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
49815
50219
  tool.setActiveModel(config.model, hasVision);
49816
50220
  }
49817
50221
  }
50222
+ for (const tool of tools) {
50223
+ if ("setLlmQueryHandler" in tool && typeof tool.setLlmQueryHandler === "function") {
50224
+ tool.setLlmQueryHandler(async (prompt, context) => {
50225
+ const subPrompt = context ? `${prompt}
50226
+
50227
+ Context:
50228
+ ${context}` : prompt;
50229
+ const response = await backend.chatCompletion({
50230
+ messages: [
50231
+ { role: "system", content: "You are a helpful assistant. Respond concisely and accurately." },
50232
+ { role: "user", content: subPrompt }
50233
+ ],
50234
+ tools: [],
50235
+ temperature: 0,
50236
+ maxTokens: 4096,
50237
+ timeoutMs: 12e4
50238
+ });
50239
+ return response.choices?.[0]?.message?.content ?? "";
50240
+ });
50241
+ }
50242
+ }
49818
50243
  runner.registerTools(tools);
49819
50244
  runner.registerTool({
49820
50245
  name: "memex_retrieve",
@@ -50563,7 +50988,7 @@ async function startInteractive(config, repoPath) {
50563
50988
  let p2pGateway = null;
50564
50989
  let peerMesh = null;
50565
50990
  let inferenceRouter = null;
50566
- const secretVault = new SecretVault(join52(repoRoot, ".oa", "vault.enc"));
50991
+ const secretVault = new SecretVault(join53(repoRoot, ".oa", "vault.enc"));
50567
50992
  let adminSessionKey = null;
50568
50993
  const callSubAgents = /* @__PURE__ */ new Map();
50569
50994
  const streamRenderer = new StreamRenderer();
@@ -50772,8 +51197,8 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
50772
51197
  const hits = allCompletions.filter((c3) => c3.toLowerCase().startsWith(lower));
50773
51198
  return [hits, line];
50774
51199
  }
50775
- const HISTORY_DIR = join52(homedir13(), ".open-agents");
50776
- const HISTORY_FILE = join52(HISTORY_DIR, "repl-history");
51200
+ const HISTORY_DIR = join53(homedir13(), ".open-agents");
51201
+ const HISTORY_FILE = join53(HISTORY_DIR, "repl-history");
50777
51202
  const MAX_HISTORY_LINES = 500;
50778
51203
  let savedHistory = [];
50779
51204
  try {
@@ -50983,7 +51408,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
50983
51408
  } catch {
50984
51409
  }
50985
51410
  try {
50986
- const oaDir = join52(repoRoot, ".oa");
51411
+ const oaDir = join53(repoRoot, ".oa");
50987
51412
  const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
50988
51413
  onInfo: (msg) => writeContent(() => renderInfo(msg)),
50989
51414
  onError: (msg) => writeContent(() => renderWarning(msg))
@@ -51006,7 +51431,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
51006
51431
  } catch {
51007
51432
  }
51008
51433
  try {
51009
- const oaDir = join52(repoRoot, ".oa");
51434
+ const oaDir = join53(repoRoot, ".oa");
51010
51435
  const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
51011
51436
  onInfo: (msg) => writeContent(() => renderInfo(msg)),
51012
51437
  onError: (msg) => writeContent(() => renderWarning(msg))
@@ -51825,7 +52250,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
51825
52250
  kind,
51826
52251
  targetUrl,
51827
52252
  authKey,
51828
- stateDir: join52(repoRoot, ".oa"),
52253
+ stateDir: join53(repoRoot, ".oa"),
51829
52254
  passthrough: passthrough ?? false,
51830
52255
  loadbalance: loadbalance ?? false,
51831
52256
  endpointAuth: passthrough ? currentConfig.apiKey : void 0,
@@ -51873,7 +52298,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
51873
52298
  await tunnelGateway.stop();
51874
52299
  tunnelGateway = null;
51875
52300
  }
51876
- const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join52(repoRoot, ".oa") });
52301
+ const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join53(repoRoot, ".oa") });
51877
52302
  newTunnel.on("stats", (stats) => {
51878
52303
  statusBar.setExposeStatus({
51879
52304
  status: stats.status,
@@ -52135,7 +52560,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
52135
52560
  }
52136
52561
  },
52137
52562
  destroyProject() {
52138
- const oaPath = join52(repoRoot, OA_DIR);
52563
+ const oaPath = join53(repoRoot, OA_DIR);
52139
52564
  if (existsSync43(oaPath)) {
52140
52565
  try {
52141
52566
  rmSync2(oaPath, { recursive: true, force: true });
@@ -53070,7 +53495,7 @@ import { glob } from "glob";
53070
53495
  import ignore from "ignore";
53071
53496
  import { readFile as readFile17, stat as stat4 } from "node:fs/promises";
53072
53497
  import { createHash as createHash4 } from "node:crypto";
53073
- import { join as join53, relative as relative3, extname as extname11, basename as basename15 } from "node:path";
53498
+ import { join as join54, relative as relative3, extname as extname11, basename as basename15 } from "node:path";
53074
53499
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
53075
53500
  var init_codebase_indexer = __esm({
53076
53501
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -53114,7 +53539,7 @@ var init_codebase_indexer = __esm({
53114
53539
  const ig = ignore.default();
53115
53540
  if (this.config.respectGitignore) {
53116
53541
  try {
53117
- const gitignoreContent = await readFile17(join53(this.config.rootDir, ".gitignore"), "utf-8");
53542
+ const gitignoreContent = await readFile17(join54(this.config.rootDir, ".gitignore"), "utf-8");
53118
53543
  ig.add(gitignoreContent);
53119
53544
  } catch {
53120
53545
  }
@@ -53129,7 +53554,7 @@ var init_codebase_indexer = __esm({
53129
53554
  for (const relativePath of files) {
53130
53555
  if (ig.ignores(relativePath))
53131
53556
  continue;
53132
- const fullPath = join53(this.config.rootDir, relativePath);
53557
+ const fullPath = join54(this.config.rootDir, relativePath);
53133
53558
  try {
53134
53559
  const fileStat = await stat4(fullPath);
53135
53560
  if (fileStat.size > this.config.maxFileSize)
@@ -53175,7 +53600,7 @@ var init_codebase_indexer = __esm({
53175
53600
  if (!child) {
53176
53601
  child = {
53177
53602
  name: part,
53178
- path: join53(current.path, part),
53603
+ path: join54(current.path, part),
53179
53604
  type: "directory",
53180
53605
  children: []
53181
53606
  };
@@ -53516,7 +53941,7 @@ var config_exports = {};
53516
53941
  __export(config_exports, {
53517
53942
  configCommand: () => configCommand
53518
53943
  });
53519
- import { join as join54, resolve as resolve31 } from "node:path";
53944
+ import { join as join55, resolve as resolve31 } from "node:path";
53520
53945
  import { homedir as homedir14 } from "node:os";
53521
53946
  import { cwd as cwd3 } from "node:process";
53522
53947
  function redactIfSensitive(key, value) {
@@ -53599,7 +54024,7 @@ function handleShow(opts, config) {
53599
54024
  }
53600
54025
  }
53601
54026
  printSection("Config File");
53602
- printInfo(`~/.open-agents/config.json (${join54(homedir14(), ".open-agents", "config.json")})`);
54027
+ printInfo(`~/.open-agents/config.json (${join55(homedir14(), ".open-agents", "config.json")})`);
53603
54028
  printSection("Priority Chain");
53604
54029
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
53605
54030
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -53638,7 +54063,7 @@ function handleSet(opts, _config) {
53638
54063
  const coerced = coerceForSettings(key, value);
53639
54064
  saveProjectSettings(repoRoot, { [key]: coerced });
53640
54065
  printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value)}`);
53641
- printInfo(`Saved to ${join54(repoRoot, ".oa", "settings.json")}`);
54066
+ printInfo(`Saved to ${join55(repoRoot, ".oa", "settings.json")}`);
53642
54067
  printInfo("This override applies only when running in this workspace.");
53643
54068
  } catch (err) {
53644
54069
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -53738,7 +54163,7 @@ var serve_exports = {};
53738
54163
  __export(serve_exports, {
53739
54164
  serveCommand: () => serveCommand
53740
54165
  });
53741
- import { spawn as spawn18 } from "node:child_process";
54166
+ import { spawn as spawn19 } from "node:child_process";
53742
54167
  async function serveCommand(opts, config) {
53743
54168
  const backendType = config.backendType;
53744
54169
  if (backendType === "ollama") {
@@ -53831,7 +54256,7 @@ async function serveVllm(opts, config) {
53831
54256
  }
53832
54257
  async function runVllmServer(args, verbose) {
53833
54258
  return new Promise((resolve32, reject) => {
53834
- const child = spawn18("python", args, {
54259
+ const child = spawn19("python", args, {
53835
54260
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
53836
54261
  env: { ...process.env }
53837
54262
  });
@@ -53895,9 +54320,9 @@ var eval_exports = {};
53895
54320
  __export(eval_exports, {
53896
54321
  evalCommand: () => evalCommand
53897
54322
  });
53898
- import { tmpdir as tmpdir9 } from "node:os";
54323
+ import { tmpdir as tmpdir10 } from "node:os";
53899
54324
  import { mkdirSync as mkdirSync20, writeFileSync as writeFileSync19 } from "node:fs";
53900
- import { join as join55 } from "node:path";
54325
+ import { join as join56 } from "node:path";
53901
54326
  async function evalCommand(opts, config) {
53902
54327
  const suiteName = opts.suite ?? "basic";
53903
54328
  const suite = SUITES[suiteName];
@@ -54022,9 +54447,9 @@ async function evalCommand(opts, config) {
54022
54447
  process.exit(failed > 0 ? 1 : 0);
54023
54448
  }
54024
54449
  function createTempEvalRepo() {
54025
- const dir = join55(tmpdir9(), `open-agents-eval-${Date.now()}`);
54450
+ const dir = join56(tmpdir10(), `open-agents-eval-${Date.now()}`);
54026
54451
  mkdirSync20(dir, { recursive: true });
54027
- writeFileSync19(join55(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
54452
+ writeFileSync19(join56(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
54028
54453
  return dir;
54029
54454
  }
54030
54455
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -54084,7 +54509,7 @@ init_updater();
54084
54509
  import { parseArgs as nodeParseArgs2 } from "node:util";
54085
54510
  import { createRequire as createRequire3 } from "node:module";
54086
54511
  import { fileURLToPath as fileURLToPath13 } from "node:url";
54087
- import { dirname as dirname19, join as join56 } from "node:path";
54512
+ import { dirname as dirname19, join as join57 } from "node:path";
54088
54513
 
54089
54514
  // packages/cli/dist/cli.js
54090
54515
  import { createInterface } from "node:readline";
@@ -54191,7 +54616,7 @@ init_output();
54191
54616
  function getVersion4() {
54192
54617
  try {
54193
54618
  const require2 = createRequire3(import.meta.url);
54194
- const pkgPath = join56(dirname19(fileURLToPath13(import.meta.url)), "..", "package.json");
54619
+ const pkgPath = join57(dirname19(fileURLToPath13(import.meta.url)), "..", "package.json");
54195
54620
  const pkg = require2(pkgPath);
54196
54621
  return pkg.version;
54197
54622
  } catch {