open-agents-ai 0.27.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +242 -45
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4019,7 +4019,7 @@ function ensureCommand(command) {
4019
4019
  const result2 = {
4020
4020
  available: false,
4021
4021
  installed: false,
4022
- error: `No supported package manager found. Install ${command} manually.`
4022
+ error: `No supported package manager detected \u2014 ${command} unavailable.`
4023
4023
  };
4024
4024
  _cache.set(command, result2);
4025
4025
  return result2;
@@ -4029,7 +4029,7 @@ function ensureCommand(command) {
4029
4029
  const result2 = {
4030
4030
  available: false,
4031
4031
  installed: false,
4032
- error: `No package for ${command} on ${pm}. Install manually.`
4032
+ error: `No package mapping for ${command} on ${pm} \u2014 cannot auto-install.`
4033
4033
  };
4034
4034
  _cache.set(command, result2);
4035
4035
  return result2;
@@ -6474,6 +6474,17 @@ async function probeStation(endpoint) {
6474
6474
  }
6475
6475
  }
6476
6476
  function findStationBinary() {
6477
+ const oaVenvPython = join15(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "python");
6478
+ if (existsSync11(oaVenvPython)) {
6479
+ try {
6480
+ execSync10(`${JSON.stringify(oaVenvPython)} -c "import moondream_station"`, { stdio: "pipe", timeout: 5e3 });
6481
+ return oaVenvPython;
6482
+ } catch {
6483
+ }
6484
+ }
6485
+ const oaVenvBin = join15(process.env["HOME"] || "/root", ".open-agents", "venv", "bin", "moondream-station");
6486
+ if (existsSync11(oaVenvBin))
6487
+ return oaVenvBin;
6477
6488
  const thisDir = dirname4(fileURLToPath(import.meta.url));
6478
6489
  const localVenvPaths = [
6479
6490
  resolve15(thisDir, "../../../../.moondream-venv/bin/python"),
@@ -14761,62 +14772,220 @@ function isFirstRun() {
14761
14772
  return true;
14762
14773
  }
14763
14774
  }
14764
- async function ensureVisionDeps(onInfo) {
14765
- const log = onInfo ?? (() => {
14766
- });
14775
+ function hasCmd(cmd) {
14767
14776
  try {
14768
- execSync13("which tesseract", { stdio: "pipe", timeout: 3e3 });
14777
+ execSync13(`which ${cmd}`, { stdio: "pipe", timeout: 3e3 });
14778
+ return true;
14769
14779
  } catch {
14770
- log("Installing tesseract-ocr...");
14771
- try {
14772
- const cmds = [
14773
- "sudo -n apt-get install -y tesseract-ocr 2>/dev/null",
14774
- "sudo -n dnf install -y tesseract 2>/dev/null",
14775
- "sudo -n pacman -S --noconfirm tesseract 2>/dev/null",
14776
- "brew install tesseract 2>/dev/null"
14777
- ];
14778
- let installed = false;
14779
- for (const cmd of cmds) {
14780
+ return false;
14781
+ }
14782
+ }
14783
+ function detectPkgManager() {
14784
+ if (hasCmd("apt-get"))
14785
+ return "apt";
14786
+ if (hasCmd("dnf"))
14787
+ return "dnf";
14788
+ if (hasCmd("pacman"))
14789
+ return "pacman";
14790
+ if (hasCmd("brew"))
14791
+ return "brew";
14792
+ return null;
14793
+ }
14794
+ function getVenvDir() {
14795
+ return join22(homedir8(), ".open-agents", "venv");
14796
+ }
14797
+ function hasVenvModule() {
14798
+ try {
14799
+ execSync13("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
14800
+ return true;
14801
+ } catch {
14802
+ return false;
14803
+ }
14804
+ }
14805
+ function ensureVenv(log) {
14806
+ const venvDir = getVenvDir();
14807
+ const venvPip = join22(venvDir, "bin", "pip");
14808
+ if (existsSync15(venvPip))
14809
+ return venvDir;
14810
+ log("Creating Python venv for vision deps...");
14811
+ if (!hasCmd("python3")) {
14812
+ log("python3 not found \u2014 cannot create venv.");
14813
+ return null;
14814
+ }
14815
+ if (!hasVenvModule()) {
14816
+ log("python3 venv module not available \u2014 venv creation skipped.");
14817
+ return null;
14818
+ }
14819
+ try {
14820
+ mkdirSync7(join22(homedir8(), ".open-agents"), { recursive: true });
14821
+ execSync13(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
14822
+ execSync13(`"${join22(venvDir, "bin", "pip")}" install --upgrade pip`, {
14823
+ stdio: "pipe",
14824
+ timeout: 6e4
14825
+ });
14826
+ log("Python venv created at ~/.open-agents/venv");
14827
+ return venvDir;
14828
+ } catch (err) {
14829
+ log(`Failed to create venv: ${err instanceof Error ? err.message : String(err)}`);
14830
+ return null;
14831
+ }
14832
+ }
14833
+ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
14834
+ try {
14835
+ execSync13(`sudo -n ${cmd}`, {
14836
+ stdio: "pipe",
14837
+ timeout: timeoutMs,
14838
+ env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
14839
+ });
14840
+ return true;
14841
+ } catch {
14842
+ return false;
14843
+ }
14844
+ }
14845
+ function runWithSudo(cmd, password, timeoutMs = 12e4) {
14846
+ try {
14847
+ execSync13(`sudo -S ${cmd}`, {
14848
+ input: password + "\n",
14849
+ stdio: ["pipe", "pipe", "pipe"],
14850
+ timeout: timeoutMs,
14851
+ env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
14852
+ });
14853
+ return true;
14854
+ } catch {
14855
+ return false;
14856
+ }
14857
+ }
14858
+ async function sudoInstall(cmd, getSudoPassword, log, cachedPasswordRef, timeoutMs = 12e4) {
14859
+ if (cachedPasswordRef.value) {
14860
+ if (runWithSudo(cmd, cachedPasswordRef.value, timeoutMs))
14861
+ return true;
14862
+ }
14863
+ if (trySudoPasswordless(cmd, timeoutMs))
14864
+ return true;
14865
+ const pw = await getSudoPassword();
14866
+ if (pw) {
14867
+ cachedPasswordRef.value = pw;
14868
+ if (runWithSudo(cmd, pw, timeoutMs))
14869
+ return true;
14870
+ log("Authentication failed \u2014 please re-enter password.");
14871
+ const pw2 = await getSudoPassword();
14872
+ if (pw2) {
14873
+ cachedPasswordRef.value = pw2;
14874
+ if (runWithSudo(cmd, pw2, timeoutMs))
14875
+ return true;
14876
+ }
14877
+ }
14878
+ return false;
14879
+ }
14880
+ async function ensureVisionDeps(onInfo, getSudoPassword) {
14881
+ const log = onInfo ?? (() => {
14882
+ });
14883
+ const cachedPasswordRef = { value: null };
14884
+ const getPassword = getSudoPassword ?? (() => Promise.resolve(null));
14885
+ if (!hasCmd("tesseract")) {
14886
+ const pm2 = detectPkgManager();
14887
+ if (pm2) {
14888
+ const pkgMap = {
14889
+ apt: { cmd: "apt-get install -y tesseract-ocr", needsSudo: true },
14890
+ dnf: { cmd: "dnf install -y tesseract", needsSudo: true },
14891
+ pacman: { cmd: "pacman -S --noconfirm tesseract", needsSudo: true },
14892
+ brew: { cmd: "brew install tesseract", needsSudo: false }
14893
+ };
14894
+ const pkg = pkgMap[pm2];
14895
+ if (pkg.needsSudo) {
14896
+ log("Installing tesseract-ocr...");
14897
+ const ok = await sudoInstall(pkg.cmd, getPassword, log, cachedPasswordRef);
14898
+ if (ok && hasCmd("tesseract")) {
14899
+ log("tesseract-ocr installed successfully.");
14900
+ } else {
14901
+ log("tesseract-ocr could not be installed \u2014 OCR features will be limited.");
14902
+ }
14903
+ } else {
14904
+ log("Installing tesseract-ocr...");
14780
14905
  try {
14781
- execSync13(cmd, { stdio: "pipe", timeout: 6e4 });
14782
- installed = true;
14783
- break;
14906
+ execSync13(pkg.cmd, { stdio: "pipe", timeout: 12e4 });
14907
+ if (hasCmd("tesseract")) {
14908
+ log("tesseract-ocr installed successfully.");
14909
+ } else {
14910
+ log("tesseract-ocr install completed but binary not found \u2014 OCR features will be limited.");
14911
+ }
14784
14912
  } catch {
14913
+ log("tesseract-ocr could not be installed \u2014 OCR features will be limited.");
14785
14914
  }
14786
14915
  }
14787
- if (installed)
14788
- log("Tesseract installed.");
14789
- else
14790
- log("Could not auto-install tesseract (install manually: sudo apt install tesseract-ocr)");
14791
- } catch {
14916
+ } else {
14917
+ log("No supported package manager detected \u2014 tesseract OCR unavailable.");
14792
14918
  }
14793
14919
  }
14794
- try {
14795
- execSync13("which moondream-station", { stdio: "pipe", timeout: 3e3 });
14796
- } catch {
14797
- log("Installing moondream-station...");
14798
- try {
14799
- const pipCmds = [
14800
- "pip3 install moondream-station 2>/dev/null",
14801
- "pip install moondream-station 2>/dev/null",
14802
- "python3 -m pip install moondream-station 2>/dev/null"
14803
- ];
14804
- let installed = false;
14805
- for (const cmd of pipCmds) {
14920
+ const pm = detectPkgManager();
14921
+ if (!hasCmd("pip3") && !hasCmd("pip") && pm) {
14922
+ const pipCmds = {
14923
+ apt: "apt-get install -y python3-pip",
14924
+ dnf: "dnf install -y python3-pip"
14925
+ };
14926
+ const pipCmd = pipCmds[pm];
14927
+ if (pipCmd) {
14928
+ log("Installing python3-pip...");
14929
+ const ok = await sudoInstall(pipCmd, getPassword, log, cachedPasswordRef);
14930
+ if (!ok) {
14931
+ log("python3-pip could not be installed \u2014 moondream-station may be unavailable.");
14932
+ }
14933
+ }
14934
+ }
14935
+ if (hasCmd("python3") && !hasVenvModule() && pm) {
14936
+ const venvCmds = {
14937
+ apt: () => {
14806
14938
  try {
14807
- execSync13(cmd, { stdio: "pipe", timeout: 12e4 });
14808
- installed = true;
14809
- break;
14939
+ const pyVer = execSync13(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
14940
+ return `apt-get install -y python3-venv python${pyVer}-venv`;
14810
14941
  } catch {
14942
+ return "apt-get install -y python3-venv";
14943
+ }
14944
+ },
14945
+ dnf: () => "dnf install -y python3-venv"
14946
+ };
14947
+ const cmdFn = venvCmds[pm];
14948
+ if (cmdFn) {
14949
+ const cmd = cmdFn();
14950
+ if (cmd) {
14951
+ log("Installing python3-venv...");
14952
+ const ok = await sudoInstall(cmd, getPassword, log, cachedPasswordRef);
14953
+ if (!ok) {
14954
+ log("python3-venv could not be installed \u2014 moondream-station may be unavailable.");
14811
14955
  }
14812
14956
  }
14813
- if (installed)
14814
- log("moondream-station installed.");
14815
- else
14816
- log("Could not auto-install moondream-station (install manually: pip install moondream-station)");
14817
- } catch {
14818
14957
  }
14819
14958
  }
14959
+ const venvDir = getVenvDir();
14960
+ const venvBin = join22(venvDir, "bin");
14961
+ const venvMoondream = join22(venvBin, "moondream-station");
14962
+ if (hasCmd("moondream-station") || existsSync15(venvMoondream)) {
14963
+ return;
14964
+ }
14965
+ const venv = ensureVenv(log);
14966
+ if (!venv) {
14967
+ log("Python venv unavailable \u2014 moondream-station will not be installed.");
14968
+ return;
14969
+ }
14970
+ const venvPip = join22(venvBin, "pip");
14971
+ log("Installing moondream-station in ~/.open-agents/venv...");
14972
+ try {
14973
+ execSync13(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
14974
+ if (existsSync15(venvMoondream)) {
14975
+ log("moondream-station installed successfully.");
14976
+ } else {
14977
+ try {
14978
+ const check = execSync13(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
14979
+ if (check.includes("moondream")) {
14980
+ log("moondream-station package installed.");
14981
+ }
14982
+ } catch {
14983
+ log("moondream-station install completed.");
14984
+ }
14985
+ }
14986
+ } catch (err) {
14987
+ log(`moondream-station install failed: ${err instanceof Error ? err.message : String(err)}`);
14988
+ }
14820
14989
  }
14821
14990
  function expandedModelName(baseModel) {
14822
14991
  return `open-agents-${baseModel.replace(":", "-").replace(/\./g, "")}`;
@@ -19667,13 +19836,33 @@ async function startInteractive(config, repoPath) {
19667
19836
  const sessionMetrics = new SessionMetrics();
19668
19837
  const workEvaluator = new WorkEvaluator();
19669
19838
  ensureTranscribeCliBackground();
19839
+ let depSudoResolver = null;
19840
+ let depSudoPromptPending = false;
19670
19841
  ensureVisionDeps((msg) => {
19671
19842
  if (statusBar?.isActive) {
19672
19843
  statusBar.beginContentWrite();
19673
19844
  renderInfo(msg);
19674
19845
  statusBar.endContentWrite();
19675
19846
  }
19676
- }).catch(() => {
19847
+ }, () => new Promise((resolve19) => {
19848
+ depSudoPromptPending = true;
19849
+ depSudoResolver = (pw) => {
19850
+ depSudoPromptPending = false;
19851
+ depSudoResolver = null;
19852
+ if (pw)
19853
+ sessionSudoPassword = pw;
19854
+ resolve19(pw);
19855
+ };
19856
+ if (statusBar?.isActive) {
19857
+ statusBar.beginContentWrite();
19858
+ }
19859
+ process.stdout.write(` ${c2.bold(c2.yellow("\u{1F511} Password needed for dependency install:"))}
19860
+ `);
19861
+ process.stdout.write(` ${c2.bold(c2.yellow("\u{1F511} Password:"))} `);
19862
+ if (statusBar?.isActive) {
19863
+ statusBar.endContentWrite();
19864
+ }
19865
+ })).catch(() => {
19677
19866
  });
19678
19867
  const voiceEngine = new VoiceEngine();
19679
19868
  const streamRenderer = new StreamRenderer();
@@ -20070,6 +20259,14 @@ async function startInteractive(config, repoPath) {
20070
20259
  }, 50);
20071
20260
  });
20072
20261
  async function processLine(input) {
20262
+ if (depSudoPromptPending && depSudoResolver) {
20263
+ const pw = input.trim();
20264
+ process.stdout.write(`\r\x1B[K ${c2.dim("\u{1F511} Password received")}
20265
+ `);
20266
+ depSudoResolver(pw || null);
20267
+ showPrompt();
20268
+ return;
20269
+ }
20073
20270
  if (sudoPromptPending && activeTask) {
20074
20271
  sudoPromptPending = false;
20075
20272
  sessionSudoPassword = input;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",