open-agents-ai 0.30.8 → 0.31.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.
package/dist/index.js CHANGED
@@ -1284,7 +1284,7 @@ ${stdinInput ?? ""}`);
1284
1284
  }
1285
1285
  runCommand(command, timeout, stdinInput) {
1286
1286
  const start = performance.now();
1287
- return new Promise((resolve21) => {
1287
+ return new Promise((resolve22) => {
1288
1288
  const child = spawn("bash", ["-c", command], {
1289
1289
  cwd: this.workingDir,
1290
1290
  env: {
@@ -1312,7 +1312,7 @@ ${stdinInput ?? ""}`);
1312
1312
  clearTimeout(timer);
1313
1313
  if (exitFlushTimer)
1314
1314
  clearTimeout(exitFlushTimer);
1315
- resolve21(result);
1315
+ resolve22(result);
1316
1316
  };
1317
1317
  const timer = setTimeout(() => {
1318
1318
  killed = true;
@@ -4682,7 +4682,7 @@ var init_custom_tool = __esm({
4682
4682
  }
4683
4683
  /** Execute a single shell command and return output */
4684
4684
  runCommand(command) {
4685
- return new Promise((resolve21) => {
4685
+ return new Promise((resolve22) => {
4686
4686
  const child = spawn3("bash", ["-c", command], {
4687
4687
  cwd: this.workingDir,
4688
4688
  env: { ...process.env, CI: "true", NO_COLOR: "1" },
@@ -4707,11 +4707,11 @@ var init_custom_tool = __esm({
4707
4707
  child.kill("SIGTERM");
4708
4708
  } catch {
4709
4709
  }
4710
- resolve21({ success: false, output: stdout, error: "Command timed out after 60s" });
4710
+ resolve22({ success: false, output: stdout, error: "Command timed out after 60s" });
4711
4711
  }, 6e4);
4712
4712
  child.on("close", (code) => {
4713
4713
  clearTimeout(timer);
4714
- resolve21({
4714
+ resolve22({
4715
4715
  success: code === 0,
4716
4716
  output: stdout + (stderr && code === 0 ? `
4717
4717
  STDERR:
@@ -4721,7 +4721,7 @@ ${stderr}` : ""),
4721
4721
  });
4722
4722
  child.on("error", (err) => {
4723
4723
  clearTimeout(timer);
4724
- resolve21({ success: false, output: stdout, error: err.message });
4724
+ resolve22({ success: false, output: stdout, error: err.message });
4725
4725
  });
4726
4726
  });
4727
4727
  }
@@ -5903,7 +5903,7 @@ import { writeFile as writeFile7, mkdtemp, rm, readdir, stat } from "node:fs/pro
5903
5903
  import { join as join14 } from "node:path";
5904
5904
  import { tmpdir as tmpdir2 } from "node:os";
5905
5905
  function runProcess(cmd, args, options) {
5906
- return new Promise((resolve21) => {
5906
+ return new Promise((resolve22) => {
5907
5907
  const proc = spawn5(cmd, args, {
5908
5908
  cwd: options.cwd,
5909
5909
  timeout: options.timeout,
@@ -5933,7 +5933,7 @@ function runProcess(cmd, args, options) {
5933
5933
  }
5934
5934
  });
5935
5935
  proc.on("error", (err) => {
5936
- resolve21({
5936
+ resolve22({
5937
5937
  stdout,
5938
5938
  stderr: stderr || err.message,
5939
5939
  exitCode: 1,
@@ -5945,7 +5945,7 @@ function runProcess(cmd, args, options) {
5945
5945
  if (signal === "SIGTERM" || signal === "SIGKILL") {
5946
5946
  timedOut = true;
5947
5947
  }
5948
- resolve21({
5948
+ resolve22({
5949
5949
  stdout,
5950
5950
  stderr,
5951
5951
  exitCode: code ?? (timedOut ? 124 : 1),
@@ -7670,6 +7670,255 @@ ${text}`,
7670
7670
  }
7671
7671
  });
7672
7672
 
7673
+ // packages/execution/dist/tools/ocr-image-advanced.js
7674
+ import { existsSync as existsSync15, statSync as statSync8 } from "node:fs";
7675
+ import { resolve as resolve18, basename as basename7, dirname as dirname6, join as join18 } from "node:path";
7676
+ import { execSync as execSync14 } from "node:child_process";
7677
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
7678
+ import { homedir as homedir6, tmpdir as tmpdir5 } from "node:os";
7679
+ function findOcrScript() {
7680
+ const thisDir = dirname6(fileURLToPath3(import.meta.url));
7681
+ const devPath = resolve18(thisDir, "../../scripts/ocr-advanced.py");
7682
+ if (existsSync15(devPath))
7683
+ return devPath;
7684
+ const bundledPath = resolve18(thisDir, "../scripts/ocr-advanced.py");
7685
+ if (existsSync15(bundledPath))
7686
+ return bundledPath;
7687
+ const sameDirPath = resolve18(thisDir, "ocr-advanced.py");
7688
+ if (existsSync15(sameDirPath))
7689
+ return sameDirPath;
7690
+ return null;
7691
+ }
7692
+ function findPython() {
7693
+ const venvPython = join18(homedir6(), ".open-agents", "venv", "bin", "python");
7694
+ if (existsSync15(venvPython)) {
7695
+ try {
7696
+ execSync14(`${JSON.stringify(venvPython)} -c "import cv2, pytesseract, numpy, PIL"`, {
7697
+ stdio: "pipe",
7698
+ timeout: 5e3
7699
+ });
7700
+ return venvPython;
7701
+ } catch {
7702
+ }
7703
+ }
7704
+ try {
7705
+ execSync14(`python3 -c "import cv2, pytesseract, numpy, PIL"`, {
7706
+ stdio: "pipe",
7707
+ timeout: 5e3
7708
+ });
7709
+ return "python3";
7710
+ } catch {
7711
+ }
7712
+ return null;
7713
+ }
7714
+ var OcrImageAdvancedTool;
7715
+ var init_ocr_image_advanced = __esm({
7716
+ "packages/execution/dist/tools/ocr-image-advanced.js"() {
7717
+ "use strict";
7718
+ init_system_deps();
7719
+ OcrImageAdvancedTool = class {
7720
+ workingDir;
7721
+ name = "ocr_image_advanced";
7722
+ description = "Advanced OCR for images using multi-variant preprocessing and multi-PSM Tesseract pipeline. Generates 5 image preprocessing variants (adaptive threshold, OTSU, fixed threshold, sharpen+OTSU, denoise+OTSU) and runs Tesseract with 3 page segmentation modes on each, picking the best result by confidence score. Much more accurate than basic OCR for photos, scans, and documents with uneven lighting. Supports region extraction (header/body/footer) for structured documents like invoices.";
7723
+ parameters = {
7724
+ type: "object",
7725
+ properties: {
7726
+ image: {
7727
+ type: "string",
7728
+ description: "Path to the image file (JPEG, PNG, TIFF, BMP, WebP)"
7729
+ },
7730
+ language: {
7731
+ type: "string",
7732
+ description: "OCR language (default: eng). Use '+' for multiple: 'eng+fra+deu'"
7733
+ },
7734
+ regions: {
7735
+ type: "boolean",
7736
+ description: "Also extract text from header/body/footer regions separately (good for invoices, forms)"
7737
+ },
7738
+ region: {
7739
+ type: "string",
7740
+ description: "Crop to a specific region before OCR: 'x,y,w,h' in pixels"
7741
+ },
7742
+ psm: {
7743
+ type: "number",
7744
+ description: "Use a single PSM mode instead of testing all 3. Options: 4 (single block), 6 (default), 11 (sparse)"
7745
+ },
7746
+ debug: {
7747
+ type: "boolean",
7748
+ description: "Save preprocessed variants to a debug directory (default: false)"
7749
+ }
7750
+ },
7751
+ required: ["image"]
7752
+ };
7753
+ constructor(workingDir) {
7754
+ this.workingDir = workingDir;
7755
+ }
7756
+ async execute(args) {
7757
+ const start = performance.now();
7758
+ const rawPath = args["image"];
7759
+ const language = args["language"] ?? "eng";
7760
+ const doRegions = args["regions"] === true;
7761
+ const region = args["region"];
7762
+ const psm = args["psm"];
7763
+ const debug = args["debug"] === true;
7764
+ if (!rawPath) {
7765
+ return { success: false, output: "", error: "image path is required", durationMs: 0 };
7766
+ }
7767
+ const fullPath = resolve18(this.workingDir, rawPath);
7768
+ if (!existsSync15(fullPath)) {
7769
+ return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: performance.now() - start };
7770
+ }
7771
+ const stat5 = statSync8(fullPath);
7772
+ if (stat5.size > 50 * 1024 * 1024) {
7773
+ return { success: false, output: "", error: `Image too large: ${(stat5.size / 1024 / 1024).toFixed(0)}MB (max 50MB)`, durationMs: performance.now() - start };
7774
+ }
7775
+ const tesCheck = ensureCommand("tesseract");
7776
+ if (!tesCheck.available) {
7777
+ return {
7778
+ success: false,
7779
+ output: "",
7780
+ error: `Tesseract not available: ${tesCheck.error ?? "auto-install failed"}`,
7781
+ durationMs: performance.now() - start
7782
+ };
7783
+ }
7784
+ const python = findPython();
7785
+ const script = findOcrScript();
7786
+ if (python && script) {
7787
+ return this.runPythonPipeline(python, script, fullPath, language, doRegions, region, psm, debug, start);
7788
+ }
7789
+ return this.runBasicTesseract(fullPath, language, region, psm, start);
7790
+ }
7791
+ runPythonPipeline(python, script, imagePath, language, regions, region, psm, debug, start) {
7792
+ const cmdParts = [
7793
+ JSON.stringify(python),
7794
+ JSON.stringify(script),
7795
+ JSON.stringify(imagePath),
7796
+ "-l",
7797
+ language,
7798
+ "--output",
7799
+ "json"
7800
+ ];
7801
+ if (regions)
7802
+ cmdParts.push("--regions");
7803
+ if (region)
7804
+ cmdParts.push("--region", region);
7805
+ if (psm)
7806
+ cmdParts.push("--psm", String(psm));
7807
+ let debugDir;
7808
+ if (debug) {
7809
+ debugDir = join18(tmpdir5(), `oa-ocr-debug-${Date.now()}`);
7810
+ cmdParts.push("--debug-dir", debugDir);
7811
+ }
7812
+ try {
7813
+ const stdout = execSync14(cmdParts.join(" "), {
7814
+ encoding: "utf8",
7815
+ stdio: ["pipe", "pipe", "pipe"],
7816
+ timeout: 3e5,
7817
+ // 5 min for large images
7818
+ cwd: this.workingDir
7819
+ });
7820
+ const result = JSON.parse(stdout);
7821
+ if (result.error) {
7822
+ return {
7823
+ success: false,
7824
+ output: "",
7825
+ error: result.error,
7826
+ durationMs: performance.now() - start
7827
+ };
7828
+ }
7829
+ const parts = [];
7830
+ parts.push(`OCR extracted from ${basename7(imagePath)} (${result.image_size})`);
7831
+ parts.push(`Best variant: ${result.variant} (confidence: ${result.confidence}%, ${result.chars} chars)`);
7832
+ parts.push(`Variants tested: ${result.variants_tested}`);
7833
+ parts.push("");
7834
+ parts.push("--- Extracted Text ---");
7835
+ parts.push(result.text);
7836
+ if (result.regions) {
7837
+ parts.push("");
7838
+ parts.push("--- Region Extraction ---");
7839
+ for (const [rname, rtext] of Object.entries(result.regions)) {
7840
+ if (rtext) {
7841
+ parts.push(`
7842
+ [${rname.toUpperCase()}]`);
7843
+ parts.push(rtext);
7844
+ }
7845
+ }
7846
+ }
7847
+ if (result.all_variants) {
7848
+ const sorted = Object.entries(result.all_variants).filter(([_, v]) => v.chars > 0).sort((a, b) => b[1].confidence - a[1].confidence).slice(0, 5);
7849
+ if (sorted.length > 1) {
7850
+ parts.push("");
7851
+ parts.push("--- Top Variants ---");
7852
+ for (const [key, v] of sorted) {
7853
+ parts.push(` ${key}: ${v.confidence}% confidence, ${v.chars} chars`);
7854
+ }
7855
+ }
7856
+ }
7857
+ if (debugDir) {
7858
+ parts.push("");
7859
+ parts.push(`Debug images saved: ${debugDir}`);
7860
+ }
7861
+ return {
7862
+ success: true,
7863
+ output: parts.join("\n"),
7864
+ durationMs: performance.now() - start
7865
+ };
7866
+ } catch (err) {
7867
+ const stderr = err?.stderr?.toString?.() ?? "";
7868
+ if (stderr.includes("ModuleNotFoundError") || stderr.includes("ImportError")) {
7869
+ return this.runBasicTesseract(imagePath, language, region, void 0, start);
7870
+ }
7871
+ return {
7872
+ success: false,
7873
+ output: "",
7874
+ error: `Advanced OCR failed: ${(stderr || (err instanceof Error ? err.message : String(err))).slice(0, 500)}`,
7875
+ durationMs: performance.now() - start
7876
+ };
7877
+ }
7878
+ }
7879
+ runBasicTesseract(imagePath, language, region, psm, start) {
7880
+ let inputPath = imagePath;
7881
+ if (region) {
7882
+ try {
7883
+ const [x, y, w, h] = region.split(",").map(Number);
7884
+ const croppedPath = join18(tmpdir5(), `oa-ocr-crop-${Date.now()}.png`);
7885
+ execSync14(`convert ${JSON.stringify(imagePath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
7886
+ inputPath = croppedPath;
7887
+ } catch {
7888
+ }
7889
+ }
7890
+ const psmArg = psm ?? 6;
7891
+ try {
7892
+ const text = execSync14(`tesseract ${JSON.stringify(inputPath)} stdout -l ${language} --psm ${psmArg} 2>/dev/null`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 6e4 }).trim();
7893
+ if (!text) {
7894
+ return {
7895
+ success: true,
7896
+ output: `(no text detected in ${basename7(imagePath)} \u2014 try the advanced Python OCR pipeline for better results)`,
7897
+ durationMs: performance.now() - start
7898
+ };
7899
+ }
7900
+ const lineCount = text.split("\n").length;
7901
+ return {
7902
+ success: true,
7903
+ output: `OCR extracted ${lineCount} lines from ${basename7(imagePath)} (basic tesseract, PSM ${psmArg}):
7904
+ Note: Advanced Python pipeline not available \u2014 install pytesseract, opencv-python-headless, Pillow, numpy for better results.
7905
+
7906
+ ` + text,
7907
+ durationMs: performance.now() - start
7908
+ };
7909
+ } catch (err) {
7910
+ return {
7911
+ success: false,
7912
+ output: "",
7913
+ error: `Tesseract OCR failed: ${err instanceof Error ? err.message : String(err)}`,
7914
+ durationMs: performance.now() - start
7915
+ };
7916
+ }
7917
+ }
7918
+ };
7919
+ }
7920
+ });
7921
+
7673
7922
  // packages/execution/dist/shellRunner.js
7674
7923
  var init_shellRunner = __esm({
7675
7924
  "packages/execution/dist/shellRunner.js"() {
@@ -7781,6 +8030,7 @@ var init_dist2 = __esm({
7781
8030
  init_desktop_click();
7782
8031
  init_ocr_pdf();
7783
8032
  init_pdf_to_text();
8033
+ init_ocr_image_advanced();
7784
8034
  init_system_deps();
7785
8035
  init_shellRunner();
7786
8036
  init_gitWorktree();
@@ -8913,7 +9163,7 @@ var init_code_retriever = __esm({
8913
9163
  import { execFile as execFile4 } from "node:child_process";
8914
9164
  import { promisify as promisify4 } from "node:util";
8915
9165
  import { readFile as readFile8, readdir as readdir2, stat as stat3 } from "node:fs/promises";
8916
- import { join as join18, extname as extname7 } from "node:path";
9166
+ import { join as join19, extname as extname7 } from "node:path";
8917
9167
  async function searchByPath(pathPattern, options) {
8918
9168
  const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
8919
9169
  const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
@@ -9055,7 +9305,7 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
9055
9305
  continue;
9056
9306
  if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
9057
9307
  continue;
9058
- const absPath = join18(dir, entry.name);
9308
+ const absPath = join19(dir, entry.name);
9059
9309
  if (entry.isDirectory()) {
9060
9310
  await walkForFiles(rootDir, absPath, excludeGlobs, results);
9061
9311
  } else if (entry.isFile()) {
@@ -9230,7 +9480,7 @@ var init_graphExpand = __esm({
9230
9480
 
9231
9481
  // packages/retrieval/dist/snippetPacker.js
9232
9482
  import { readFile as readFile9 } from "node:fs/promises";
9233
- import { join as join19 } from "node:path";
9483
+ import { join as join20 } from "node:path";
9234
9484
  async function packSnippets(requests, opts = {}) {
9235
9485
  const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
9236
9486
  const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
@@ -9256,7 +9506,7 @@ async function packSnippets(requests, opts = {}) {
9256
9506
  return { packed, dropped, totalTokens };
9257
9507
  }
9258
9508
  async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
9259
- const absPath = req.filePath.startsWith("/") ? req.filePath : join19(repoRoot, req.filePath);
9509
+ const absPath = req.filePath.startsWith("/") ? req.filePath : join20(repoRoot, req.filePath);
9260
9510
  let content;
9261
9511
  try {
9262
9512
  content = await readFile9(absPath, "utf-8");
@@ -10769,8 +11019,8 @@ Rules:
10769
11019
  async waitIfPaused() {
10770
11020
  if (!this._paused)
10771
11021
  return true;
10772
- await new Promise((resolve21) => {
10773
- this._pauseResolve = resolve21;
11022
+ await new Promise((resolve22) => {
11023
+ this._pauseResolve = resolve22;
10774
11024
  });
10775
11025
  return !this.aborted;
10776
11026
  }
@@ -11280,14 +11530,14 @@ ${result.output}`;
11280
11530
  waitForSudoPassword(timeoutMs = 12e4) {
11281
11531
  if (this._sudoPassword)
11282
11532
  return Promise.resolve(this._sudoPassword);
11283
- return new Promise((resolve21) => {
11533
+ return new Promise((resolve22) => {
11284
11534
  const timer = setTimeout(() => {
11285
11535
  this._sudoResolve = null;
11286
- resolve21(null);
11536
+ resolve22(null);
11287
11537
  }, timeoutMs);
11288
11538
  this._sudoResolve = (pw) => {
11289
11539
  clearTimeout(timer);
11290
- resolve21(pw);
11540
+ resolve22(pw);
11291
11541
  };
11292
11542
  });
11293
11543
  }
@@ -12443,11 +12693,11 @@ var init_dist5 = __esm({
12443
12693
  });
12444
12694
 
12445
12695
  // packages/cli/dist/tui/listen.js
12446
- import { spawn as spawn7, execSync as execSync14 } from "node:child_process";
12447
- import { existsSync as existsSync15, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
12448
- import { join as join20, dirname as dirname6 } from "node:path";
12449
- import { homedir as homedir6 } from "node:os";
12450
- import { fileURLToPath as fileURLToPath3 } from "node:url";
12696
+ import { spawn as spawn7, execSync as execSync15 } from "node:child_process";
12697
+ import { existsSync as existsSync16, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readdirSync as readdirSync6 } from "node:fs";
12698
+ import { join as join21, dirname as dirname7 } from "node:path";
12699
+ import { homedir as homedir7 } from "node:os";
12700
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
12451
12701
  import { EventEmitter } from "node:events";
12452
12702
  import { createInterface as createInterface2 } from "node:readline";
12453
12703
  function isAudioPath(path) {
@@ -12465,7 +12715,7 @@ function findMicCaptureCommand() {
12465
12715
  const platform4 = process.platform;
12466
12716
  if (platform4 === "linux") {
12467
12717
  try {
12468
- execSync14("which arecord", { stdio: "pipe" });
12718
+ execSync15("which arecord", { stdio: "pipe" });
12469
12719
  return {
12470
12720
  cmd: "arecord",
12471
12721
  args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
@@ -12475,7 +12725,7 @@ function findMicCaptureCommand() {
12475
12725
  }
12476
12726
  if (platform4 === "darwin") {
12477
12727
  try {
12478
- execSync14("which sox", { stdio: "pipe" });
12728
+ execSync15("which sox", { stdio: "pipe" });
12479
12729
  return {
12480
12730
  cmd: "sox",
12481
12731
  args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
@@ -12484,7 +12734,7 @@ function findMicCaptureCommand() {
12484
12734
  }
12485
12735
  }
12486
12736
  try {
12487
- execSync14("which ffmpeg", { stdio: "pipe" });
12737
+ execSync15("which ffmpeg", { stdio: "pipe" });
12488
12738
  if (platform4 === "linux") {
12489
12739
  return {
12490
12740
  cmd: "ffmpeg",
@@ -12529,41 +12779,41 @@ function findMicCaptureCommand() {
12529
12779
  return null;
12530
12780
  }
12531
12781
  function findLiveWhisperScript() {
12532
- const thisDir = dirname6(fileURLToPath3(import.meta.url));
12782
+ const thisDir = dirname7(fileURLToPath4(import.meta.url));
12533
12783
  const candidates = [
12534
- join20(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
12535
- join20(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
12536
- join20(thisDir, "../../execution/scripts/live-whisper.py"),
12784
+ join21(thisDir, "../../../../packages/execution/scripts/live-whisper.py"),
12785
+ join21(thisDir, "../../../packages/execution/scripts/live-whisper.py"),
12786
+ join21(thisDir, "../../execution/scripts/live-whisper.py"),
12537
12787
  // npm install layout — scripts bundled alongside dist
12538
- join20(thisDir, "../scripts/live-whisper.py"),
12539
- join20(thisDir, "../../scripts/live-whisper.py")
12788
+ join21(thisDir, "../scripts/live-whisper.py"),
12789
+ join21(thisDir, "../../scripts/live-whisper.py")
12540
12790
  ];
12541
12791
  for (const p of candidates) {
12542
- if (existsSync15(p))
12792
+ if (existsSync16(p))
12543
12793
  return p;
12544
12794
  }
12545
12795
  try {
12546
- const globalRoot = execSync14("npm root -g", {
12796
+ const globalRoot = execSync15("npm root -g", {
12547
12797
  encoding: "utf-8",
12548
12798
  timeout: 5e3,
12549
12799
  stdio: ["pipe", "pipe", "pipe"]
12550
12800
  }).trim();
12551
12801
  const candidates2 = [
12552
- join20(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
12553
- join20(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
12802
+ join21(globalRoot, "open-agents-ai", "dist", "scripts", "live-whisper.py"),
12803
+ join21(globalRoot, "open-agents-ai", "scripts", "live-whisper.py")
12554
12804
  ];
12555
12805
  for (const p of candidates2) {
12556
- if (existsSync15(p))
12806
+ if (existsSync16(p))
12557
12807
  return p;
12558
12808
  }
12559
12809
  } catch {
12560
12810
  }
12561
- const nvmBase = join20(homedir6(), ".nvm", "versions", "node");
12562
- if (existsSync15(nvmBase)) {
12811
+ const nvmBase = join21(homedir7(), ".nvm", "versions", "node");
12812
+ if (existsSync16(nvmBase)) {
12563
12813
  try {
12564
12814
  for (const ver of readdirSync6(nvmBase)) {
12565
- const p = join20(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
12566
- if (existsSync15(p))
12815
+ const p = join21(nvmBase, ver, "lib", "node_modules", "open-agents-ai", "dist", "scripts", "live-whisper.py");
12816
+ if (existsSync16(p))
12567
12817
  return p;
12568
12818
  }
12569
12819
  } catch {
@@ -12576,21 +12826,21 @@ function ensureTranscribeCliBackground() {
12576
12826
  return;
12577
12827
  _bgInstallPromise = (async () => {
12578
12828
  try {
12579
- const globalRoot = execSync14("npm root -g", {
12829
+ const globalRoot = execSync15("npm root -g", {
12580
12830
  encoding: "utf-8",
12581
12831
  timeout: 5e3,
12582
12832
  stdio: ["pipe", "pipe", "pipe"]
12583
12833
  }).trim();
12584
- if (existsSync15(join20(globalRoot, "transcribe-cli", "dist", "index.js"))) {
12834
+ if (existsSync16(join21(globalRoot, "transcribe-cli", "dist", "index.js"))) {
12585
12835
  return true;
12586
12836
  }
12587
12837
  } catch {
12588
12838
  }
12589
12839
  try {
12590
12840
  const { exec } = await import("node:child_process");
12591
- return new Promise((resolve21) => {
12841
+ return new Promise((resolve22) => {
12592
12842
  exec("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
12593
- resolve21(!err);
12843
+ resolve22(!err);
12594
12844
  });
12595
12845
  });
12596
12846
  } catch {
@@ -12643,7 +12893,7 @@ var init_listen = __esm({
12643
12893
  return this._ready;
12644
12894
  }
12645
12895
  async start() {
12646
- return new Promise((resolve21, reject) => {
12896
+ return new Promise((resolve22, reject) => {
12647
12897
  const timeout = setTimeout(() => {
12648
12898
  reject(new Error("Whisper fallback: model load timeout (5 min). First run downloads the model."));
12649
12899
  }, 3e5);
@@ -12671,7 +12921,7 @@ var init_listen = __esm({
12671
12921
  this._ready = true;
12672
12922
  clearTimeout(timeout);
12673
12923
  this.emit("ready");
12674
- resolve21();
12924
+ resolve22();
12675
12925
  break;
12676
12926
  case "transcript":
12677
12927
  this.emit("transcript", {
@@ -12776,7 +13026,7 @@ var init_listen = __esm({
12776
13026
  }
12777
13027
  if (!this.transcribeCliAvailable) {
12778
13028
  try {
12779
- execSync14("which transcribe-cli", { stdio: "pipe" });
13029
+ execSync15("which transcribe-cli", { stdio: "pipe" });
12780
13030
  this.transcribeCliAvailable = true;
12781
13031
  } catch {
12782
13032
  this.transcribeCliAvailable = false;
@@ -12793,29 +13043,29 @@ var init_listen = __esm({
12793
13043
  } catch {
12794
13044
  }
12795
13045
  try {
12796
- const globalRoot = execSync14("npm root -g", {
13046
+ const globalRoot = execSync15("npm root -g", {
12797
13047
  encoding: "utf-8",
12798
13048
  timeout: 5e3,
12799
13049
  stdio: ["pipe", "pipe", "pipe"]
12800
13050
  }).trim();
12801
- const tcPath = join20(globalRoot, "transcribe-cli");
12802
- if (existsSync15(join20(tcPath, "dist", "index.js"))) {
13051
+ const tcPath = join21(globalRoot, "transcribe-cli");
13052
+ if (existsSync16(join21(tcPath, "dist", "index.js"))) {
12803
13053
  const { createRequire: createRequire4 } = await import("node:module");
12804
13054
  const req = createRequire4(import.meta.url);
12805
- return req(join20(tcPath, "dist", "index.js"));
13055
+ return req(join21(tcPath, "dist", "index.js"));
12806
13056
  }
12807
13057
  } catch {
12808
13058
  }
12809
- const nvmBase = join20(homedir6(), ".nvm", "versions", "node");
12810
- if (existsSync15(nvmBase)) {
13059
+ const nvmBase = join21(homedir7(), ".nvm", "versions", "node");
13060
+ if (existsSync16(nvmBase)) {
12811
13061
  try {
12812
13062
  const { readdirSync: readdirSync11 } = await import("node:fs");
12813
13063
  for (const ver of readdirSync11(nvmBase)) {
12814
- const tcPath = join20(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
12815
- if (existsSync15(join20(tcPath, "dist", "index.js"))) {
13064
+ const tcPath = join21(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
13065
+ if (existsSync16(join21(tcPath, "dist", "index.js"))) {
12816
13066
  const { createRequire: createRequire4 } = await import("node:module");
12817
13067
  const req = createRequire4(import.meta.url);
12818
- return req(join20(tcPath, "dist", "index.js"));
13068
+ return req(join21(tcPath, "dist", "index.js"));
12819
13069
  }
12820
13070
  }
12821
13071
  } catch {
@@ -12843,7 +13093,7 @@ var init_listen = __esm({
12843
13093
  }
12844
13094
  if (!tc) {
12845
13095
  try {
12846
- execSync14("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
13096
+ execSync15("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
12847
13097
  this.transcribeCliAvailable = null;
12848
13098
  tc = await this.loadTranscribeCli();
12849
13099
  } catch {
@@ -12875,11 +13125,11 @@ var init_listen = __esm({
12875
13125
  this.liveTranscriber.on("error", (err) => {
12876
13126
  this.emit("error", err);
12877
13127
  });
12878
- await new Promise((resolve21, reject) => {
13128
+ await new Promise((resolve22, reject) => {
12879
13129
  const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
12880
13130
  this.liveTranscriber.on("ready", () => {
12881
13131
  clearTimeout(timeout);
12882
- resolve21();
13132
+ resolve22();
12883
13133
  });
12884
13134
  this.liveTranscriber.on("error", (err) => {
12885
13135
  clearTimeout(timeout);
@@ -13024,7 +13274,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
13024
13274
  }
13025
13275
  if (!tc) {
13026
13276
  try {
13027
- execSync14("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
13277
+ execSync15("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
13028
13278
  this.transcribeCliAvailable = null;
13029
13279
  tc = await this.loadTranscribeCli();
13030
13280
  } catch {
@@ -13040,10 +13290,10 @@ transcribe-cli error: ${transcribeCliError}` : "";
13040
13290
  wordTimestamps: false
13041
13291
  });
13042
13292
  if (outputDir) {
13043
- const { basename: basename12 } = await import("node:path");
13044
- const transcriptDir = join20(outputDir, ".oa", "transcripts");
13293
+ const { basename: basename13 } = await import("node:path");
13294
+ const transcriptDir = join21(outputDir, ".oa", "transcripts");
13045
13295
  mkdirSync5(transcriptDir, { recursive: true });
13046
- const outFile = join20(transcriptDir, `${basename12(filePath)}.txt`);
13296
+ const outFile = join21(transcriptDir, `${basename13(filePath)}.txt`);
13047
13297
  writeFileSync5(outFile, result.text, "utf-8");
13048
13298
  }
13049
13299
  return {
@@ -13742,7 +13992,7 @@ function renderSlashHelp() {
13742
13992
  ["/dream stop", "Wake up \u2014 stop dreaming"],
13743
13993
  ["/listen", "Toggle live microphone transcription (Whisper)"],
13744
13994
  ["/listen <model>", "Set model: tiny, base, small, medium, large"],
13745
- ["/listen confirm", "Require Enter to submit transcription"],
13995
+ ["/listen manual", "Manual mode \u2014 press Enter to submit (turns off auto)"],
13746
13996
  ["/listen auto", "Auto-submit after 3s silence (blinking \u25CF indicator)"],
13747
13997
  ["/listen stop", "Stop listening"],
13748
13998
  ["/cost", "Show session token cost breakdown"],
@@ -14307,8 +14557,8 @@ Approach this task thoughtfully:
14307
14557
  });
14308
14558
 
14309
14559
  // packages/prompts/dist/index.js
14310
- import { join as join21, dirname as dirname7 } from "node:path";
14311
- import { fileURLToPath as fileURLToPath4 } from "node:url";
14560
+ import { join as join22, dirname as dirname8 } from "node:path";
14561
+ import { fileURLToPath as fileURLToPath5 } from "node:url";
14312
14562
  var _dir, _packageRoot;
14313
14563
  var init_dist6 = __esm({
14314
14564
  "packages/prompts/dist/index.js"() {
@@ -14317,29 +14567,29 @@ var init_dist6 = __esm({
14317
14567
  init_render2();
14318
14568
  init_task_templates();
14319
14569
  init_render2();
14320
- _dir = dirname7(fileURLToPath4(import.meta.url));
14321
- _packageRoot = join21(_dir, "..");
14570
+ _dir = dirname8(fileURLToPath5(import.meta.url));
14571
+ _packageRoot = join22(_dir, "..");
14322
14572
  }
14323
14573
  });
14324
14574
 
14325
14575
  // packages/cli/dist/tui/oa-directory.js
14326
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync8, unlinkSync as unlinkSync3 } from "node:fs";
14327
- import { join as join22, relative as relative2, basename as basename7, extname as extname8 } from "node:path";
14328
- import { homedir as homedir7 } from "node:os";
14576
+ import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync13, writeFileSync as writeFileSync6, readdirSync as readdirSync7, statSync as statSync9, unlinkSync as unlinkSync3 } from "node:fs";
14577
+ import { join as join23, relative as relative2, basename as basename8, extname as extname8 } from "node:path";
14578
+ import { homedir as homedir8 } from "node:os";
14329
14579
  function initOaDirectory(repoRoot) {
14330
- const oaPath = join22(repoRoot, OA_DIR);
14580
+ const oaPath = join23(repoRoot, OA_DIR);
14331
14581
  for (const sub of SUBDIRS) {
14332
- mkdirSync6(join22(oaPath, sub), { recursive: true });
14582
+ mkdirSync6(join23(oaPath, sub), { recursive: true });
14333
14583
  }
14334
14584
  return oaPath;
14335
14585
  }
14336
14586
  function hasOaDirectory(repoRoot) {
14337
- return existsSync16(join22(repoRoot, OA_DIR, "index"));
14587
+ return existsSync17(join23(repoRoot, OA_DIR, "index"));
14338
14588
  }
14339
14589
  function loadProjectSettings(repoRoot) {
14340
- const settingsPath = join22(repoRoot, OA_DIR, "settings.json");
14590
+ const settingsPath = join23(repoRoot, OA_DIR, "settings.json");
14341
14591
  try {
14342
- if (existsSync16(settingsPath)) {
14592
+ if (existsSync17(settingsPath)) {
14343
14593
  return JSON.parse(readFileSync13(settingsPath, "utf-8"));
14344
14594
  }
14345
14595
  } catch {
@@ -14347,16 +14597,16 @@ function loadProjectSettings(repoRoot) {
14347
14597
  return {};
14348
14598
  }
14349
14599
  function saveProjectSettings(repoRoot, settings) {
14350
- const oaPath = join22(repoRoot, OA_DIR);
14600
+ const oaPath = join23(repoRoot, OA_DIR);
14351
14601
  mkdirSync6(oaPath, { recursive: true });
14352
14602
  const existing = loadProjectSettings(repoRoot);
14353
14603
  const merged = { ...existing, ...settings };
14354
- writeFileSync6(join22(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
14604
+ writeFileSync6(join23(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
14355
14605
  }
14356
14606
  function loadGlobalSettings() {
14357
- const settingsPath = join22(homedir7(), ".open-agents", "settings.json");
14607
+ const settingsPath = join23(homedir8(), ".open-agents", "settings.json");
14358
14608
  try {
14359
- if (existsSync16(settingsPath)) {
14609
+ if (existsSync17(settingsPath)) {
14360
14610
  return JSON.parse(readFileSync13(settingsPath, "utf-8"));
14361
14611
  }
14362
14612
  } catch {
@@ -14364,11 +14614,11 @@ function loadGlobalSettings() {
14364
14614
  return {};
14365
14615
  }
14366
14616
  function saveGlobalSettings(settings) {
14367
- const dir = join22(homedir7(), ".open-agents");
14617
+ const dir = join23(homedir8(), ".open-agents");
14368
14618
  mkdirSync6(dir, { recursive: true });
14369
14619
  const existing = loadGlobalSettings();
14370
14620
  const merged = { ...existing, ...settings };
14371
- writeFileSync6(join22(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
14621
+ writeFileSync6(join23(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
14372
14622
  }
14373
14623
  function resolveSettings(repoRoot) {
14374
14624
  const global = loadGlobalSettings();
@@ -14383,9 +14633,9 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
14383
14633
  while (dir && !visited.has(dir)) {
14384
14634
  visited.add(dir);
14385
14635
  for (const name of CONTEXT_FILES) {
14386
- const filePath = join22(dir, name);
14636
+ const filePath = join23(dir, name);
14387
14637
  const normalizedName = name.toLowerCase();
14388
- if (existsSync16(filePath) && !seen.has(filePath)) {
14638
+ if (existsSync17(filePath) && !seen.has(filePath)) {
14389
14639
  seen.add(filePath);
14390
14640
  try {
14391
14641
  let content = readFileSync13(filePath, "utf-8");
@@ -14402,8 +14652,8 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
14402
14652
  }
14403
14653
  }
14404
14654
  }
14405
- const projectMap = join22(dir, OA_DIR, "context", "project-map.md");
14406
- if (existsSync16(projectMap) && !seen.has(projectMap)) {
14655
+ const projectMap = join23(dir, OA_DIR, "context", "project-map.md");
14656
+ if (existsSync17(projectMap) && !seen.has(projectMap)) {
14407
14657
  seen.add(projectMap);
14408
14658
  try {
14409
14659
  let content = readFileSync13(projectMap, "utf-8");
@@ -14418,7 +14668,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
14418
14668
  } catch {
14419
14669
  }
14420
14670
  }
14421
- const parent = join22(dir, "..");
14671
+ const parent = join23(dir, "..");
14422
14672
  if (parent === dir)
14423
14673
  break;
14424
14674
  dir = parent;
@@ -14436,7 +14686,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
14436
14686
  return found;
14437
14687
  }
14438
14688
  function readIndexMeta(repoRoot) {
14439
- const metaPath = join22(repoRoot, OA_DIR, "index", "meta.json");
14689
+ const metaPath = join23(repoRoot, OA_DIR, "index", "meta.json");
14440
14690
  try {
14441
14691
  return JSON.parse(readFileSync13(metaPath, "utf-8"));
14442
14692
  } catch {
@@ -14445,7 +14695,7 @@ function readIndexMeta(repoRoot) {
14445
14695
  }
14446
14696
  function generateProjectMap(repoRoot) {
14447
14697
  const sections = [];
14448
- const repoName2 = basename7(repoRoot);
14698
+ const repoName2 = basename8(repoRoot);
14449
14699
  sections.push(`# Project Map: ${repoName2}
14450
14700
  `);
14451
14701
  sections.push(`> Auto-generated by open-agents. Updated: ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
@@ -14489,28 +14739,28 @@ ${tree}\`\`\`
14489
14739
  sections.push("");
14490
14740
  }
14491
14741
  const content = sections.join("\n");
14492
- const contextDir = join22(repoRoot, OA_DIR, "context");
14742
+ const contextDir = join23(repoRoot, OA_DIR, "context");
14493
14743
  mkdirSync6(contextDir, { recursive: true });
14494
- writeFileSync6(join22(contextDir, "project-map.md"), content, "utf-8");
14744
+ writeFileSync6(join23(contextDir, "project-map.md"), content, "utf-8");
14495
14745
  return content;
14496
14746
  }
14497
14747
  function saveSession(repoRoot, session) {
14498
- const historyDir = join22(repoRoot, OA_DIR, "history");
14748
+ const historyDir = join23(repoRoot, OA_DIR, "history");
14499
14749
  mkdirSync6(historyDir, { recursive: true });
14500
- writeFileSync6(join22(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
14750
+ writeFileSync6(join23(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
14501
14751
  }
14502
14752
  function loadRecentSessions(repoRoot, limit = 5) {
14503
- const historyDir = join22(repoRoot, OA_DIR, "history");
14504
- if (!existsSync16(historyDir))
14753
+ const historyDir = join23(repoRoot, OA_DIR, "history");
14754
+ if (!existsSync17(historyDir))
14505
14755
  return [];
14506
14756
  try {
14507
14757
  const files = readdirSync7(historyDir).filter((f) => f.endsWith(".json") && f !== "pending-task.json").map((f) => {
14508
- const stat5 = statSync8(join22(historyDir, f));
14758
+ const stat5 = statSync9(join23(historyDir, f));
14509
14759
  return { file: f, mtime: stat5.mtimeMs };
14510
14760
  }).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
14511
14761
  return files.map((f) => {
14512
14762
  try {
14513
- return JSON.parse(readFileSync13(join22(historyDir, f.file), "utf-8"));
14763
+ return JSON.parse(readFileSync13(join23(historyDir, f.file), "utf-8"));
14514
14764
  } catch {
14515
14765
  return null;
14516
14766
  }
@@ -14520,14 +14770,14 @@ function loadRecentSessions(repoRoot, limit = 5) {
14520
14770
  }
14521
14771
  }
14522
14772
  function savePendingTask(repoRoot, task) {
14523
- const historyDir = join22(repoRoot, OA_DIR, "history");
14773
+ const historyDir = join23(repoRoot, OA_DIR, "history");
14524
14774
  mkdirSync6(historyDir, { recursive: true });
14525
- writeFileSync6(join22(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
14775
+ writeFileSync6(join23(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
14526
14776
  }
14527
14777
  function loadPendingTask(repoRoot) {
14528
- const filePath = join22(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
14778
+ const filePath = join23(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
14529
14779
  try {
14530
- if (!existsSync16(filePath))
14780
+ if (!existsSync17(filePath))
14531
14781
  return null;
14532
14782
  const data = JSON.parse(readFileSync13(filePath, "utf-8"));
14533
14783
  try {
@@ -14557,8 +14807,8 @@ function detectManifests(repoRoot) {
14557
14807
  { file: "docker-compose.yaml", type: "Docker Compose" }
14558
14808
  ];
14559
14809
  for (const check of checks) {
14560
- const filePath = join22(repoRoot, check.file);
14561
- if (existsSync16(filePath)) {
14810
+ const filePath = join23(repoRoot, check.file);
14811
+ if (existsSync17(filePath)) {
14562
14812
  let name;
14563
14813
  if (check.nameField) {
14564
14814
  try {
@@ -14591,7 +14841,7 @@ function findKeyFiles(repoRoot) {
14591
14841
  { pattern: "CLAUDE.md", description: "Claude Code context" }
14592
14842
  ];
14593
14843
  for (const check of checks) {
14594
- if (existsSync16(join22(repoRoot, check.pattern))) {
14844
+ if (existsSync17(join23(repoRoot, check.pattern))) {
14595
14845
  keyFiles.push({ path: check.pattern, description: check.description });
14596
14846
  }
14597
14847
  }
@@ -14617,12 +14867,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
14617
14867
  if (entry.isDirectory()) {
14618
14868
  let fileCount = 0;
14619
14869
  try {
14620
- fileCount = readdirSync7(join22(root, entry.name)).filter((f) => !f.startsWith(".")).length;
14870
+ fileCount = readdirSync7(join23(root, entry.name)).filter((f) => !f.startsWith(".")).length;
14621
14871
  } catch {
14622
14872
  }
14623
14873
  result += `${prefix}${connector}${entry.name}/ (${fileCount})
14624
14874
  `;
14625
- result += buildDirTree(join22(root, entry.name), maxDepth, childPrefix, depth + 1);
14875
+ result += buildDirTree(join23(root, entry.name), maxDepth, childPrefix, depth + 1);
14626
14876
  } else if (depth < maxDepth) {
14627
14877
  result += `${prefix}${connector}${entry.name}
14628
14878
  `;
@@ -14673,17 +14923,17 @@ var init_oa_directory = __esm({
14673
14923
 
14674
14924
  // packages/cli/dist/tui/setup.js
14675
14925
  import * as readline from "node:readline";
14676
- import { execSync as execSync15, spawn as spawn8 } from "node:child_process";
14677
- import { existsSync as existsSync17, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
14678
- import { join as join23 } from "node:path";
14679
- import { homedir as homedir8, platform } from "node:os";
14926
+ import { execSync as execSync16, spawn as spawn8 } from "node:child_process";
14927
+ import { existsSync as existsSync18, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
14928
+ import { join as join24 } from "node:path";
14929
+ import { homedir as homedir9, platform } from "node:os";
14680
14930
  function detectSystemSpecs() {
14681
14931
  let totalRamGB = 0;
14682
14932
  let availableRamGB = 0;
14683
14933
  let gpuVramGB = 0;
14684
14934
  let gpuName = "";
14685
14935
  try {
14686
- const memInfo = execSync15("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
14936
+ const memInfo = execSync16("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
14687
14937
  encoding: "utf8",
14688
14938
  timeout: 5e3
14689
14939
  });
@@ -14703,7 +14953,7 @@ function detectSystemSpecs() {
14703
14953
  } catch {
14704
14954
  }
14705
14955
  try {
14706
- const nvidiaSmi = execSync15("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
14956
+ const nvidiaSmi = execSync16("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
14707
14957
  const lines = nvidiaSmi.trim().split("\n");
14708
14958
  if (lines.length > 0) {
14709
14959
  for (const line of lines) {
@@ -14759,8 +15009,8 @@ function modelSupportsToolCalling(modelName) {
14759
15009
  return false;
14760
15010
  }
14761
15011
  function ask(rl, question) {
14762
- return new Promise((resolve21) => {
14763
- rl.question(question, (answer) => resolve21(answer.trim()));
15012
+ return new Promise((resolve22) => {
15013
+ rl.question(question, (answer) => resolve22(answer.trim()));
14764
15014
  });
14765
15015
  }
14766
15016
  async function autoInstallOllama(rl) {
@@ -14785,7 +15035,7 @@ function installOllamaLinux() {
14785
15035
 
14786
15036
  `);
14787
15037
  try {
14788
- execSync15("curl -fsSL https://ollama.com/install.sh | sh", {
15038
+ execSync16("curl -fsSL https://ollama.com/install.sh | sh", {
14789
15039
  stdio: "inherit",
14790
15040
  timeout: 3e5
14791
15041
  });
@@ -14824,10 +15074,10 @@ async function installOllamaMac(rl) {
14824
15074
 
14825
15075
  `);
14826
15076
  try {
14827
- execSync15('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
15077
+ execSync16('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
14828
15078
  if (!hasCmd("brew")) {
14829
15079
  try {
14830
- const brewPrefix = existsSync17("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
15080
+ const brewPrefix = existsSync18("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
14831
15081
  process.env["PATH"] = `${brewPrefix}/bin:${process.env["PATH"]}`;
14832
15082
  } catch {
14833
15083
  }
@@ -14857,7 +15107,7 @@ async function installOllamaMac(rl) {
14857
15107
 
14858
15108
  `);
14859
15109
  try {
14860
- execSync15("brew install ollama", {
15110
+ execSync16("brew install ollama", {
14861
15111
  stdio: "inherit",
14862
15112
  timeout: 3e5
14863
15113
  });
@@ -14884,7 +15134,7 @@ function installOllamaWindows() {
14884
15134
 
14885
15135
  `);
14886
15136
  try {
14887
- execSync15('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
15137
+ execSync16('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
14888
15138
  stdio: "inherit",
14889
15139
  timeout: 3e5
14890
15140
  });
@@ -14907,7 +15157,7 @@ function installOllamaWindows() {
14907
15157
  }
14908
15158
  function pullModelWithAutoUpdate(tag) {
14909
15159
  try {
14910
- execSync15(`ollama pull ${tag}`, {
15160
+ execSync16(`ollama pull ${tag}`, {
14911
15161
  stdio: "inherit",
14912
15162
  timeout: 36e5
14913
15163
  // 1 hour max
@@ -14924,7 +15174,7 @@ function pullModelWithAutoUpdate(tag) {
14924
15174
 
14925
15175
  `);
14926
15176
  try {
14927
- execSync15("curl -fsSL https://ollama.com/install.sh | sh", {
15177
+ execSync16("curl -fsSL https://ollama.com/install.sh | sh", {
14928
15178
  stdio: "inherit",
14929
15179
  timeout: 3e5
14930
15180
  // 5 min max for install
@@ -14935,7 +15185,7 @@ function pullModelWithAutoUpdate(tag) {
14935
15185
  process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
14936
15186
 
14937
15187
  `);
14938
- execSync15(`ollama pull ${tag}`, {
15188
+ execSync16(`ollama pull ${tag}`, {
14939
15189
  stdio: "inherit",
14940
15190
  timeout: 36e5
14941
15191
  });
@@ -15118,7 +15368,7 @@ async function doSetup(config, rl) {
15118
15368
  try {
15119
15369
  const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
15120
15370
  child.unref();
15121
- await new Promise((resolve21) => setTimeout(resolve21, 3e3));
15371
+ await new Promise((resolve22) => setTimeout(resolve22, 3e3));
15122
15372
  try {
15123
15373
  models = await fetchOllamaModels(config.backendUrl);
15124
15374
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -15146,7 +15396,7 @@ async function doSetup(config, rl) {
15146
15396
  try {
15147
15397
  const child = spawn8("ollama", ["serve"], { stdio: "ignore", detached: true });
15148
15398
  child.unref();
15149
- await new Promise((resolve21) => setTimeout(resolve21, 3e3));
15399
+ await new Promise((resolve22) => setTimeout(resolve22, 3e3));
15150
15400
  try {
15151
15401
  models = await fetchOllamaModels(config.backendUrl);
15152
15402
  process.stdout.write(` ${c2.green("\u2714")} Ollama is running.
@@ -15300,12 +15550,12 @@ async function doSetup(config, rl) {
15300
15550
  `PARAMETER num_predict 16384`,
15301
15551
  `PARAMETER stop "<|endoftext|>"`
15302
15552
  ].join("\n");
15303
- const modelDir2 = join23(homedir8(), ".open-agents", "models");
15553
+ const modelDir2 = join24(homedir9(), ".open-agents", "models");
15304
15554
  mkdirSync7(modelDir2, { recursive: true });
15305
- const modelfilePath = join23(modelDir2, `Modelfile.${customName}`);
15555
+ const modelfilePath = join24(modelDir2, `Modelfile.${customName}`);
15306
15556
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
15307
15557
  process.stdout.write(` ${c2.dim("Creating model...")} `);
15308
- execSync15(`ollama create ${customName} -f ${modelfilePath}`, {
15558
+ execSync16(`ollama create ${customName} -f ${modelfilePath}`, {
15309
15559
  stdio: "pipe",
15310
15560
  timeout: 12e4
15311
15561
  });
@@ -15348,7 +15598,7 @@ async function isModelAvailable(config) {
15348
15598
  }
15349
15599
  function isFirstRun() {
15350
15600
  try {
15351
- return !existsSync17(join23(homedir8(), ".open-agents", "config.json"));
15601
+ return !existsSync18(join24(homedir9(), ".open-agents", "config.json"));
15352
15602
  } catch {
15353
15603
  return true;
15354
15604
  }
@@ -15356,7 +15606,7 @@ function isFirstRun() {
15356
15606
  function hasCmd(cmd) {
15357
15607
  try {
15358
15608
  const whichCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
15359
- execSync15(whichCmd, { stdio: "pipe", timeout: 3e3 });
15609
+ execSync16(whichCmd, { stdio: "pipe", timeout: 3e3 });
15360
15610
  return true;
15361
15611
  } catch {
15362
15612
  return false;
@@ -15385,11 +15635,11 @@ function detectPkgManager() {
15385
15635
  return null;
15386
15636
  }
15387
15637
  function getVenvDir() {
15388
- return join23(homedir8(), ".open-agents", "venv");
15638
+ return join24(homedir9(), ".open-agents", "venv");
15389
15639
  }
15390
15640
  function hasVenvModule() {
15391
15641
  try {
15392
- execSync15("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
15642
+ execSync16("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
15393
15643
  return true;
15394
15644
  } catch {
15395
15645
  return false;
@@ -15397,8 +15647,8 @@ function hasVenvModule() {
15397
15647
  }
15398
15648
  function ensureVenv(log) {
15399
15649
  const venvDir = getVenvDir();
15400
- const venvPip = join23(venvDir, "bin", "pip");
15401
- if (existsSync17(venvPip))
15650
+ const venvPip = join24(venvDir, "bin", "pip");
15651
+ if (existsSync18(venvPip))
15402
15652
  return venvDir;
15403
15653
  log("Creating Python venv for vision deps...");
15404
15654
  if (!hasCmd("python3")) {
@@ -15410,9 +15660,9 @@ function ensureVenv(log) {
15410
15660
  return null;
15411
15661
  }
15412
15662
  try {
15413
- mkdirSync7(join23(homedir8(), ".open-agents"), { recursive: true });
15414
- execSync15(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
15415
- execSync15(`"${join23(venvDir, "bin", "pip")}" install --upgrade pip`, {
15663
+ mkdirSync7(join24(homedir9(), ".open-agents"), { recursive: true });
15664
+ execSync16(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
15665
+ execSync16(`"${join24(venvDir, "bin", "pip")}" install --upgrade pip`, {
15416
15666
  stdio: "pipe",
15417
15667
  timeout: 6e4
15418
15668
  });
@@ -15425,7 +15675,7 @@ function ensureVenv(log) {
15425
15675
  }
15426
15676
  function trySudoPasswordless(cmd, timeoutMs = 12e4) {
15427
15677
  try {
15428
- execSync15(`sudo -n ${cmd}`, {
15678
+ execSync16(`sudo -n ${cmd}`, {
15429
15679
  stdio: "pipe",
15430
15680
  timeout: timeoutMs,
15431
15681
  env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
@@ -15437,7 +15687,7 @@ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
15437
15687
  }
15438
15688
  function runWithSudo(cmd, password, timeoutMs = 12e4) {
15439
15689
  try {
15440
- execSync15(`sudo -S ${cmd}`, {
15690
+ execSync16(`sudo -S ${cmd}`, {
15441
15691
  input: password + "\n",
15442
15692
  stdio: ["pipe", "pipe", "pipe"],
15443
15693
  timeout: timeoutMs,
@@ -15497,7 +15747,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
15497
15747
  } else {
15498
15748
  log("Installing tesseract-ocr...");
15499
15749
  try {
15500
- execSync15(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
15750
+ execSync16(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
15501
15751
  if (hasCmd("tesseract")) {
15502
15752
  log("tesseract-ocr installed successfully.");
15503
15753
  } else {
@@ -15569,7 +15819,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
15569
15819
  } else {
15570
15820
  log(`Installing ${dep.label}...`);
15571
15821
  try {
15572
- execSync15(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
15822
+ execSync16(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
15573
15823
  if (hasCmd(dep.binary)) {
15574
15824
  log(`${dep.label} installed successfully.`);
15575
15825
  } else {
@@ -15600,7 +15850,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
15600
15850
  const venvCmds = {
15601
15851
  apt: () => {
15602
15852
  try {
15603
- const pyVer = execSync15(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
15853
+ const pyVer = execSync16(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
15604
15854
  return `apt-get install -y python3-venv python${pyVer}-venv`;
15605
15855
  } catch {
15606
15856
  return "apt-get install -y python3-venv";
@@ -15621,34 +15871,56 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
15621
15871
  }
15622
15872
  }
15623
15873
  const venvDir = getVenvDir();
15624
- const venvBin = join23(venvDir, "bin");
15625
- const venvMoondream = join23(venvBin, "moondream-station");
15626
- if (hasCmd("moondream-station") || existsSync17(venvMoondream)) {
15627
- return;
15628
- }
15874
+ const venvBin = join24(venvDir, "bin");
15875
+ const venvMoondream = join24(venvBin, "moondream-station");
15629
15876
  const venv = ensureVenv(log);
15630
- if (!venv) {
15631
- log("Python venv unavailable \u2014 moondream-station will not be installed.");
15632
- return;
15877
+ if (venv && !hasCmd("moondream-station") && !existsSync18(venvMoondream)) {
15878
+ const venvPip = join24(venvBin, "pip");
15879
+ log("Installing moondream-station in ~/.open-agents/venv...");
15880
+ try {
15881
+ execSync16(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
15882
+ if (existsSync18(venvMoondream)) {
15883
+ log("moondream-station installed successfully.");
15884
+ } else {
15885
+ try {
15886
+ const check = execSync16(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
15887
+ if (check.includes("moondream")) {
15888
+ log("moondream-station package installed.");
15889
+ }
15890
+ } catch {
15891
+ log("moondream-station install completed.");
15892
+ }
15893
+ }
15894
+ } catch (err) {
15895
+ log(`moondream-station install failed: ${err instanceof Error ? err.message : String(err)}`);
15896
+ }
15633
15897
  }
15634
- const venvPip = join23(venvBin, "pip");
15635
- log("Installing moondream-station in ~/.open-agents/venv...");
15636
- try {
15637
- execSync15(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
15638
- if (existsSync17(venvMoondream)) {
15639
- log("moondream-station installed successfully.");
15640
- } else {
15898
+ if (venv) {
15899
+ const venvPython = join24(venvBin, "python");
15900
+ const venvPip2 = join24(venvBin, "pip");
15901
+ let ocrStackInstalled = false;
15902
+ try {
15903
+ execSync16(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
15904
+ ocrStackInstalled = true;
15905
+ } catch {
15906
+ }
15907
+ if (!ocrStackInstalled) {
15908
+ const ocrPackages = "pytesseract Pillow opencv-python-headless numpy";
15909
+ log("Installing OCR Python stack (pytesseract, OpenCV, Pillow, numpy)...");
15641
15910
  try {
15642
- const check = execSync15(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
15643
- if (check.includes("moondream")) {
15644
- log("moondream-station package installed.");
15911
+ execSync16(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
15912
+ try {
15913
+ execSync16(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
15914
+ log("OCR Python stack installed successfully.");
15915
+ } catch {
15916
+ log("OCR Python stack install completed but import verification failed.");
15645
15917
  }
15646
- } catch {
15647
- log("moondream-station install completed.");
15918
+ } catch (err) {
15919
+ log(`OCR Python stack install failed: ${err instanceof Error ? err.message : String(err)}`);
15648
15920
  }
15649
15921
  }
15650
- } catch (err) {
15651
- log(`moondream-station install failed: ${err instanceof Error ? err.message : String(err)}`);
15922
+ } else {
15923
+ log("Python venv unavailable \u2014 advanced OCR pipeline will fall back to basic tesseract.");
15652
15924
  }
15653
15925
  }
15654
15926
  function expandedModelName(baseModel) {
@@ -15684,11 +15956,11 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
15684
15956
  `PARAMETER num_predict 16384`,
15685
15957
  `PARAMETER stop "<|endoftext|>"`
15686
15958
  ].join("\n");
15687
- const modelDir2 = join23(homedir8(), ".open-agents", "models");
15959
+ const modelDir2 = join24(homedir9(), ".open-agents", "models");
15688
15960
  mkdirSync7(modelDir2, { recursive: true });
15689
- const modelfilePath = join23(modelDir2, `Modelfile.${customName}`);
15961
+ const modelfilePath = join24(modelDir2, `Modelfile.${customName}`);
15690
15962
  writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
15691
- execSync15(`ollama create ${customName} -f ${modelfilePath}`, {
15963
+ execSync16(`ollama create ${customName} -f ${modelfilePath}`, {
15692
15964
  stdio: "pipe",
15693
15965
  timeout: 12e4
15694
15966
  });
@@ -16115,8 +16387,8 @@ async function handleSlashCommand(input, ctx) {
16115
16387
  renderInfo(msg2);
16116
16388
  return "handled";
16117
16389
  }
16118
- if (arg === "confirm") {
16119
- const msg2 = ctx.listenSetMode?.("confirm") ?? "Confirm mode set.";
16390
+ if (arg === "confirm" || arg === "manual") {
16391
+ const msg2 = ctx.listenSetMode?.("confirm") ?? "Manual mode set.";
16120
16392
  renderInfo(msg2);
16121
16393
  return "handled";
16122
16394
  }
@@ -16375,18 +16647,18 @@ async function handleUpdate(subcommand, ctx) {
16375
16647
  let currentVersion = "0.0.0";
16376
16648
  try {
16377
16649
  const { createRequire: createRequire4 } = await import("node:module");
16378
- const { fileURLToPath: fileURLToPath7 } = await import("node:url");
16379
- const { dirname: dirname10, join: join34 } = await import("node:path");
16380
- const { existsSync: existsSync24 } = await import("node:fs");
16650
+ const { fileURLToPath: fileURLToPath8 } = await import("node:url");
16651
+ const { dirname: dirname11, join: join35 } = await import("node:path");
16652
+ const { existsSync: existsSync25 } = await import("node:fs");
16381
16653
  const req = createRequire4(import.meta.url);
16382
- const thisDir = dirname10(fileURLToPath7(import.meta.url));
16654
+ const thisDir = dirname11(fileURLToPath8(import.meta.url));
16383
16655
  const candidates = [
16384
- join34(thisDir, "..", "package.json"),
16385
- join34(thisDir, "..", "..", "package.json"),
16386
- join34(thisDir, "..", "..", "..", "package.json")
16656
+ join35(thisDir, "..", "package.json"),
16657
+ join35(thisDir, "..", "..", "package.json"),
16658
+ join35(thisDir, "..", "..", "..", "package.json")
16387
16659
  ];
16388
16660
  for (const pkgPath of candidates) {
16389
- if (existsSync24(pkgPath)) {
16661
+ if (existsSync25(pkgPath)) {
16390
16662
  const pkg = req(pkgPath);
16391
16663
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
16392
16664
  currentVersion = pkg.version ?? "0.0.0";
@@ -16411,9 +16683,9 @@ async function handleUpdate(subcommand, ctx) {
16411
16683
  process.stdout.write(` ${c2.cyan("\u25CF")} Installing update...
16412
16684
 
16413
16685
  `);
16414
- const { execSync: execSync19 } = await import("node:child_process");
16686
+ const { execSync: execSync20 } = await import("node:child_process");
16415
16687
  try {
16416
- execSync19(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { stdio: "pipe", timeout: 18e4 });
16688
+ execSync20(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { stdio: "pipe", timeout: 18e4 });
16417
16689
  } catch {
16418
16690
  renderWarning("Update install failed. Try manually: npm i -g open-agents-ai");
16419
16691
  return;
@@ -16500,10 +16772,10 @@ var init_commands = __esm({
16500
16772
  });
16501
16773
 
16502
16774
  // packages/cli/dist/tui/project-context.js
16503
- import { existsSync as existsSync18, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "node:fs";
16504
- import { join as join24, basename as basename8 } from "node:path";
16505
- import { execSync as execSync16 } from "node:child_process";
16506
- import { homedir as homedir9, platform as platform2, release } from "node:os";
16775
+ import { existsSync as existsSync19, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "node:fs";
16776
+ import { join as join25, basename as basename9 } from "node:path";
16777
+ import { execSync as execSync17 } from "node:child_process";
16778
+ import { homedir as homedir10, platform as platform2, release } from "node:os";
16507
16779
  function getModelTier(modelName) {
16508
16780
  const m = modelName.toLowerCase();
16509
16781
  const sizeMatch = m.match(/\b(\d+)b\b/);
@@ -16536,8 +16808,8 @@ function loadProjectMap(repoRoot) {
16536
16808
  if (!hasOaDirectory(repoRoot)) {
16537
16809
  initOaDirectory(repoRoot);
16538
16810
  }
16539
- const mapPath = join24(repoRoot, OA_DIR, "context", "project-map.md");
16540
- if (existsSync18(mapPath)) {
16811
+ const mapPath = join25(repoRoot, OA_DIR, "context", "project-map.md");
16812
+ if (existsSync19(mapPath)) {
16541
16813
  try {
16542
16814
  const content = readFileSync14(mapPath, "utf-8");
16543
16815
  return content;
@@ -16548,19 +16820,19 @@ function loadProjectMap(repoRoot) {
16548
16820
  }
16549
16821
  function getGitInfo(repoRoot) {
16550
16822
  try {
16551
- execSync16("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
16823
+ execSync17("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
16552
16824
  } catch {
16553
16825
  return "";
16554
16826
  }
16555
16827
  const lines = [];
16556
16828
  try {
16557
- const branch = execSync16("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
16829
+ const branch = execSync17("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
16558
16830
  if (branch)
16559
16831
  lines.push(`Branch: ${branch}`);
16560
16832
  } catch {
16561
16833
  }
16562
16834
  try {
16563
- const status = execSync16("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
16835
+ const status = execSync17("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
16564
16836
  if (status) {
16565
16837
  const changed = status.split("\n").length;
16566
16838
  lines.push(`Working tree: ${changed} changed file(s)`);
@@ -16570,7 +16842,7 @@ function getGitInfo(repoRoot) {
16570
16842
  } catch {
16571
16843
  }
16572
16844
  try {
16573
- const log = execSync16("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
16845
+ const log = execSync17("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
16574
16846
  if (log)
16575
16847
  lines.push(`Recent commits:
16576
16848
  ${log}`);
@@ -16580,33 +16852,33 @@ ${log}`);
16580
16852
  }
16581
16853
  function loadMemoryContext(repoRoot) {
16582
16854
  const sections = [];
16583
- const oaMemDir = join24(repoRoot, OA_DIR, "memory");
16855
+ const oaMemDir = join25(repoRoot, OA_DIR, "memory");
16584
16856
  const oaEntries = loadMemoryDir(oaMemDir, "project");
16585
16857
  if (oaEntries)
16586
16858
  sections.push(oaEntries);
16587
- const legacyMemDir = join24(repoRoot, ".open-agents", "memory");
16588
- if (legacyMemDir !== oaMemDir && existsSync18(legacyMemDir)) {
16859
+ const legacyMemDir = join25(repoRoot, ".open-agents", "memory");
16860
+ if (legacyMemDir !== oaMemDir && existsSync19(legacyMemDir)) {
16589
16861
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
16590
16862
  if (legacyEntries)
16591
16863
  sections.push(legacyEntries);
16592
16864
  }
16593
- const globalMemDir = join24(homedir9(), ".open-agents", "memory");
16865
+ const globalMemDir = join25(homedir10(), ".open-agents", "memory");
16594
16866
  const globalEntries = loadMemoryDir(globalMemDir, "global");
16595
16867
  if (globalEntries)
16596
16868
  sections.push(globalEntries);
16597
16869
  return sections.join("\n\n");
16598
16870
  }
16599
16871
  function loadMemoryDir(memDir, scope) {
16600
- if (!existsSync18(memDir))
16872
+ if (!existsSync19(memDir))
16601
16873
  return "";
16602
16874
  const lines = [];
16603
16875
  try {
16604
16876
  const files = readdirSync8(memDir).filter((f) => f.endsWith(".json"));
16605
16877
  for (const file of files.slice(0, 10)) {
16606
16878
  try {
16607
- const raw = readFileSync14(join24(memDir, file), "utf-8");
16879
+ const raw = readFileSync14(join25(memDir, file), "utf-8");
16608
16880
  const entries = JSON.parse(raw);
16609
- const topic = basename8(file, ".json");
16881
+ const topic = basename9(file, ".json");
16610
16882
  const keys = Object.keys(entries);
16611
16883
  if (keys.length === 0)
16612
16884
  continue;
@@ -17631,12 +17903,12 @@ var init_carousel = __esm({
17631
17903
  });
17632
17904
 
17633
17905
  // packages/cli/dist/tui/carousel-descriptors.js
17634
- import { existsSync as existsSync19, readFileSync as readFileSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
17635
- import { join as join25, basename as basename9 } from "node:path";
17906
+ import { existsSync as existsSync20, readFileSync as readFileSync15, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, readdirSync as readdirSync9 } from "node:fs";
17907
+ import { join as join26, basename as basename10 } from "node:path";
17636
17908
  function loadToolProfile(repoRoot) {
17637
- const filePath = join25(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
17909
+ const filePath = join26(repoRoot, OA_DIR, "context", TOOL_PROFILE_FILE);
17638
17910
  try {
17639
- if (!existsSync19(filePath))
17911
+ if (!existsSync20(filePath))
17640
17912
  return null;
17641
17913
  return JSON.parse(readFileSync15(filePath, "utf-8"));
17642
17914
  } catch {
@@ -17644,9 +17916,9 @@ function loadToolProfile(repoRoot) {
17644
17916
  }
17645
17917
  }
17646
17918
  function saveToolProfile(repoRoot, profile) {
17647
- const contextDir = join25(repoRoot, OA_DIR, "context");
17919
+ const contextDir = join26(repoRoot, OA_DIR, "context");
17648
17920
  mkdirSync8(contextDir, { recursive: true });
17649
- writeFileSync8(join25(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
17921
+ writeFileSync8(join26(contextDir, TOOL_PROFILE_FILE), JSON.stringify(profile, null, 2), "utf-8");
17650
17922
  }
17651
17923
  function categorizeToolCall(toolName) {
17652
17924
  for (const cat of TOOL_CATEGORIES) {
@@ -17704,9 +17976,9 @@ function weightedColor(profile) {
17704
17976
  return selectedCat.colors[Math.floor(Math.random() * selectedCat.colors.length)];
17705
17977
  }
17706
17978
  function loadCachedDescriptors(repoRoot) {
17707
- const filePath = join25(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
17979
+ const filePath = join26(repoRoot, OA_DIR, "context", DESCRIPTOR_FILE);
17708
17980
  try {
17709
- if (!existsSync19(filePath))
17981
+ if (!existsSync20(filePath))
17710
17982
  return null;
17711
17983
  const cached = JSON.parse(readFileSync15(filePath, "utf-8"));
17712
17984
  return cached.phrases.length > 0 ? cached.phrases : null;
@@ -17715,14 +17987,14 @@ function loadCachedDescriptors(repoRoot) {
17715
17987
  }
17716
17988
  }
17717
17989
  function saveCachedDescriptors(repoRoot, phrases, sourceHash) {
17718
- const contextDir = join25(repoRoot, OA_DIR, "context");
17990
+ const contextDir = join26(repoRoot, OA_DIR, "context");
17719
17991
  mkdirSync8(contextDir, { recursive: true });
17720
17992
  const cached = {
17721
17993
  phrases,
17722
17994
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
17723
17995
  sourceHash
17724
17996
  };
17725
- writeFileSync8(join25(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
17997
+ writeFileSync8(join26(contextDir, DESCRIPTOR_FILE), JSON.stringify(cached, null, 2), "utf-8");
17726
17998
  }
17727
17999
  function generateDescriptors(repoRoot) {
17728
18000
  const profile = loadToolProfile(repoRoot);
@@ -17733,7 +18005,7 @@ function generateDescriptors(repoRoot) {
17733
18005
  extractFromSessions(repoRoot, tags);
17734
18006
  extractFromMemory(repoRoot, tags);
17735
18007
  extractFromToolProfile(profile, tags);
17736
- const repoName2 = basename9(repoRoot);
18008
+ const repoName2 = basename10(repoRoot);
17737
18009
  if (repoName2 && !tags.includes(repoName2)) {
17738
18010
  tags.push(repoName2);
17739
18011
  }
@@ -17770,9 +18042,9 @@ function generateDescriptors(repoRoot) {
17770
18042
  return phrases;
17771
18043
  }
17772
18044
  function extractFromPackageJson(repoRoot, tags) {
17773
- const pkgPath = join25(repoRoot, "package.json");
18045
+ const pkgPath = join26(repoRoot, "package.json");
17774
18046
  try {
17775
- if (!existsSync19(pkgPath))
18047
+ if (!existsSync20(pkgPath))
17776
18048
  return;
17777
18049
  const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
17778
18050
  if (pkg.name && typeof pkg.name === "string") {
@@ -17818,7 +18090,7 @@ function extractFromManifests(repoRoot, tags) {
17818
18090
  { file: ".github/workflows", tag: "ci/cd" }
17819
18091
  ];
17820
18092
  for (const check of manifestChecks) {
17821
- if (existsSync19(join25(repoRoot, check.file))) {
18093
+ if (existsSync20(join26(repoRoot, check.file))) {
17822
18094
  tags.push(check.tag);
17823
18095
  }
17824
18096
  }
@@ -17840,16 +18112,16 @@ function extractFromSessions(repoRoot, tags) {
17840
18112
  }
17841
18113
  }
17842
18114
  function extractFromMemory(repoRoot, tags) {
17843
- const memoryDir = join25(repoRoot, OA_DIR, "memory");
18115
+ const memoryDir = join26(repoRoot, OA_DIR, "memory");
17844
18116
  try {
17845
- if (!existsSync19(memoryDir))
18117
+ if (!existsSync20(memoryDir))
17846
18118
  return;
17847
18119
  const files = readdirSync9(memoryDir).filter((f) => f.endsWith(".json"));
17848
18120
  for (const file of files) {
17849
18121
  const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
17850
18122
  tags.push(topic);
17851
18123
  try {
17852
- const data = JSON.parse(readFileSync15(join25(memoryDir, file), "utf-8"));
18124
+ const data = JSON.parse(readFileSync15(join26(memoryDir, file), "utf-8"));
17853
18125
  if (data && typeof data === "object") {
17854
18126
  const keys = Object.keys(data).slice(0, 3);
17855
18127
  for (const key of keys) {
@@ -17984,25 +18256,25 @@ var init_carousel_descriptors = __esm({
17984
18256
  });
17985
18257
 
17986
18258
  // packages/cli/dist/tui/voice.js
17987
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync4 } from "node:fs";
17988
- import { join as join26 } from "node:path";
17989
- import { homedir as homedir10, tmpdir as tmpdir5, platform as platform3 } from "node:os";
17990
- import { execSync as execSync17, spawn as nodeSpawn } from "node:child_process";
18259
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync16, unlinkSync as unlinkSync4 } from "node:fs";
18260
+ import { join as join27 } from "node:path";
18261
+ import { homedir as homedir11, tmpdir as tmpdir6, platform as platform3 } from "node:os";
18262
+ import { execSync as execSync18, spawn as nodeSpawn } from "node:child_process";
17991
18263
  import { createRequire } from "node:module";
17992
18264
  function voiceDir() {
17993
- return join26(homedir10(), ".open-agents", "voice");
18265
+ return join27(homedir11(), ".open-agents", "voice");
17994
18266
  }
17995
18267
  function modelsDir() {
17996
- return join26(voiceDir(), "models");
18268
+ return join27(voiceDir(), "models");
17997
18269
  }
17998
18270
  function modelDir(id) {
17999
- return join26(modelsDir(), id);
18271
+ return join27(modelsDir(), id);
18000
18272
  }
18001
18273
  function modelOnnxPath(id) {
18002
- return join26(modelDir(id), "model.onnx");
18274
+ return join27(modelDir(id), "model.onnx");
18003
18275
  }
18004
18276
  function modelConfigPath(id) {
18005
- return join26(modelDir(id), "config.json");
18277
+ return join27(modelDir(id), "config.json");
18006
18278
  }
18007
18279
  function describeToolCall(toolName, args) {
18008
18280
  const path = args["path"];
@@ -18275,7 +18547,7 @@ var init_voice = __esm({
18275
18547
  const audioData = result["output"].data;
18276
18548
  if (audioData.length === 0)
18277
18549
  return;
18278
- const wavPath = join26(tmpdir5(), `oa-voice-${Date.now()}.wav`);
18550
+ const wavPath = join27(tmpdir6(), `oa-voice-${Date.now()}.wav`);
18279
18551
  this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
18280
18552
  await this.playWav(wavPath);
18281
18553
  try {
@@ -18364,7 +18636,7 @@ var init_voice = __esm({
18364
18636
  const cmd = this.getPlayCommand(path);
18365
18637
  if (!cmd)
18366
18638
  return;
18367
- return new Promise((resolve21) => {
18639
+ return new Promise((resolve22) => {
18368
18640
  const child = nodeSpawn(cmd[0], cmd.slice(1), {
18369
18641
  stdio: "ignore",
18370
18642
  detached: false
@@ -18373,12 +18645,12 @@ var init_voice = __esm({
18373
18645
  child.on("close", () => {
18374
18646
  if (this.currentPlayback === child)
18375
18647
  this.currentPlayback = null;
18376
- resolve21();
18648
+ resolve22();
18377
18649
  });
18378
18650
  child.on("error", () => {
18379
18651
  if (this.currentPlayback === child)
18380
18652
  this.currentPlayback = null;
18381
- resolve21();
18653
+ resolve22();
18382
18654
  });
18383
18655
  setTimeout(() => {
18384
18656
  if (this.currentPlayback === child) {
@@ -18388,7 +18660,7 @@ var init_voice = __esm({
18388
18660
  }
18389
18661
  this.currentPlayback = null;
18390
18662
  }
18391
- resolve21();
18663
+ resolve22();
18392
18664
  }, 15e3);
18393
18665
  });
18394
18666
  }
@@ -18405,7 +18677,7 @@ var init_voice = __esm({
18405
18677
  }
18406
18678
  for (const player of ["paplay", "pw-play", "aplay"]) {
18407
18679
  try {
18408
- execSync17(`which ${player}`, { stdio: "pipe" });
18680
+ execSync18(`which ${player}`, { stdio: "pipe" });
18409
18681
  return [player, path];
18410
18682
  } catch {
18411
18683
  }
@@ -18430,12 +18702,12 @@ var init_voice = __esm({
18430
18702
  const arch = process.arch;
18431
18703
  const isArmLinux = (arch === "arm64" || arch === "arm") && process.platform === "linux";
18432
18704
  mkdirSync9(voiceDir(), { recursive: true });
18433
- const pkgPath = join26(voiceDir(), "package.json");
18705
+ const pkgPath = join27(voiceDir(), "package.json");
18434
18706
  const expectedDeps = {
18435
18707
  "onnxruntime-node": "^1.21.0",
18436
18708
  "phonemizer": "^1.2.1"
18437
18709
  };
18438
- if (existsSync20(pkgPath)) {
18710
+ if (existsSync21(pkgPath)) {
18439
18711
  try {
18440
18712
  const existing = JSON.parse(readFileSync16(pkgPath, "utf8"));
18441
18713
  if (!existing.dependencies?.["phonemizer"]) {
@@ -18445,14 +18717,14 @@ var init_voice = __esm({
18445
18717
  } catch {
18446
18718
  }
18447
18719
  }
18448
- if (!existsSync20(pkgPath)) {
18720
+ if (!existsSync21(pkgPath)) {
18449
18721
  writeFileSync9(pkgPath, JSON.stringify({
18450
18722
  name: "open-agents-voice",
18451
18723
  private: true,
18452
18724
  dependencies: expectedDeps
18453
18725
  }, null, 2));
18454
18726
  }
18455
- const voiceRequire = createRequire(join26(voiceDir(), "index.js"));
18727
+ const voiceRequire = createRequire(join27(voiceDir(), "index.js"));
18456
18728
  try {
18457
18729
  this.ort = voiceRequire("onnxruntime-node");
18458
18730
  } catch {
@@ -18461,7 +18733,7 @@ var init_voice = __esm({
18461
18733
  }
18462
18734
  renderInfo("Installing ONNX runtime for voice synthesis...");
18463
18735
  try {
18464
- execSync17("npm install --no-audit --no-fund", {
18736
+ execSync18("npm install --no-audit --no-fund", {
18465
18737
  cwd: voiceDir(),
18466
18738
  stdio: "pipe",
18467
18739
  timeout: 12e4
@@ -18482,7 +18754,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
18482
18754
  }
18483
18755
  renderInfo("Installing phonemizer for voice synthesis...");
18484
18756
  try {
18485
- execSync17("npm install --no-audit --no-fund", {
18757
+ execSync18("npm install --no-audit --no-fund", {
18486
18758
  cwd: voiceDir(),
18487
18759
  stdio: "pipe",
18488
18760
  timeout: 12e4
@@ -18506,10 +18778,10 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
18506
18778
  const dir = modelDir(id);
18507
18779
  const onnxPath = modelOnnxPath(id);
18508
18780
  const configPath = modelConfigPath(id);
18509
- if (existsSync20(onnxPath) && existsSync20(configPath))
18781
+ if (existsSync21(onnxPath) && existsSync21(configPath))
18510
18782
  return;
18511
18783
  mkdirSync9(dir, { recursive: true });
18512
- if (!existsSync20(configPath)) {
18784
+ if (!existsSync21(configPath)) {
18513
18785
  renderInfo(`Downloading ${model.label} voice config...`);
18514
18786
  const configResp = await fetch(model.configUrl);
18515
18787
  if (!configResp.ok)
@@ -18517,7 +18789,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
18517
18789
  const configText = await configResp.text();
18518
18790
  writeFileSync9(configPath, configText);
18519
18791
  }
18520
- if (!existsSync20(onnxPath)) {
18792
+ if (!existsSync21(onnxPath)) {
18521
18793
  renderInfo(`Downloading ${model.label} voice model (this may take a minute)...`);
18522
18794
  const onnxResp = await fetch(model.onnxUrl);
18523
18795
  if (!onnxResp.ok)
@@ -18553,7 +18825,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
18553
18825
  throw new Error("ONNX runtime not loaded");
18554
18826
  const onnxPath = modelOnnxPath(this.modelId);
18555
18827
  const configPath = modelConfigPath(this.modelId);
18556
- if (!existsSync20(onnxPath) || !existsSync20(configPath)) {
18828
+ if (!existsSync21(onnxPath) || !existsSync21(configPath)) {
18557
18829
  throw new Error(`Model files not found for ${this.modelId}`);
18558
18830
  }
18559
18831
  this.config = JSON.parse(readFileSync16(configPath, "utf8"));
@@ -19057,10 +19329,10 @@ var init_stream_renderer = __esm({
19057
19329
 
19058
19330
  // packages/cli/dist/tui/edit-history.js
19059
19331
  import { appendFileSync, mkdirSync as mkdirSync10 } from "node:fs";
19060
- import { join as join27 } from "node:path";
19332
+ import { join as join28 } from "node:path";
19061
19333
  function createEditHistoryLogger(repoRoot, sessionId) {
19062
- const historyDir = join27(repoRoot, ".oa", "history");
19063
- const logPath = join27(historyDir, "edits.jsonl");
19334
+ const historyDir = join28(repoRoot, ".oa", "history");
19335
+ const logPath = join28(historyDir, "edits.jsonl");
19064
19336
  try {
19065
19337
  mkdirSync10(historyDir, { recursive: true });
19066
19338
  } catch {
@@ -19171,9 +19443,9 @@ var init_edit_history = __esm({
19171
19443
  });
19172
19444
 
19173
19445
  // packages/cli/dist/tui/dream-engine.js
19174
- import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync17, existsSync as existsSync21, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
19175
- import { join as join28, basename as basename10 } from "node:path";
19176
- import { execSync as execSync18 } from "node:child_process";
19446
+ import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10, readFileSync as readFileSync17, existsSync as existsSync22, cpSync, rmSync, readdirSync as readdirSync10 } from "node:fs";
19447
+ import { join as join29, basename as basename11 } from "node:path";
19448
+ import { execSync as execSync19 } from "node:child_process";
19177
19449
  function adaptTool(tool) {
19178
19450
  return {
19179
19451
  name: tool.name,
@@ -19347,12 +19619,12 @@ var init_dream_engine = __esm({
19347
19619
  const content = String(args["content"] ?? "");
19348
19620
  if (!rawPath)
19349
19621
  return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
19350
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join28(this.dreamsDir, basename10(rawPath)) : join28(this.dreamsDir, rawPath);
19622
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join29(this.dreamsDir, basename11(rawPath)) : join29(this.dreamsDir, rawPath);
19351
19623
  if (!targetPath.startsWith(this.dreamsDir)) {
19352
19624
  return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
19353
19625
  }
19354
19626
  try {
19355
- const dir = join28(targetPath, "..");
19627
+ const dir = join29(targetPath, "..");
19356
19628
  mkdirSync11(dir, { recursive: true });
19357
19629
  writeFileSync10(targetPath, content, "utf-8");
19358
19630
  return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
@@ -19382,12 +19654,12 @@ var init_dream_engine = __esm({
19382
19654
  const rawPath = String(args["path"] ?? "");
19383
19655
  const oldStr = String(args["old_string"] ?? "");
19384
19656
  const newStr = String(args["new_string"] ?? "");
19385
- const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join28(this.dreamsDir, basename10(rawPath)) : join28(this.dreamsDir, rawPath);
19657
+ const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join29(this.dreamsDir, basename11(rawPath)) : join29(this.dreamsDir, rawPath);
19386
19658
  if (!targetPath.startsWith(this.dreamsDir)) {
19387
19659
  return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
19388
19660
  }
19389
19661
  try {
19390
- if (!existsSync21(targetPath)) {
19662
+ if (!existsSync22(targetPath)) {
19391
19663
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
19392
19664
  }
19393
19665
  let content = readFileSync17(targetPath, "utf-8");
@@ -19426,7 +19698,7 @@ var init_dream_engine = __esm({
19426
19698
  }
19427
19699
  }
19428
19700
  try {
19429
- const output = execSync18(cmd, {
19701
+ const output = execSync19(cmd, {
19430
19702
  cwd: this.repoRoot,
19431
19703
  timeout: 3e4,
19432
19704
  encoding: "utf-8",
@@ -19449,7 +19721,7 @@ var init_dream_engine = __esm({
19449
19721
  constructor(config, repoRoot) {
19450
19722
  this.config = config;
19451
19723
  this.repoRoot = repoRoot;
19452
- this.dreamsDir = join28(repoRoot, ".oa", "dreams");
19724
+ this.dreamsDir = join29(repoRoot, ".oa", "dreams");
19453
19725
  this.state = {
19454
19726
  mode: "default",
19455
19727
  active: false,
@@ -19521,7 +19793,7 @@ ${result.summary}`;
19521
19793
  if (mode !== "default" || cycle === totalCycles) {
19522
19794
  renderDreamContraction(cycle);
19523
19795
  const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
19524
- const summaryPath = join28(this.dreamsDir, `cycle-${cycle}-summary.md`);
19796
+ const summaryPath = join29(this.dreamsDir, `cycle-${cycle}-summary.md`);
19525
19797
  writeFileSync10(summaryPath, cycleSummary, "utf-8");
19526
19798
  }
19527
19799
  if (mode === "lucid" && !this.abortController.signal.aborted) {
@@ -19644,29 +19916,29 @@ Dreams directory: ${this.dreamsDir}`);
19644
19916
  }
19645
19917
  /** Save workspace backup for lucid mode */
19646
19918
  saveVersionCheckpoint(cycle) {
19647
- const checkpointDir = join28(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
19919
+ const checkpointDir = join29(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
19648
19920
  try {
19649
19921
  mkdirSync11(checkpointDir, { recursive: true });
19650
19922
  try {
19651
- const gitStatus = execSync18("git status --porcelain", {
19923
+ const gitStatus = execSync19("git status --porcelain", {
19652
19924
  cwd: this.repoRoot,
19653
19925
  encoding: "utf-8",
19654
19926
  timeout: 1e4
19655
19927
  });
19656
- const gitDiff = execSync18("git diff", {
19928
+ const gitDiff = execSync19("git diff", {
19657
19929
  cwd: this.repoRoot,
19658
19930
  encoding: "utf-8",
19659
19931
  timeout: 1e4
19660
19932
  });
19661
- const gitHash = execSync18("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
19933
+ const gitHash = execSync19("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
19662
19934
  cwd: this.repoRoot,
19663
19935
  encoding: "utf-8",
19664
19936
  timeout: 5e3
19665
19937
  }).trim();
19666
- writeFileSync10(join28(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
19667
- writeFileSync10(join28(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
19668
- writeFileSync10(join28(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
19669
- writeFileSync10(join28(checkpointDir, "checkpoint.json"), JSON.stringify({
19938
+ writeFileSync10(join29(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
19939
+ writeFileSync10(join29(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
19940
+ writeFileSync10(join29(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
19941
+ writeFileSync10(join29(checkpointDir, "checkpoint.json"), JSON.stringify({
19670
19942
  cycle,
19671
19943
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
19672
19944
  gitHash,
@@ -19674,7 +19946,7 @@ Dreams directory: ${this.dreamsDir}`);
19674
19946
  }, null, 2), "utf-8");
19675
19947
  renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
19676
19948
  } catch {
19677
- writeFileSync10(join28(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
19949
+ writeFileSync10(join29(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
19678
19950
  renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
19679
19951
  }
19680
19952
  } catch (err) {
@@ -19732,14 +20004,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
19732
20004
  ---
19733
20005
  *Auto-generated by open-agents dream engine*
19734
20006
  `;
19735
- writeFileSync10(join28(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
20007
+ writeFileSync10(join29(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
19736
20008
  } catch {
19737
20009
  }
19738
20010
  }
19739
20011
  /** Save dream state for resume/inspection */
19740
20012
  saveDreamState() {
19741
20013
  try {
19742
- writeFileSync10(join28(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
20014
+ writeFileSync10(join29(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
19743
20015
  } catch {
19744
20016
  }
19745
20017
  }
@@ -20571,22 +20843,22 @@ var init_status_bar = __esm({
20571
20843
  import * as readline2 from "node:readline";
20572
20844
  import { Writable } from "node:stream";
20573
20845
  import { cwd } from "node:process";
20574
- import { resolve as resolve18, join as join29, dirname as dirname8, extname as extname9 } from "node:path";
20846
+ import { resolve as resolve19, join as join30, dirname as dirname9, extname as extname9 } from "node:path";
20575
20847
  import { createRequire as createRequire2 } from "node:module";
20576
- import { fileURLToPath as fileURLToPath5 } from "node:url";
20848
+ import { fileURLToPath as fileURLToPath6 } from "node:url";
20577
20849
  import { readFileSync as readFileSync18 } from "node:fs";
20578
- import { existsSync as existsSync22 } from "node:fs";
20850
+ import { existsSync as existsSync23 } from "node:fs";
20579
20851
  function getVersion() {
20580
20852
  try {
20581
20853
  const require2 = createRequire2(import.meta.url);
20582
- const thisDir = dirname8(fileURLToPath5(import.meta.url));
20854
+ const thisDir = dirname9(fileURLToPath6(import.meta.url));
20583
20855
  const candidates = [
20584
- join29(thisDir, "..", "package.json"),
20585
- join29(thisDir, "..", "..", "package.json"),
20586
- join29(thisDir, "..", "..", "..", "package.json")
20856
+ join30(thisDir, "..", "package.json"),
20857
+ join30(thisDir, "..", "..", "package.json"),
20858
+ join30(thisDir, "..", "..", "..", "package.json")
20587
20859
  ];
20588
20860
  for (const pkgPath of candidates) {
20589
- if (existsSync22(pkgPath)) {
20861
+ if (existsSync23(pkgPath)) {
20590
20862
  const pkg = require2(pkgPath);
20591
20863
  if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
20592
20864
  return pkg.version ?? "0.0.0";
@@ -20679,7 +20951,9 @@ function buildTools(repoRoot, config) {
20679
20951
  new DesktopDescribeTool(repoRoot),
20680
20952
  // PDF tools (OCR + text extraction)
20681
20953
  new OcrPdfTool(repoRoot),
20682
- new PdfToTextTool(repoRoot)
20954
+ new PdfToTextTool(repoRoot),
20955
+ // Advanced image OCR (multi-variant preprocessing pipeline)
20956
+ new OcrImageAdvancedTool(repoRoot)
20683
20957
  ];
20684
20958
  return [
20685
20959
  ...executionTools.map(adaptTool2),
@@ -20983,7 +21257,7 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
20983
21257
  } };
20984
21258
  }
20985
21259
  async function startInteractive(config, repoPath) {
20986
- const repoRoot = resolve18(repoPath ?? cwd());
21260
+ const repoRoot = resolve19(repoPath ?? cwd());
20987
21261
  const resumeFlag = process.env.__OA_RESUMED ?? "";
20988
21262
  const isResumed = resumeFlag !== "";
20989
21263
  const hasTaskToResume = resumeFlag === "1";
@@ -21135,14 +21409,14 @@ async function startInteractive(config, repoPath) {
21135
21409
  renderInfo(msg);
21136
21410
  statusBar.endContentWrite();
21137
21411
  }
21138
- }, () => new Promise((resolve21) => {
21412
+ }, () => new Promise((resolve22) => {
21139
21413
  depSudoPromptPending = true;
21140
21414
  depSudoResolver = (pw) => {
21141
21415
  depSudoPromptPending = false;
21142
21416
  depSudoResolver = null;
21143
21417
  if (pw)
21144
21418
  sessionSudoPassword = pw;
21145
- resolve21(pw);
21419
+ resolve22(pw);
21146
21420
  };
21147
21421
  if (statusBar?.isActive) {
21148
21422
  statusBar.beginContentWrite();
@@ -21437,7 +21711,7 @@ async function startInteractive(config, repoPath) {
21437
21711
  listenSetMode(mode) {
21438
21712
  const engine = getListenEngine();
21439
21713
  engine.setMode(mode);
21440
- return mode === "auto" ? "Auto mode: transcriptions auto-submit after 3s silence" : "Confirm mode: press Enter to submit transcriptions";
21714
+ return mode === "auto" ? "Auto mode: transcriptions auto-submit after 3s silence" : "Manual mode: press Enter to submit transcriptions (auto-submit off)";
21441
21715
  },
21442
21716
  async listenStop() {
21443
21717
  const engine = getListenEngine();
@@ -21654,12 +21928,12 @@ Execute this skill now. Follow the behavioral guidance above.`;
21654
21928
  }
21655
21929
  }
21656
21930
  const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
21657
- const isImage = isImagePath(cleanPath) && existsSync22(resolve18(repoRoot, cleanPath));
21658
- const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync22(resolve18(repoRoot, cleanPath));
21931
+ const isImage = isImagePath(cleanPath) && existsSync23(resolve19(repoRoot, cleanPath));
21932
+ const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync23(resolve19(repoRoot, cleanPath));
21659
21933
  if (activeTask) {
21660
21934
  if (isImage) {
21661
21935
  try {
21662
- const imgPath = resolve18(repoRoot, cleanPath);
21936
+ const imgPath = resolve19(repoRoot, cleanPath);
21663
21937
  const imgBuffer = readFileSync18(imgPath);
21664
21938
  const base64 = imgBuffer.toString("base64");
21665
21939
  const ext = extname9(cleanPath).toLowerCase();
@@ -21673,7 +21947,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
21673
21947
  } else if (isMedia) {
21674
21948
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
21675
21949
  const engine = getListenEngine();
21676
- const result = await engine.transcribeFile(resolve18(repoRoot, cleanPath), repoRoot);
21950
+ const result = await engine.transcribeFile(resolve19(repoRoot, cleanPath), repoRoot);
21677
21951
  if (result) {
21678
21952
  const transcript = `[Transcription of ${cleanPath}]
21679
21953
  ${result.text}`;
@@ -21706,7 +21980,7 @@ ${result.text}`;
21706
21980
  if (isMedia && fullInput === input) {
21707
21981
  writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
21708
21982
  const engine = getListenEngine();
21709
- const result = await engine.transcribeFile(resolve18(repoRoot, cleanPath), repoRoot);
21983
+ const result = await engine.transcribeFile(resolve19(repoRoot, cleanPath), repoRoot);
21710
21984
  if (result) {
21711
21985
  fullInput = `The user has provided an audio/video file: ${cleanPath}.
21712
21986
 
@@ -21826,7 +22100,7 @@ ${c2.dim("(Use /quit to exit)")}
21826
22100
  });
21827
22101
  }
21828
22102
  async function runWithTUI(task, config, repoPath) {
21829
- const repoRoot = resolve18(repoPath ?? cwd());
22103
+ const repoRoot = resolve19(repoPath ?? cwd());
21830
22104
  const needsSetup = isFirstRun() || !await isModelAvailable(config);
21831
22105
  if (needsSetup && config.backendType === "ollama") {
21832
22106
  const setupModel = await runSetupWizard(config);
@@ -21931,7 +22205,7 @@ import { glob } from "glob";
21931
22205
  import ignore from "ignore";
21932
22206
  import { readFile as readFile10, stat as stat4 } from "node:fs/promises";
21933
22207
  import { createHash } from "node:crypto";
21934
- import { join as join30, relative as relative3, extname as extname10, basename as basename11 } from "node:path";
22208
+ import { join as join31, relative as relative3, extname as extname10, basename as basename12 } from "node:path";
21935
22209
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
21936
22210
  var init_codebase_indexer = __esm({
21937
22211
  "packages/indexer/dist/codebase-indexer.js"() {
@@ -21975,7 +22249,7 @@ var init_codebase_indexer = __esm({
21975
22249
  const ig = ignore.default();
21976
22250
  if (this.config.respectGitignore) {
21977
22251
  try {
21978
- const gitignoreContent = await readFile10(join30(this.config.rootDir, ".gitignore"), "utf-8");
22252
+ const gitignoreContent = await readFile10(join31(this.config.rootDir, ".gitignore"), "utf-8");
21979
22253
  ig.add(gitignoreContent);
21980
22254
  } catch {
21981
22255
  }
@@ -21990,7 +22264,7 @@ var init_codebase_indexer = __esm({
21990
22264
  for (const relativePath of files) {
21991
22265
  if (ig.ignores(relativePath))
21992
22266
  continue;
21993
- const fullPath = join30(this.config.rootDir, relativePath);
22267
+ const fullPath = join31(this.config.rootDir, relativePath);
21994
22268
  try {
21995
22269
  const fileStat = await stat4(fullPath);
21996
22270
  if (fileStat.size > this.config.maxFileSize)
@@ -22013,7 +22287,7 @@ var init_codebase_indexer = __esm({
22013
22287
  }
22014
22288
  buildTree(files) {
22015
22289
  const root = {
22016
- name: basename11(this.config.rootDir),
22290
+ name: basename12(this.config.rootDir),
22017
22291
  path: this.config.rootDir,
22018
22292
  type: "directory",
22019
22293
  children: []
@@ -22036,7 +22310,7 @@ var init_codebase_indexer = __esm({
22036
22310
  if (!child) {
22037
22311
  child = {
22038
22312
  name: part,
22039
- path: join30(current.path, part),
22313
+ path: join31(current.path, part),
22040
22314
  type: "directory",
22041
22315
  children: []
22042
22316
  };
@@ -22110,18 +22384,18 @@ var index_repo_exports = {};
22110
22384
  __export(index_repo_exports, {
22111
22385
  indexRepoCommand: () => indexRepoCommand
22112
22386
  });
22113
- import { resolve as resolve19 } from "node:path";
22114
- import { existsSync as existsSync23, statSync as statSync9 } from "node:fs";
22387
+ import { resolve as resolve20 } from "node:path";
22388
+ import { existsSync as existsSync24, statSync as statSync10 } from "node:fs";
22115
22389
  import { cwd as cwd2 } from "node:process";
22116
22390
  async function indexRepoCommand(opts, _config) {
22117
- const repoRoot = resolve19(opts.repoPath ?? cwd2());
22391
+ const repoRoot = resolve20(opts.repoPath ?? cwd2());
22118
22392
  printHeader("Index Repository");
22119
22393
  printInfo(`Indexing: ${repoRoot}`);
22120
- if (!existsSync23(repoRoot)) {
22394
+ if (!existsSync24(repoRoot)) {
22121
22395
  printError(`Path does not exist: ${repoRoot}`);
22122
22396
  process.exit(1);
22123
22397
  }
22124
- const stat5 = statSync9(repoRoot);
22398
+ const stat5 = statSync10(repoRoot);
22125
22399
  if (!stat5.isDirectory()) {
22126
22400
  printError(`Path is not a directory: ${repoRoot}`);
22127
22401
  process.exit(1);
@@ -22363,8 +22637,8 @@ var config_exports = {};
22363
22637
  __export(config_exports, {
22364
22638
  configCommand: () => configCommand
22365
22639
  });
22366
- import { join as join31, resolve as resolve20 } from "node:path";
22367
- import { homedir as homedir11 } from "node:os";
22640
+ import { join as join32, resolve as resolve21 } from "node:path";
22641
+ import { homedir as homedir12 } from "node:os";
22368
22642
  import { cwd as cwd3 } from "node:process";
22369
22643
  function coerceForSettings(key, value) {
22370
22644
  if (INT_KEYS.has(key))
@@ -22384,7 +22658,7 @@ async function configCommand(opts, config) {
22384
22658
  return handleShow(opts, config);
22385
22659
  }
22386
22660
  function handleShow(opts, config) {
22387
- const repoRoot = resolve20(opts.repoPath ?? cwd3());
22661
+ const repoRoot = resolve21(opts.repoPath ?? cwd3());
22388
22662
  printHeader("Configuration");
22389
22663
  printSection("Active Settings (merged)");
22390
22664
  printKeyValue("backendUrl", config.backendUrl, 2);
@@ -22416,7 +22690,7 @@ function handleShow(opts, config) {
22416
22690
  }
22417
22691
  }
22418
22692
  printSection("Config File");
22419
- printInfo(`~/.open-agents/config.json (${join31(homedir11(), ".open-agents", "config.json")})`);
22693
+ printInfo(`~/.open-agents/config.json (${join32(homedir12(), ".open-agents", "config.json")})`);
22420
22694
  printSection("Priority Chain");
22421
22695
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
22422
22696
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -22449,13 +22723,13 @@ function handleSet(opts, _config) {
22449
22723
  process.exit(1);
22450
22724
  }
22451
22725
  if (opts.local) {
22452
- const repoRoot = resolve20(opts.repoPath ?? cwd3());
22726
+ const repoRoot = resolve21(opts.repoPath ?? cwd3());
22453
22727
  try {
22454
22728
  initOaDirectory(repoRoot);
22455
22729
  const coerced = coerceForSettings(key, value);
22456
22730
  saveProjectSettings(repoRoot, { [key]: coerced });
22457
22731
  printSuccess(`Project override set: ${key} = ${value}`);
22458
- printInfo(`Saved to ${join31(repoRoot, ".oa", "settings.json")}`);
22732
+ printInfo(`Saved to ${join32(repoRoot, ".oa", "settings.json")}`);
22459
22733
  printInfo("This override applies only when running in this workspace.");
22460
22734
  } catch (err) {
22461
22735
  printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
@@ -22607,7 +22881,7 @@ async function serveVllm(opts, config) {
22607
22881
  await runVllmServer(args, opts.verbose ?? false);
22608
22882
  }
22609
22883
  async function runVllmServer(args, verbose) {
22610
- return new Promise((resolve21, reject) => {
22884
+ return new Promise((resolve22, reject) => {
22611
22885
  const child = spawn9("python", args, {
22612
22886
  stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
22613
22887
  env: { ...process.env }
@@ -22642,10 +22916,10 @@ async function runVllmServer(args, verbose) {
22642
22916
  child.once("exit", (code, signal) => {
22643
22917
  if (signal) {
22644
22918
  printInfo(`vLLM server stopped by signal ${signal}`);
22645
- resolve21();
22919
+ resolve22();
22646
22920
  } else if (code === 0) {
22647
22921
  printSuccess("vLLM server exited cleanly");
22648
- resolve21();
22922
+ resolve22();
22649
22923
  } else {
22650
22924
  printError(`vLLM server exited with code ${code}`);
22651
22925
  reject(new Error(`vLLM exited with code ${code}`));
@@ -22672,9 +22946,9 @@ var eval_exports = {};
22672
22946
  __export(eval_exports, {
22673
22947
  evalCommand: () => evalCommand
22674
22948
  });
22675
- import { tmpdir as tmpdir6 } from "node:os";
22949
+ import { tmpdir as tmpdir7 } from "node:os";
22676
22950
  import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync11 } from "node:fs";
22677
- import { join as join32 } from "node:path";
22951
+ import { join as join33 } from "node:path";
22678
22952
  async function evalCommand(opts, config) {
22679
22953
  const suiteName = opts.suite ?? "basic";
22680
22954
  const suite = SUITES[suiteName];
@@ -22795,9 +23069,9 @@ async function evalCommand(opts, config) {
22795
23069
  process.exit(failed > 0 ? 1 : 0);
22796
23070
  }
22797
23071
  function createTempEvalRepo() {
22798
- const dir = join32(tmpdir6(), `open-agents-eval-${Date.now()}`);
23072
+ const dir = join33(tmpdir7(), `open-agents-eval-${Date.now()}`);
22799
23073
  mkdirSync12(dir, { recursive: true });
22800
- writeFileSync11(join32(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
23074
+ writeFileSync11(join33(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
22801
23075
  return dir;
22802
23076
  }
22803
23077
  var BASIC_SUITE, FULL_SUITE, SUITES;
@@ -22856,8 +23130,8 @@ init_output();
22856
23130
  init_updater();
22857
23131
  import { parseArgs as nodeParseArgs2 } from "node:util";
22858
23132
  import { createRequire as createRequire3 } from "node:module";
22859
- import { fileURLToPath as fileURLToPath6 } from "node:url";
22860
- import { dirname as dirname9, join as join33 } from "node:path";
23133
+ import { fileURLToPath as fileURLToPath7 } from "node:url";
23134
+ import { dirname as dirname10, join as join34 } from "node:path";
22861
23135
 
22862
23136
  // packages/cli/dist/cli.js
22863
23137
  import { createInterface } from "node:readline";
@@ -22964,7 +23238,7 @@ init_output();
22964
23238
  function getVersion2() {
22965
23239
  try {
22966
23240
  const require2 = createRequire3(import.meta.url);
22967
- const pkgPath = join33(dirname9(fileURLToPath6(import.meta.url)), "..", "package.json");
23241
+ const pkgPath = join34(dirname10(fileURLToPath7(import.meta.url)), "..", "package.json");
22968
23242
  const pkg = require2(pkgPath);
22969
23243
  return pkg.version;
22970
23244
  } catch {