open-agents-ai 0.18.0 → 0.19.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/README.md +22 -4
- package/dist/index.js +372 -107
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,6 +32,7 @@ An autonomous multi-turn tool-calling agent that reads your code, makes changes,
|
|
|
32
32
|
- **35 autonomous tools** — file I/O, shell, grep, web search/fetch, memory, sub-agents, background tasks, image/OCR, git, diagnostics, vision, desktop automation, structured files, code sandbox
|
|
33
33
|
- **Moondream vision** — see and interact with the desktop via Moondream VLM (caption, query, detect, point-and-click)
|
|
34
34
|
- **Desktop automation** — vision-guided clicking: describe a UI element in natural language, the agent finds and clicks it
|
|
35
|
+
- **Auto-install desktop deps** — screenshot, mouse, OCR, and image tools auto-install missing system packages (scrot, xdotool, tesseract, imagemagick) on first use
|
|
35
36
|
- **Parallel tool execution** — read-only tools run concurrently via `Promise.allSettled`
|
|
36
37
|
- **Sub-agent delegation** — spawn independent agents for parallel workstreams
|
|
37
38
|
- **Ralph Loop** — iterative task execution that keeps retrying until completion criteria are met
|
|
@@ -226,10 +227,27 @@ python3 -m venv .moondream-venv
|
|
|
226
227
|
|
|
227
228
|
The vision tools auto-detect a running Moondream Station on `localhost:2020`. For cloud inference, set `MOONDREAM_API_KEY` instead.
|
|
228
229
|
|
|
229
|
-
**System
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
**System dependencies (auto-installed on first use):**
|
|
231
|
+
|
|
232
|
+
Desktop tools automatically install missing system packages when first needed. No manual setup required — just use the tool and it handles the rest:
|
|
233
|
+
|
|
234
|
+
| Tool | Linux Package | What It Does |
|
|
235
|
+
|------|--------------|-------------|
|
|
236
|
+
| `scrot` | `apt install scrot` | Screenshot capture |
|
|
237
|
+
| `xdotool` | `apt install xdotool` | Mouse/keyboard automation |
|
|
238
|
+
| `tesseract` | `apt install tesseract-ocr` | OCR text extraction |
|
|
239
|
+
| `identify` | `apt install imagemagick` | Image dimensions/conversion |
|
|
240
|
+
|
|
241
|
+
Supports `apt` (Debian/Ubuntu), `dnf` (Fedora), `pacman` (Arch), and `brew` (macOS). You can also pre-install everything at once:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
./scripts/setup-desktop.sh # Install all desktop deps
|
|
245
|
+
./scripts/setup-desktop.sh --check-only # Just check what's missing
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Vision backend:**
|
|
249
|
+
- Moondream Station (local) — runs entirely on your machine, no API keys needed
|
|
250
|
+
- Moondream Cloud API — set `MOONDREAM_API_KEY` for cloud inference
|
|
233
251
|
|
|
234
252
|
## Interactive TUI
|
|
235
253
|
|
package/dist/index.js
CHANGED
|
@@ -1304,7 +1304,17 @@ ${stdinInput ?? ""}`);
|
|
|
1304
1304
|
let stdout = "";
|
|
1305
1305
|
let stderr = "";
|
|
1306
1306
|
let killed = false;
|
|
1307
|
+
let resolved = false;
|
|
1307
1308
|
const maxBuf = 1024 * 1024;
|
|
1309
|
+
const doResolve = (result) => {
|
|
1310
|
+
if (resolved)
|
|
1311
|
+
return;
|
|
1312
|
+
resolved = true;
|
|
1313
|
+
clearTimeout(timer);
|
|
1314
|
+
if (exitFlushTimer)
|
|
1315
|
+
clearTimeout(exitFlushTimer);
|
|
1316
|
+
resolve19(result);
|
|
1317
|
+
};
|
|
1308
1318
|
const timer = setTimeout(() => {
|
|
1309
1319
|
killed = true;
|
|
1310
1320
|
child.kill("SIGTERM");
|
|
@@ -1315,6 +1325,7 @@ ${stdinInput ?? ""}`);
|
|
|
1315
1325
|
}
|
|
1316
1326
|
}, 5e3);
|
|
1317
1327
|
}, timeout);
|
|
1328
|
+
let exitFlushTimer = null;
|
|
1318
1329
|
child.stdout.on("data", (data) => {
|
|
1319
1330
|
stdout += data.toString();
|
|
1320
1331
|
if (stdout.length > maxBuf) {
|
|
@@ -1331,14 +1342,39 @@ ${stdinInput ?? ""}`);
|
|
|
1331
1342
|
child.stdin.write(stdinInput);
|
|
1332
1343
|
}
|
|
1333
1344
|
child.stdin.end();
|
|
1345
|
+
child.on("exit", (code) => {
|
|
1346
|
+
exitFlushTimer = setTimeout(() => {
|
|
1347
|
+
const durationMs = performance.now() - start;
|
|
1348
|
+
if (killed) {
|
|
1349
|
+
const combined = stdout + stderr;
|
|
1350
|
+
const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
|
|
1351
|
+
const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : "";
|
|
1352
|
+
doResolve({
|
|
1353
|
+
success: false,
|
|
1354
|
+
output: stdout,
|
|
1355
|
+
error: `Command timed out after ${timeout}ms.${hint}`,
|
|
1356
|
+
durationMs
|
|
1357
|
+
});
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
const success = code === 0;
|
|
1361
|
+
doResolve({
|
|
1362
|
+
success,
|
|
1363
|
+
output: stdout + (stderr && success ? `
|
|
1364
|
+
STDERR:
|
|
1365
|
+
${stderr}` : ""),
|
|
1366
|
+
error: success ? void 0 : stderr || `Exit code ${code}`,
|
|
1367
|
+
durationMs
|
|
1368
|
+
});
|
|
1369
|
+
}, 1e3);
|
|
1370
|
+
});
|
|
1334
1371
|
child.on("close", (code) => {
|
|
1335
|
-
clearTimeout(timer);
|
|
1336
1372
|
const durationMs = performance.now() - start;
|
|
1337
1373
|
if (killed) {
|
|
1338
1374
|
const combined = stdout + stderr;
|
|
1339
1375
|
const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
|
|
1340
1376
|
const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : "";
|
|
1341
|
-
|
|
1377
|
+
doResolve({
|
|
1342
1378
|
success: false,
|
|
1343
1379
|
output: stdout,
|
|
1344
1380
|
error: `Command timed out after ${timeout}ms.${hint}`,
|
|
@@ -1347,7 +1383,7 @@ ${stdinInput ?? ""}`);
|
|
|
1347
1383
|
return;
|
|
1348
1384
|
}
|
|
1349
1385
|
const success = code === 0;
|
|
1350
|
-
|
|
1386
|
+
doResolve({
|
|
1351
1387
|
success,
|
|
1352
1388
|
output: stdout + (stderr && success ? `
|
|
1353
1389
|
STDERR:
|
|
@@ -1357,8 +1393,7 @@ ${stderr}` : ""),
|
|
|
1357
1393
|
});
|
|
1358
1394
|
});
|
|
1359
1395
|
child.on("error", (err) => {
|
|
1360
|
-
|
|
1361
|
-
resolve19({
|
|
1396
|
+
doResolve({
|
|
1362
1397
|
success: false,
|
|
1363
1398
|
output: stdout,
|
|
1364
1399
|
error: err.message,
|
|
@@ -3893,10 +3928,173 @@ Exit code: ${task.exitCode ?? "N/A"}`,
|
|
|
3893
3928
|
}
|
|
3894
3929
|
});
|
|
3895
3930
|
|
|
3931
|
+
// packages/execution/dist/system-deps.js
|
|
3932
|
+
import { execSync as execSync6 } from "node:child_process";
|
|
3933
|
+
function detectPackageManager() {
|
|
3934
|
+
if (_detectedPkgManager !== void 0)
|
|
3935
|
+
return _detectedPkgManager;
|
|
3936
|
+
const plat = process.platform;
|
|
3937
|
+
if (plat === "darwin") {
|
|
3938
|
+
_detectedPkgManager = hasCommand("brew") ? "brew" : null;
|
|
3939
|
+
return _detectedPkgManager;
|
|
3940
|
+
}
|
|
3941
|
+
if (plat === "linux") {
|
|
3942
|
+
if (hasCommand("apt-get"))
|
|
3943
|
+
_detectedPkgManager = "apt";
|
|
3944
|
+
else if (hasCommand("dnf"))
|
|
3945
|
+
_detectedPkgManager = "dnf";
|
|
3946
|
+
else if (hasCommand("pacman"))
|
|
3947
|
+
_detectedPkgManager = "pacman";
|
|
3948
|
+
else
|
|
3949
|
+
_detectedPkgManager = null;
|
|
3950
|
+
return _detectedPkgManager;
|
|
3951
|
+
}
|
|
3952
|
+
_detectedPkgManager = null;
|
|
3953
|
+
return null;
|
|
3954
|
+
}
|
|
3955
|
+
function hasCommand(cmd) {
|
|
3956
|
+
try {
|
|
3957
|
+
execSync6(`which ${cmd}`, { stdio: "pipe", timeout: 3e3 });
|
|
3958
|
+
return true;
|
|
3959
|
+
} catch {
|
|
3960
|
+
return false;
|
|
3961
|
+
}
|
|
3962
|
+
}
|
|
3963
|
+
function runInstall(installCmd) {
|
|
3964
|
+
const needsSudo = process.platform === "linux";
|
|
3965
|
+
let cmd = installCmd;
|
|
3966
|
+
if (needsSudo) {
|
|
3967
|
+
if (_sudoPassword) {
|
|
3968
|
+
cmd = `echo ${JSON.stringify(_sudoPassword)} | sudo -S ${installCmd}`;
|
|
3969
|
+
} else {
|
|
3970
|
+
cmd = `sudo -n ${installCmd}`;
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
execSync6(cmd, {
|
|
3974
|
+
stdio: "pipe",
|
|
3975
|
+
timeout: 12e4,
|
|
3976
|
+
// 2 min for package install
|
|
3977
|
+
env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
|
|
3978
|
+
});
|
|
3979
|
+
}
|
|
3980
|
+
function ensureCommand(command) {
|
|
3981
|
+
const cached = _cache.get(command);
|
|
3982
|
+
if (cached)
|
|
3983
|
+
return cached;
|
|
3984
|
+
if (hasCommand(command)) {
|
|
3985
|
+
const result2 = { available: true, installed: false };
|
|
3986
|
+
_cache.set(command, result2);
|
|
3987
|
+
return result2;
|
|
3988
|
+
}
|
|
3989
|
+
const dep = DESKTOP_DEPS.find((d) => d.command === command);
|
|
3990
|
+
if (!dep) {
|
|
3991
|
+
const result2 = {
|
|
3992
|
+
available: false,
|
|
3993
|
+
installed: false,
|
|
3994
|
+
error: `Unknown dependency: ${command}. Cannot auto-install.`
|
|
3995
|
+
};
|
|
3996
|
+
_cache.set(command, result2);
|
|
3997
|
+
return result2;
|
|
3998
|
+
}
|
|
3999
|
+
const pm = detectPackageManager();
|
|
4000
|
+
if (!pm) {
|
|
4001
|
+
const result2 = {
|
|
4002
|
+
available: false,
|
|
4003
|
+
installed: false,
|
|
4004
|
+
error: `No supported package manager found. Install ${command} manually.`
|
|
4005
|
+
};
|
|
4006
|
+
_cache.set(command, result2);
|
|
4007
|
+
return result2;
|
|
4008
|
+
}
|
|
4009
|
+
const pkg = dep.packages[pm];
|
|
4010
|
+
if (!pkg) {
|
|
4011
|
+
const result2 = {
|
|
4012
|
+
available: false,
|
|
4013
|
+
installed: false,
|
|
4014
|
+
error: `No package for ${command} on ${pm}. Install manually.`
|
|
4015
|
+
};
|
|
4016
|
+
_cache.set(command, result2);
|
|
4017
|
+
return result2;
|
|
4018
|
+
}
|
|
4019
|
+
let installCmd;
|
|
4020
|
+
switch (pm) {
|
|
4021
|
+
case "apt":
|
|
4022
|
+
installCmd = `apt-get install -y ${pkg}`;
|
|
4023
|
+
break;
|
|
4024
|
+
case "dnf":
|
|
4025
|
+
installCmd = `dnf install -y ${pkg}`;
|
|
4026
|
+
break;
|
|
4027
|
+
case "pacman":
|
|
4028
|
+
installCmd = `pacman -S --noconfirm ${pkg}`;
|
|
4029
|
+
break;
|
|
4030
|
+
case "brew":
|
|
4031
|
+
installCmd = `brew install ${pkg}`;
|
|
4032
|
+
break;
|
|
4033
|
+
}
|
|
4034
|
+
try {
|
|
4035
|
+
runInstall(installCmd);
|
|
4036
|
+
} catch (err) {
|
|
4037
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4038
|
+
const result2 = {
|
|
4039
|
+
available: false,
|
|
4040
|
+
installed: false,
|
|
4041
|
+
error: `Failed to install ${pkg} via ${pm}: ${msg.slice(0, 200)}`
|
|
4042
|
+
};
|
|
4043
|
+
_cache.set(command, result2);
|
|
4044
|
+
return result2;
|
|
4045
|
+
}
|
|
4046
|
+
if (hasCommand(command)) {
|
|
4047
|
+
const result2 = { available: true, installed: true };
|
|
4048
|
+
_cache.set(command, result2);
|
|
4049
|
+
return result2;
|
|
4050
|
+
}
|
|
4051
|
+
const result = {
|
|
4052
|
+
available: false,
|
|
4053
|
+
installed: false,
|
|
4054
|
+
error: `Installed ${pkg} but ${command} still not found on PATH.`
|
|
4055
|
+
};
|
|
4056
|
+
_cache.set(command, result);
|
|
4057
|
+
return result;
|
|
4058
|
+
}
|
|
4059
|
+
var DESKTOP_DEPS, _detectedPkgManager, _cache, _sudoPassword;
|
|
4060
|
+
var init_system_deps = __esm({
|
|
4061
|
+
"packages/execution/dist/system-deps.js"() {
|
|
4062
|
+
"use strict";
|
|
4063
|
+
DESKTOP_DEPS = [
|
|
4064
|
+
{
|
|
4065
|
+
command: "scrot",
|
|
4066
|
+
packages: { apt: "scrot", dnf: "scrot", pacman: "scrot", brew: "scrot" },
|
|
4067
|
+
description: "Screenshot capture tool",
|
|
4068
|
+
group: "screenshot"
|
|
4069
|
+
},
|
|
4070
|
+
{
|
|
4071
|
+
command: "xdotool",
|
|
4072
|
+
packages: { apt: "xdotool", dnf: "xdotool", pacman: "xdotool" },
|
|
4073
|
+
description: "X11 desktop automation (mouse/keyboard)",
|
|
4074
|
+
group: "click"
|
|
4075
|
+
},
|
|
4076
|
+
{
|
|
4077
|
+
command: "tesseract",
|
|
4078
|
+
packages: { apt: "tesseract-ocr", dnf: "tesseract", pacman: "tesseract", brew: "tesseract" },
|
|
4079
|
+
description: "OCR text extraction engine",
|
|
4080
|
+
group: "ocr"
|
|
4081
|
+
},
|
|
4082
|
+
{
|
|
4083
|
+
command: "identify",
|
|
4084
|
+
packages: { apt: "imagemagick", dnf: "ImageMagick", pacman: "imagemagick", brew: "imagemagick" },
|
|
4085
|
+
description: "Image metadata and conversion (ImageMagick)",
|
|
4086
|
+
group: "image"
|
|
4087
|
+
}
|
|
4088
|
+
];
|
|
4089
|
+
_cache = /* @__PURE__ */ new Map();
|
|
4090
|
+
_sudoPassword = null;
|
|
4091
|
+
}
|
|
4092
|
+
});
|
|
4093
|
+
|
|
3896
4094
|
// packages/execution/dist/tools/image.js
|
|
3897
4095
|
import { existsSync as existsSync7, readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
|
|
3898
4096
|
import { resolve as resolve11, extname as extname2, basename } from "node:path";
|
|
3899
|
-
import { execSync as
|
|
4097
|
+
import { execSync as execSync7 } from "node:child_process";
|
|
3900
4098
|
import { tmpdir } from "node:os";
|
|
3901
4099
|
import { join as join10 } from "node:path";
|
|
3902
4100
|
function isImagePath(path) {
|
|
@@ -3923,7 +4121,7 @@ function getMimeType(filePath) {
|
|
|
3923
4121
|
}
|
|
3924
4122
|
function getImageDimensions(filePath) {
|
|
3925
4123
|
try {
|
|
3926
|
-
const out =
|
|
4124
|
+
const out = execSync7(`identify -format "%w %h" ${JSON.stringify(filePath)}`, {
|
|
3927
4125
|
encoding: "utf8",
|
|
3928
4126
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3929
4127
|
timeout: 5e3
|
|
@@ -3932,9 +4130,23 @@ function getImageDimensions(filePath) {
|
|
|
3932
4130
|
if (w && h)
|
|
3933
4131
|
return { width: w, height: h };
|
|
3934
4132
|
} catch {
|
|
4133
|
+
const dep = ensureCommand("identify");
|
|
4134
|
+
if (dep.installed) {
|
|
4135
|
+
try {
|
|
4136
|
+
const out = execSync7(`identify -format "%w %h" ${JSON.stringify(filePath)}`, {
|
|
4137
|
+
encoding: "utf8",
|
|
4138
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
4139
|
+
timeout: 5e3
|
|
4140
|
+
}).trim();
|
|
4141
|
+
const [w, h] = out.split(" ").map(Number);
|
|
4142
|
+
if (w && h)
|
|
4143
|
+
return { width: w, height: h };
|
|
4144
|
+
} catch {
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
3935
4147
|
}
|
|
3936
4148
|
try {
|
|
3937
|
-
const out =
|
|
4149
|
+
const out = execSync7(`file ${JSON.stringify(filePath)}`, {
|
|
3938
4150
|
encoding: "utf8",
|
|
3939
4151
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3940
4152
|
timeout: 5e3
|
|
@@ -3948,15 +4160,16 @@ function getImageDimensions(filePath) {
|
|
|
3948
4160
|
}
|
|
3949
4161
|
function hasTesseract() {
|
|
3950
4162
|
try {
|
|
3951
|
-
|
|
4163
|
+
execSync7("tesseract --version", { stdio: "pipe", timeout: 5e3 });
|
|
3952
4164
|
return true;
|
|
3953
4165
|
} catch {
|
|
3954
|
-
|
|
4166
|
+
const dep = ensureCommand("tesseract");
|
|
4167
|
+
return dep.available;
|
|
3955
4168
|
}
|
|
3956
4169
|
}
|
|
3957
4170
|
function runOCR(filePath) {
|
|
3958
4171
|
try {
|
|
3959
|
-
return
|
|
4172
|
+
return execSync7(`tesseract ${JSON.stringify(filePath)} stdout 2>/dev/null`, {
|
|
3960
4173
|
encoding: "utf8",
|
|
3961
4174
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3962
4175
|
timeout: 3e4
|
|
@@ -3969,6 +4182,7 @@ var IMAGE_EXTENSIONS, ImageReadTool, ScreenshotTool, OCRTool;
|
|
|
3969
4182
|
var init_image = __esm({
|
|
3970
4183
|
"packages/execution/dist/tools/image.js"() {
|
|
3971
4184
|
"use strict";
|
|
4185
|
+
init_system_deps();
|
|
3972
4186
|
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
3973
4187
|
".png",
|
|
3974
4188
|
".jpg",
|
|
@@ -4089,7 +4303,7 @@ ${ocrText}`);
|
|
|
4089
4303
|
};
|
|
4090
4304
|
}
|
|
4091
4305
|
try {
|
|
4092
|
-
|
|
4306
|
+
execSync7(cmd, { stdio: "pipe", timeout: 1e4 });
|
|
4093
4307
|
} catch (err) {
|
|
4094
4308
|
return {
|
|
4095
4309
|
success: false,
|
|
@@ -4137,7 +4351,7 @@ ${ocrText}`);
|
|
|
4137
4351
|
if (plat === "linux") {
|
|
4138
4352
|
for (const tool of ["scrot", "gnome-screenshot", "import"]) {
|
|
4139
4353
|
try {
|
|
4140
|
-
|
|
4354
|
+
execSync7(`which ${tool}`, { stdio: "pipe" });
|
|
4141
4355
|
if (tool === "scrot") {
|
|
4142
4356
|
if (region === "active")
|
|
4143
4357
|
return `scrot -u ${out}`;
|
|
@@ -4160,6 +4374,16 @@ ${ocrText}`);
|
|
|
4160
4374
|
} catch {
|
|
4161
4375
|
}
|
|
4162
4376
|
}
|
|
4377
|
+
const dep = ensureCommand("scrot");
|
|
4378
|
+
if (dep.available) {
|
|
4379
|
+
if (region === "active")
|
|
4380
|
+
return `scrot -u ${out}`;
|
|
4381
|
+
if (region !== "full" && region.includes(",")) {
|
|
4382
|
+
const [x, y, w, h] = region.split(",").map(Number);
|
|
4383
|
+
return `scrot -a ${x},${y},${w},${h} ${out}`;
|
|
4384
|
+
}
|
|
4385
|
+
return `scrot ${out}`;
|
|
4386
|
+
}
|
|
4163
4387
|
}
|
|
4164
4388
|
return null;
|
|
4165
4389
|
}
|
|
@@ -4204,7 +4428,7 @@ ${ocrText}`);
|
|
|
4204
4428
|
return {
|
|
4205
4429
|
success: false,
|
|
4206
4430
|
output: "",
|
|
4207
|
-
error: "Tesseract not
|
|
4431
|
+
error: "Tesseract not available. Auto-install failed. Try manually: sudo apt install tesseract-ocr",
|
|
4208
4432
|
durationMs: Date.now() - start
|
|
4209
4433
|
};
|
|
4210
4434
|
}
|
|
@@ -4214,14 +4438,14 @@ ${ocrText}`);
|
|
|
4214
4438
|
if (x != null && y != null && w != null && h != null) {
|
|
4215
4439
|
const croppedPath = join10(tmpdir(), `oa-ocr-crop-${Date.now()}.png`);
|
|
4216
4440
|
try {
|
|
4217
|
-
|
|
4441
|
+
execSync7(`convert ${JSON.stringify(fullPath)} -crop ${w}x${h}+${x}+${y} +repage ${JSON.stringify(croppedPath)}`, { stdio: "pipe", timeout: 1e4 });
|
|
4218
4442
|
inputPath = croppedPath;
|
|
4219
4443
|
} catch {
|
|
4220
4444
|
}
|
|
4221
4445
|
}
|
|
4222
4446
|
}
|
|
4223
4447
|
try {
|
|
4224
|
-
const text =
|
|
4448
|
+
const text = execSync7(`tesseract ${JSON.stringify(inputPath)} stdout -l ${language} --psm ${psm} 2>/dev/null`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e4 }).trim();
|
|
4225
4449
|
if (!text) {
|
|
4226
4450
|
return { success: true, output: "(no text detected in image)", durationMs: Date.now() - start };
|
|
4227
4451
|
}
|
|
@@ -4756,7 +4980,7 @@ var init_tool_creator = __esm({
|
|
|
4756
4980
|
import { existsSync as existsSync9, readdirSync as readdirSync5, readFileSync as readFileSync8 } from "node:fs";
|
|
4757
4981
|
import { join as join12, basename as basename2, dirname as dirname2 } from "node:path";
|
|
4758
4982
|
import { homedir as homedir4 } from "node:os";
|
|
4759
|
-
import { execSync as
|
|
4983
|
+
import { execSync as execSync8 } from "node:child_process";
|
|
4760
4984
|
function getAiwgPaths() {
|
|
4761
4985
|
const dataDir = join12(homedir4(), ".local", "share", "ai-writing-guide");
|
|
4762
4986
|
return {
|
|
@@ -4769,7 +4993,7 @@ function findAiwgPackageRoot() {
|
|
|
4769
4993
|
if (_cachedAiwgPkgRoot !== void 0)
|
|
4770
4994
|
return _cachedAiwgPkgRoot;
|
|
4771
4995
|
try {
|
|
4772
|
-
const globalRoot =
|
|
4996
|
+
const globalRoot = execSync8("npm root -g", {
|
|
4773
4997
|
encoding: "utf-8",
|
|
4774
4998
|
timeout: 5e3,
|
|
4775
4999
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -5156,7 +5380,7 @@ ${content}`,
|
|
|
5156
5380
|
import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4, readFileSync as readFileSync9, unlinkSync } from "node:fs";
|
|
5157
5381
|
import { join as join13, basename as basename3, extname as extname3, resolve as resolve12 } from "node:path";
|
|
5158
5382
|
import { homedir as homedir5 } from "node:os";
|
|
5159
|
-
import { execSync as
|
|
5383
|
+
import { execSync as execSync9, spawn as spawn4 } from "node:child_process";
|
|
5160
5384
|
function isTranscribable(path) {
|
|
5161
5385
|
const ext = extname3(path).toLowerCase();
|
|
5162
5386
|
return AUDIO_EXTS.has(ext) || VIDEO_EXTS.has(ext);
|
|
@@ -5166,7 +5390,7 @@ async function loadTranscribeCli() {
|
|
|
5166
5390
|
return _tcModule;
|
|
5167
5391
|
_tcChecked = true;
|
|
5168
5392
|
try {
|
|
5169
|
-
const globalRoot =
|
|
5393
|
+
const globalRoot = execSync9("npm root -g", {
|
|
5170
5394
|
encoding: "utf-8",
|
|
5171
5395
|
timeout: 5e3,
|
|
5172
5396
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -5331,7 +5555,7 @@ var init_transcribe_tool = __esm({
|
|
|
5331
5555
|
const args = [filePath, "-m", model, "-f", "txt"];
|
|
5332
5556
|
if (diarize)
|
|
5333
5557
|
args.push("--diarize");
|
|
5334
|
-
const output =
|
|
5558
|
+
const output = execSync9(`transcribe-cli ${args.join(" ")}`, {
|
|
5335
5559
|
encoding: "utf-8",
|
|
5336
5560
|
timeout: 3e5,
|
|
5337
5561
|
// 5 min max
|
|
@@ -5398,12 +5622,12 @@ var init_transcribe_tool = __esm({
|
|
|
5398
5622
|
const tmpFile = join13(tmpDir, `download-${Date.now()}${ext}`);
|
|
5399
5623
|
try {
|
|
5400
5624
|
try {
|
|
5401
|
-
|
|
5625
|
+
execSync9(`curl -sL -o "${tmpFile}" "${url}"`, {
|
|
5402
5626
|
timeout: 12e4,
|
|
5403
5627
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5404
5628
|
});
|
|
5405
5629
|
} catch {
|
|
5406
|
-
|
|
5630
|
+
execSync9(`wget -q -O "${tmpFile}" "${url}"`, {
|
|
5407
5631
|
timeout: 12e4,
|
|
5408
5632
|
stdio: ["pipe", "pipe", "pipe"]
|
|
5409
5633
|
});
|
|
@@ -6216,7 +6440,7 @@ ${parts.join("\n\n")}`,
|
|
|
6216
6440
|
|
|
6217
6441
|
// packages/execution/dist/tools/vision.js
|
|
6218
6442
|
import { readFileSync as readFileSync10, existsSync as existsSync11, statSync as statSync5 } from "node:fs";
|
|
6219
|
-
import { execSync as
|
|
6443
|
+
import { execSync as execSync10, spawn as spawn6 } from "node:child_process";
|
|
6220
6444
|
import { resolve as resolve15, extname as extname6, basename as basename4, dirname as dirname4, join as join15 } from "node:path";
|
|
6221
6445
|
import { fileURLToPath } from "node:url";
|
|
6222
6446
|
async function probeStation(endpoint) {
|
|
@@ -6240,14 +6464,14 @@ function findStationBinary() {
|
|
|
6240
6464
|
for (const p of localVenvPaths) {
|
|
6241
6465
|
if (existsSync11(p)) {
|
|
6242
6466
|
try {
|
|
6243
|
-
|
|
6467
|
+
execSync10(`${JSON.stringify(p)} -c "import moondream_station"`, { stdio: "pipe", timeout: 5e3 });
|
|
6244
6468
|
return p;
|
|
6245
6469
|
} catch {
|
|
6246
6470
|
}
|
|
6247
6471
|
}
|
|
6248
6472
|
}
|
|
6249
6473
|
try {
|
|
6250
|
-
const path =
|
|
6474
|
+
const path = execSync10("which moondream-station", { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 3e3 }).trim();
|
|
6251
6475
|
if (path)
|
|
6252
6476
|
return path;
|
|
6253
6477
|
} catch {
|
|
@@ -6518,13 +6742,13 @@ Coordinates are normalized (0-1). Multiply by image width/height for pixel value
|
|
|
6518
6742
|
|
|
6519
6743
|
// packages/execution/dist/tools/desktop-click.js
|
|
6520
6744
|
import { readFileSync as readFileSync11, existsSync as existsSync12 } from "node:fs";
|
|
6521
|
-
import { execSync as
|
|
6745
|
+
import { execSync as execSync11 } from "node:child_process";
|
|
6522
6746
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
6523
6747
|
import { join as join16, dirname as dirname5 } from "node:path";
|
|
6524
6748
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
6525
|
-
function
|
|
6749
|
+
function hasCommand2(cmd) {
|
|
6526
6750
|
try {
|
|
6527
|
-
|
|
6751
|
+
execSync11(`which ${cmd}`, { stdio: "pipe", timeout: 3e3 });
|
|
6528
6752
|
return true;
|
|
6529
6753
|
} catch {
|
|
6530
6754
|
return false;
|
|
@@ -6532,7 +6756,7 @@ function hasCommand(cmd) {
|
|
|
6532
6756
|
}
|
|
6533
6757
|
function getImageDimensions2(filePath) {
|
|
6534
6758
|
try {
|
|
6535
|
-
const out =
|
|
6759
|
+
const out = execSync11(`identify -format "%w %h" ${JSON.stringify(filePath)}`, {
|
|
6536
6760
|
encoding: "utf8",
|
|
6537
6761
|
stdio: ["pipe", "pipe", "pipe"],
|
|
6538
6762
|
timeout: 5e3
|
|
@@ -6543,14 +6767,14 @@ function getImageDimensions2(filePath) {
|
|
|
6543
6767
|
} catch {
|
|
6544
6768
|
}
|
|
6545
6769
|
try {
|
|
6546
|
-
const out =
|
|
6770
|
+
const out = execSync11(`python3 -c "from PIL import Image; i=Image.open(${JSON.stringify(filePath)}); print(i.size[0], i.size[1])"`, { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }).trim();
|
|
6547
6771
|
const [w, h] = out.split(" ").map(Number);
|
|
6548
6772
|
if (w && h)
|
|
6549
6773
|
return { width: w, height: h };
|
|
6550
6774
|
} catch {
|
|
6551
6775
|
}
|
|
6552
6776
|
try {
|
|
6553
|
-
const out =
|
|
6777
|
+
const out = execSync11(`file ${JSON.stringify(filePath)}`, {
|
|
6554
6778
|
encoding: "utf8",
|
|
6555
6779
|
stdio: ["pipe", "pipe", "pipe"],
|
|
6556
6780
|
timeout: 5e3
|
|
@@ -6569,25 +6793,30 @@ function captureScreenshot(outputPath) {
|
|
|
6569
6793
|
if (plat === "darwin") {
|
|
6570
6794
|
cmd = `screencapture ${out}`;
|
|
6571
6795
|
} else if (plat === "linux") {
|
|
6572
|
-
if (
|
|
6796
|
+
if (hasCommand2("scrot")) {
|
|
6573
6797
|
cmd = `scrot ${out}`;
|
|
6574
|
-
} else if (
|
|
6798
|
+
} else if (hasCommand2("gnome-screenshot")) {
|
|
6575
6799
|
cmd = `gnome-screenshot -f ${out}`;
|
|
6576
|
-
} else if (
|
|
6800
|
+
} else if (hasCommand2("import")) {
|
|
6577
6801
|
cmd = `import -window root ${out}`;
|
|
6578
6802
|
} else {
|
|
6579
|
-
|
|
6580
|
-
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6803
|
+
const dep = ensureCommand("scrot");
|
|
6804
|
+
if (dep.available) {
|
|
6805
|
+
cmd = `scrot ${out}`;
|
|
6806
|
+
} else {
|
|
6807
|
+
try {
|
|
6808
|
+
execSync11(`DISPLAY=:0 python3 -c "from PIL import ImageGrab; ImageGrab.grab().save(${JSON.stringify(outputPath)})"`, { stdio: "pipe", timeout: 1e4 });
|
|
6809
|
+
if (existsSync12(outputPath))
|
|
6810
|
+
return;
|
|
6811
|
+
} catch {
|
|
6812
|
+
}
|
|
6584
6813
|
}
|
|
6585
6814
|
}
|
|
6586
6815
|
}
|
|
6587
6816
|
if (!cmd) {
|
|
6588
|
-
throw new Error("No screenshot tool found.
|
|
6817
|
+
throw new Error("No screenshot tool found. Auto-install failed. Try manually: sudo apt install scrot");
|
|
6589
6818
|
}
|
|
6590
|
-
|
|
6819
|
+
execSync11(cmd, { stdio: "pipe", timeout: 1e4 });
|
|
6591
6820
|
if (!existsSync12(outputPath)) {
|
|
6592
6821
|
throw new Error("Screenshot file was not created");
|
|
6593
6822
|
}
|
|
@@ -6599,12 +6828,17 @@ function clickAt(x, y, button, clickType) {
|
|
|
6599
6828
|
const buttonNum = button === "right" ? 3 : button === "middle" ? 2 : 1;
|
|
6600
6829
|
const clicks = clickType === "double" ? 2 : 1;
|
|
6601
6830
|
if (plat === "linux") {
|
|
6602
|
-
|
|
6603
|
-
|
|
6831
|
+
let hasXdotool = hasCommand2("xdotool");
|
|
6832
|
+
if (!hasXdotool) {
|
|
6833
|
+
const dep = ensureCommand("xdotool");
|
|
6834
|
+
hasXdotool = dep.available;
|
|
6835
|
+
}
|
|
6836
|
+
if (hasXdotool) {
|
|
6837
|
+
execSync11(`xdotool mousemove --sync ${rx} ${ry}`, { stdio: "pipe", timeout: 5e3 });
|
|
6604
6838
|
if (clickType === "double") {
|
|
6605
|
-
|
|
6839
|
+
execSync11(`xdotool click --repeat 2 --delay 50 ${buttonNum}`, { stdio: "pipe", timeout: 5e3 });
|
|
6606
6840
|
} else {
|
|
6607
|
-
|
|
6841
|
+
execSync11(`xdotool click ${buttonNum}`, { stdio: "pipe", timeout: 5e3 });
|
|
6608
6842
|
}
|
|
6609
6843
|
return;
|
|
6610
6844
|
}
|
|
@@ -6628,31 +6862,30 @@ for i in range(${clicks}):
|
|
|
6628
6862
|
if i < ${clicks - 1}:
|
|
6629
6863
|
time.sleep(0.05)
|
|
6630
6864
|
`.trim().replace(/\n/g, "; ");
|
|
6631
|
-
const pythonPaths = ["python3"];
|
|
6632
6865
|
try {
|
|
6633
|
-
|
|
6866
|
+
execSync11(`DISPLAY=:0 python3 -c "${pyScript}"`, { stdio: "pipe", timeout: 5e3 });
|
|
6634
6867
|
return;
|
|
6635
6868
|
} catch {
|
|
6636
6869
|
}
|
|
6637
6870
|
try {
|
|
6638
6871
|
const venvPy = join16(__dirname, "../../../../.moondream-venv/bin/python");
|
|
6639
|
-
|
|
6872
|
+
execSync11(`DISPLAY=:0 ${JSON.stringify(venvPy)} -c "${pyScript}"`, { stdio: "pipe", timeout: 5e3 });
|
|
6640
6873
|
return;
|
|
6641
6874
|
} catch {
|
|
6642
6875
|
}
|
|
6643
|
-
throw new Error("No mouse control available.
|
|
6876
|
+
throw new Error("No mouse control available. Auto-install of xdotool failed. Try manually:\n sudo apt install xdotool");
|
|
6644
6877
|
} else if (plat === "darwin") {
|
|
6645
|
-
if (!
|
|
6878
|
+
if (!hasCommand2("cliclick")) {
|
|
6646
6879
|
throw new Error("cliclick not found. Install with: brew install cliclick");
|
|
6647
6880
|
}
|
|
6648
6881
|
const rx2 = Math.round(x);
|
|
6649
6882
|
const ry2 = Math.round(y);
|
|
6650
6883
|
if (clickType === "double") {
|
|
6651
|
-
|
|
6884
|
+
execSync11(`cliclick dc:${rx2},${ry2}`, { stdio: "pipe", timeout: 5e3 });
|
|
6652
6885
|
} else if (button === "right") {
|
|
6653
|
-
|
|
6886
|
+
execSync11(`cliclick rc:${rx2},${ry2}`, { stdio: "pipe", timeout: 5e3 });
|
|
6654
6887
|
} else {
|
|
6655
|
-
|
|
6888
|
+
execSync11(`cliclick c:${rx2},${ry2}`, { stdio: "pipe", timeout: 5e3 });
|
|
6656
6889
|
}
|
|
6657
6890
|
} else {
|
|
6658
6891
|
throw new Error(`Desktop click not supported on platform: ${plat}`);
|
|
@@ -6662,6 +6895,7 @@ var __dirname, DesktopClickTool, DesktopDescribeTool;
|
|
|
6662
6895
|
var init_desktop_click = __esm({
|
|
6663
6896
|
"packages/execution/dist/tools/desktop-click.js"() {
|
|
6664
6897
|
"use strict";
|
|
6898
|
+
init_system_deps();
|
|
6665
6899
|
__dirname = dirname5(fileURLToPath2(import.meta.url));
|
|
6666
6900
|
DesktopClickTool = class {
|
|
6667
6901
|
workingDir;
|
|
@@ -6991,6 +7225,7 @@ var init_dist2 = __esm({
|
|
|
6991
7225
|
init_structured_read();
|
|
6992
7226
|
init_vision();
|
|
6993
7227
|
init_desktop_click();
|
|
7228
|
+
init_system_deps();
|
|
6994
7229
|
init_shellRunner();
|
|
6995
7230
|
init_gitWorktree();
|
|
6996
7231
|
init_patchApplier();
|
|
@@ -11476,7 +11711,7 @@ var init_dist5 = __esm({
|
|
|
11476
11711
|
});
|
|
11477
11712
|
|
|
11478
11713
|
// packages/cli/dist/tui/listen.js
|
|
11479
|
-
import { spawn as spawn7, execSync as
|
|
11714
|
+
import { spawn as spawn7, execSync as execSync12 } from "node:child_process";
|
|
11480
11715
|
import { existsSync as existsSync13, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
11481
11716
|
import { join as join19 } from "node:path";
|
|
11482
11717
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -11496,7 +11731,7 @@ function findMicCaptureCommand() {
|
|
|
11496
11731
|
const platform3 = process.platform;
|
|
11497
11732
|
if (platform3 === "linux") {
|
|
11498
11733
|
try {
|
|
11499
|
-
|
|
11734
|
+
execSync12("which arecord", { stdio: "pipe" });
|
|
11500
11735
|
return {
|
|
11501
11736
|
cmd: "arecord",
|
|
11502
11737
|
args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
|
|
@@ -11506,7 +11741,7 @@ function findMicCaptureCommand() {
|
|
|
11506
11741
|
}
|
|
11507
11742
|
if (platform3 === "darwin") {
|
|
11508
11743
|
try {
|
|
11509
|
-
|
|
11744
|
+
execSync12("which sox", { stdio: "pipe" });
|
|
11510
11745
|
return {
|
|
11511
11746
|
cmd: "sox",
|
|
11512
11747
|
args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
|
|
@@ -11515,7 +11750,7 @@ function findMicCaptureCommand() {
|
|
|
11515
11750
|
}
|
|
11516
11751
|
}
|
|
11517
11752
|
try {
|
|
11518
|
-
|
|
11753
|
+
execSync12("which ffmpeg", { stdio: "pipe" });
|
|
11519
11754
|
if (platform3 === "linux") {
|
|
11520
11755
|
return {
|
|
11521
11756
|
cmd: "ffmpeg",
|
|
@@ -11564,7 +11799,7 @@ function ensureTranscribeCliBackground() {
|
|
|
11564
11799
|
return;
|
|
11565
11800
|
_bgInstallPromise = (async () => {
|
|
11566
11801
|
try {
|
|
11567
|
-
const globalRoot =
|
|
11802
|
+
const globalRoot = execSync12("npm root -g", {
|
|
11568
11803
|
encoding: "utf-8",
|
|
11569
11804
|
timeout: 5e3,
|
|
11570
11805
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -11671,7 +11906,7 @@ var init_listen = __esm({
|
|
|
11671
11906
|
}
|
|
11672
11907
|
if (!this.transcribeCliAvailable) {
|
|
11673
11908
|
try {
|
|
11674
|
-
|
|
11909
|
+
execSync12("which transcribe-cli", { stdio: "pipe" });
|
|
11675
11910
|
this.transcribeCliAvailable = true;
|
|
11676
11911
|
} catch {
|
|
11677
11912
|
this.transcribeCliAvailable = false;
|
|
@@ -11688,7 +11923,7 @@ var init_listen = __esm({
|
|
|
11688
11923
|
} catch {
|
|
11689
11924
|
}
|
|
11690
11925
|
try {
|
|
11691
|
-
const globalRoot =
|
|
11926
|
+
const globalRoot = execSync12("npm root -g", {
|
|
11692
11927
|
encoding: "utf-8",
|
|
11693
11928
|
timeout: 5e3,
|
|
11694
11929
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -11739,7 +11974,7 @@ var init_listen = __esm({
|
|
|
11739
11974
|
if (!tc) {
|
|
11740
11975
|
this.emit("info", "Installing transcribe-cli...");
|
|
11741
11976
|
try {
|
|
11742
|
-
|
|
11977
|
+
execSync12("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
|
|
11743
11978
|
this.transcribeCliAvailable = null;
|
|
11744
11979
|
tc = await this.loadTranscribeCli();
|
|
11745
11980
|
} catch {
|
|
@@ -11750,14 +11985,23 @@ var init_listen = __esm({
|
|
|
11750
11985
|
}
|
|
11751
11986
|
}
|
|
11752
11987
|
const TranscribeLive = tc.TranscribeLive;
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11988
|
+
if (!TranscribeLive) {
|
|
11989
|
+
return "transcribe-cli does not export TranscribeLive. Try updating: npm i -g transcribe-cli@latest";
|
|
11990
|
+
}
|
|
11991
|
+
try {
|
|
11992
|
+
this.liveTranscriber = new TranscribeLive({
|
|
11993
|
+
model: this.config.model,
|
|
11994
|
+
sampleRate: 16e3,
|
|
11995
|
+
channels: 1,
|
|
11996
|
+
sampleWidth: 2,
|
|
11997
|
+
chunkDuration: 3
|
|
11998
|
+
// 3s chunks for responsive transcription
|
|
11999
|
+
});
|
|
12000
|
+
} catch (err) {
|
|
12001
|
+
const arch = process.arch;
|
|
12002
|
+
const armHint = arch === "arm64" || arch === "arm" ? ` Live transcription may not be supported on ${process.platform}-${arch}.` : "";
|
|
12003
|
+
return `Failed to create live transcriber.${armHint} Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
12004
|
+
}
|
|
11761
12005
|
this.liveTranscriber.on("transcript", (evt) => {
|
|
11762
12006
|
if (!evt.text.trim())
|
|
11763
12007
|
return;
|
|
@@ -11771,17 +12015,28 @@ var init_listen = __esm({
|
|
|
11771
12015
|
this.liveTranscriber.on("error", (err) => {
|
|
11772
12016
|
this.emit("error", err);
|
|
11773
12017
|
});
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
|
|
11779
|
-
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
|
|
12018
|
+
try {
|
|
12019
|
+
await new Promise((resolve19, reject) => {
|
|
12020
|
+
const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
|
|
12021
|
+
this.liveTranscriber.on("ready", () => {
|
|
12022
|
+
clearTimeout(timeout);
|
|
12023
|
+
resolve19();
|
|
12024
|
+
});
|
|
12025
|
+
this.liveTranscriber.on("error", (err) => {
|
|
12026
|
+
clearTimeout(timeout);
|
|
12027
|
+
reject(err);
|
|
12028
|
+
});
|
|
11783
12029
|
});
|
|
11784
|
-
})
|
|
12030
|
+
} catch (err) {
|
|
12031
|
+
try {
|
|
12032
|
+
this.liveTranscriber.stop();
|
|
12033
|
+
} catch {
|
|
12034
|
+
}
|
|
12035
|
+
this.liveTranscriber = null;
|
|
12036
|
+
const arch = process.arch;
|
|
12037
|
+
const armHint = arch === "arm64" || arch === "arm" ? ` The whisper model or phonemizer WASM may not support ${process.platform}-${arch}. File transcription (/transcribe <file>) may still work.` : "";
|
|
12038
|
+
return `Failed to start live transcription: ${err instanceof Error ? err.message : String(err)}${armHint}`;
|
|
12039
|
+
}
|
|
11785
12040
|
this.micProcess = spawn7(micCmd.cmd, micCmd.args, {
|
|
11786
12041
|
stdio: ["pipe", "pipe", "pipe"],
|
|
11787
12042
|
env: { ...process.env }
|
|
@@ -11876,7 +12131,7 @@ var init_listen = __esm({
|
|
|
11876
12131
|
}
|
|
11877
12132
|
if (!tc) {
|
|
11878
12133
|
try {
|
|
11879
|
-
|
|
12134
|
+
execSync12("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
|
|
11880
12135
|
this.transcribeCliAvailable = null;
|
|
11881
12136
|
tc = await this.loadTranscribeCli();
|
|
11882
12137
|
} catch {
|
|
@@ -13428,7 +13683,7 @@ var init_oa_directory = __esm({
|
|
|
13428
13683
|
|
|
13429
13684
|
// packages/cli/dist/tui/setup.js
|
|
13430
13685
|
import * as readline from "node:readline";
|
|
13431
|
-
import { execSync as
|
|
13686
|
+
import { execSync as execSync13 } from "node:child_process";
|
|
13432
13687
|
import { existsSync as existsSync15, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
13433
13688
|
import { join as join22 } from "node:path";
|
|
13434
13689
|
import { homedir as homedir8 } from "node:os";
|
|
@@ -13438,7 +13693,7 @@ function detectSystemSpecs() {
|
|
|
13438
13693
|
let gpuVramGB = 0;
|
|
13439
13694
|
let gpuName = "";
|
|
13440
13695
|
try {
|
|
13441
|
-
const memInfo =
|
|
13696
|
+
const memInfo = execSync13("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
|
|
13442
13697
|
encoding: "utf8",
|
|
13443
13698
|
timeout: 5e3
|
|
13444
13699
|
});
|
|
@@ -13458,7 +13713,7 @@ function detectSystemSpecs() {
|
|
|
13458
13713
|
} catch {
|
|
13459
13714
|
}
|
|
13460
13715
|
try {
|
|
13461
|
-
const nvidiaSmi =
|
|
13716
|
+
const nvidiaSmi = execSync13("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
|
|
13462
13717
|
const lines = nvidiaSmi.trim().split("\n");
|
|
13463
13718
|
if (lines.length > 0) {
|
|
13464
13719
|
for (const line of lines) {
|
|
@@ -13520,7 +13775,7 @@ function ask(rl, question) {
|
|
|
13520
13775
|
}
|
|
13521
13776
|
function pullModelWithAutoUpdate(tag) {
|
|
13522
13777
|
try {
|
|
13523
|
-
|
|
13778
|
+
execSync13(`ollama pull ${tag}`, {
|
|
13524
13779
|
stdio: "inherit",
|
|
13525
13780
|
timeout: 36e5
|
|
13526
13781
|
// 1 hour max
|
|
@@ -13537,7 +13792,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
13537
13792
|
|
|
13538
13793
|
`);
|
|
13539
13794
|
try {
|
|
13540
|
-
|
|
13795
|
+
execSync13("curl -fsSL https://ollama.com/install.sh | sh", {
|
|
13541
13796
|
stdio: "inherit",
|
|
13542
13797
|
timeout: 3e5
|
|
13543
13798
|
// 5 min max for install
|
|
@@ -13548,7 +13803,7 @@ function pullModelWithAutoUpdate(tag) {
|
|
|
13548
13803
|
process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
|
|
13549
13804
|
|
|
13550
13805
|
`);
|
|
13551
|
-
|
|
13806
|
+
execSync13(`ollama pull ${tag}`, {
|
|
13552
13807
|
stdio: "inherit",
|
|
13553
13808
|
timeout: 36e5
|
|
13554
13809
|
});
|
|
@@ -13869,7 +14124,7 @@ async function doSetup(config, rl) {
|
|
|
13869
14124
|
const modelfilePath = join22(modelDir2, `Modelfile.${customName}`);
|
|
13870
14125
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
13871
14126
|
process.stdout.write(` ${c2.dim("Creating model...")} `);
|
|
13872
|
-
|
|
14127
|
+
execSync13(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
13873
14128
|
stdio: "pipe",
|
|
13874
14129
|
timeout: 12e4
|
|
13875
14130
|
});
|
|
@@ -13954,7 +14209,7 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
|
|
|
13954
14209
|
mkdirSync7(modelDir2, { recursive: true });
|
|
13955
14210
|
const modelfilePath = join22(modelDir2, `Modelfile.${customName}`);
|
|
13956
14211
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
13957
|
-
|
|
14212
|
+
execSync13(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
13958
14213
|
stdio: "pipe",
|
|
13959
14214
|
timeout: 12e4
|
|
13960
14215
|
});
|
|
@@ -14624,9 +14879,9 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
14624
14879
|
process.stdout.write(` ${c2.cyan("\u25CF")} Installing update...
|
|
14625
14880
|
|
|
14626
14881
|
`);
|
|
14627
|
-
const { execSync:
|
|
14882
|
+
const { execSync: execSync17 } = await import("node:child_process");
|
|
14628
14883
|
try {
|
|
14629
|
-
|
|
14884
|
+
execSync17(`npm cache clean --force open-agents-ai 2>/dev/null; npm install -g open-agents-ai@latest --force`, { stdio: "pipe", timeout: 18e4 });
|
|
14630
14885
|
} catch {
|
|
14631
14886
|
renderWarning("Update install failed. Try manually: npm i -g open-agents-ai");
|
|
14632
14887
|
return;
|
|
@@ -14706,7 +14961,7 @@ var init_commands = __esm({
|
|
|
14706
14961
|
// packages/cli/dist/tui/project-context.js
|
|
14707
14962
|
import { existsSync as existsSync16, readFileSync as readFileSync13, readdirSync as readdirSync7 } from "node:fs";
|
|
14708
14963
|
import { join as join23, basename as basename6 } from "node:path";
|
|
14709
|
-
import { execSync as
|
|
14964
|
+
import { execSync as execSync14 } from "node:child_process";
|
|
14710
14965
|
import { homedir as homedir9, platform, release } from "node:os";
|
|
14711
14966
|
function loadProjectFiles(repoRoot) {
|
|
14712
14967
|
const discovered = discoverContextFiles(repoRoot);
|
|
@@ -14737,19 +14992,19 @@ function loadProjectMap(repoRoot) {
|
|
|
14737
14992
|
}
|
|
14738
14993
|
function getGitInfo(repoRoot) {
|
|
14739
14994
|
try {
|
|
14740
|
-
|
|
14995
|
+
execSync14("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
|
|
14741
14996
|
} catch {
|
|
14742
14997
|
return "";
|
|
14743
14998
|
}
|
|
14744
14999
|
const lines = [];
|
|
14745
15000
|
try {
|
|
14746
|
-
const branch =
|
|
15001
|
+
const branch = execSync14("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
14747
15002
|
if (branch)
|
|
14748
15003
|
lines.push(`Branch: ${branch}`);
|
|
14749
15004
|
} catch {
|
|
14750
15005
|
}
|
|
14751
15006
|
try {
|
|
14752
|
-
const status =
|
|
15007
|
+
const status = execSync14("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
14753
15008
|
if (status) {
|
|
14754
15009
|
const changed = status.split("\n").length;
|
|
14755
15010
|
lines.push(`Working tree: ${changed} changed file(s)`);
|
|
@@ -14759,7 +15014,7 @@ function getGitInfo(repoRoot) {
|
|
|
14759
15014
|
} catch {
|
|
14760
15015
|
}
|
|
14761
15016
|
try {
|
|
14762
|
-
const log =
|
|
15017
|
+
const log = execSync14("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
|
|
14763
15018
|
if (log)
|
|
14764
15019
|
lines.push(`Recent commits:
|
|
14765
15020
|
${log}`);
|
|
@@ -15807,7 +16062,7 @@ var init_carousel = __esm({
|
|
|
15807
16062
|
import { existsSync as existsSync17, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "node:fs";
|
|
15808
16063
|
import { join as join24 } from "node:path";
|
|
15809
16064
|
import { homedir as homedir10, tmpdir as tmpdir4, platform as platform2 } from "node:os";
|
|
15810
|
-
import { execSync as
|
|
16065
|
+
import { execSync as execSync15, spawn as nodeSpawn } from "node:child_process";
|
|
15811
16066
|
import { createRequire } from "node:module";
|
|
15812
16067
|
function voiceDir() {
|
|
15813
16068
|
return join24(homedir10(), ".open-agents", "voice");
|
|
@@ -16225,7 +16480,7 @@ var init_voice = __esm({
|
|
|
16225
16480
|
}
|
|
16226
16481
|
for (const player of ["paplay", "pw-play", "aplay"]) {
|
|
16227
16482
|
try {
|
|
16228
|
-
|
|
16483
|
+
execSync15(`which ${player}`, { stdio: "pipe" });
|
|
16229
16484
|
return [player, path];
|
|
16230
16485
|
} catch {
|
|
16231
16486
|
}
|
|
@@ -16247,6 +16502,8 @@ var init_voice = __esm({
|
|
|
16247
16502
|
async ensureRuntime() {
|
|
16248
16503
|
if (this.ort)
|
|
16249
16504
|
return;
|
|
16505
|
+
const arch = process.arch;
|
|
16506
|
+
const isArmLinux = (arch === "arm64" || arch === "arm") && process.platform === "linux";
|
|
16250
16507
|
mkdirSync8(voiceDir(), { recursive: true });
|
|
16251
16508
|
const pkgPath = join24(voiceDir(), "package.json");
|
|
16252
16509
|
const expectedDeps = {
|
|
@@ -16274,16 +16531,20 @@ var init_voice = __esm({
|
|
|
16274
16531
|
try {
|
|
16275
16532
|
this.ort = voiceRequire("onnxruntime-node");
|
|
16276
16533
|
} catch {
|
|
16534
|
+
if (isArmLinux) {
|
|
16535
|
+
throw new Error(`Voice synthesis (onnxruntime-node) is not available on ARM Linux (${arch}). Voice feedback is disabled on this architecture.`);
|
|
16536
|
+
}
|
|
16277
16537
|
renderInfo("Installing ONNX runtime for voice synthesis...");
|
|
16278
16538
|
try {
|
|
16279
|
-
|
|
16539
|
+
execSync15("npm install --no-audit --no-fund", {
|
|
16280
16540
|
cwd: voiceDir(),
|
|
16281
16541
|
stdio: "pipe",
|
|
16282
16542
|
timeout: 12e4
|
|
16283
16543
|
});
|
|
16284
16544
|
this.ort = voiceRequire("onnxruntime-node");
|
|
16285
16545
|
} catch (err) {
|
|
16286
|
-
|
|
16546
|
+
const armHint = arch !== "x64" ? ` onnxruntime-node may not support ${process.platform}-${arch}.` : "";
|
|
16547
|
+
throw new Error(`Failed to install voice dependencies.${armHint} Try manually: cd ${voiceDir()} && npm install
|
|
16287
16548
|
Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
16288
16549
|
}
|
|
16289
16550
|
}
|
|
@@ -16291,9 +16552,12 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
16291
16552
|
const phonemizerMod = voiceRequire("phonemizer");
|
|
16292
16553
|
this.phonemizeFn = phonemizerMod.phonemize ?? phonemizerMod.default?.phonemize ?? phonemizerMod;
|
|
16293
16554
|
} catch {
|
|
16555
|
+
if (isArmLinux) {
|
|
16556
|
+
throw new Error(`Phonemizer (espeak-ng WASM) is not available on ARM Linux (${arch}). Voice feedback is disabled on this architecture.`);
|
|
16557
|
+
}
|
|
16294
16558
|
renderInfo("Installing phonemizer for voice synthesis...");
|
|
16295
16559
|
try {
|
|
16296
|
-
|
|
16560
|
+
execSync15("npm install --no-audit --no-fund", {
|
|
16297
16561
|
cwd: voiceDir(),
|
|
16298
16562
|
stdio: "pipe",
|
|
16299
16563
|
timeout: 12e4
|
|
@@ -16301,7 +16565,8 @@ Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
|
16301
16565
|
const phonemizerMod = voiceRequire("phonemizer");
|
|
16302
16566
|
this.phonemizeFn = phonemizerMod.phonemize ?? phonemizerMod.default?.phonemize ?? phonemizerMod;
|
|
16303
16567
|
} catch (err) {
|
|
16304
|
-
|
|
16568
|
+
const armHint = arch !== "x64" ? ` phonemizer WASM may not support ${process.platform}-${arch}.` : "";
|
|
16569
|
+
throw new Error(`Failed to install phonemizer.${armHint} Try manually: cd ${voiceDir()} && npm install
|
|
16305
16570
|
Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
16306
16571
|
}
|
|
16307
16572
|
}
|
|
@@ -16983,7 +17248,7 @@ var init_edit_history = __esm({
|
|
|
16983
17248
|
// packages/cli/dist/tui/dream-engine.js
|
|
16984
17249
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync15, existsSync as existsSync18, cpSync, rmSync, readdirSync as readdirSync8 } from "node:fs";
|
|
16985
17250
|
import { join as join26, basename as basename7 } from "node:path";
|
|
16986
|
-
import { execSync as
|
|
17251
|
+
import { execSync as execSync16 } from "node:child_process";
|
|
16987
17252
|
function adaptTool(tool) {
|
|
16988
17253
|
return {
|
|
16989
17254
|
name: tool.name,
|
|
@@ -17236,7 +17501,7 @@ var init_dream_engine = __esm({
|
|
|
17236
17501
|
}
|
|
17237
17502
|
}
|
|
17238
17503
|
try {
|
|
17239
|
-
const output =
|
|
17504
|
+
const output = execSync16(cmd, {
|
|
17240
17505
|
cwd: this.repoRoot,
|
|
17241
17506
|
timeout: 3e4,
|
|
17242
17507
|
encoding: "utf-8",
|
|
@@ -17456,17 +17721,17 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
17456
17721
|
try {
|
|
17457
17722
|
mkdirSync10(checkpointDir, { recursive: true });
|
|
17458
17723
|
try {
|
|
17459
|
-
const gitStatus =
|
|
17724
|
+
const gitStatus = execSync16("git status --porcelain", {
|
|
17460
17725
|
cwd: this.repoRoot,
|
|
17461
17726
|
encoding: "utf-8",
|
|
17462
17727
|
timeout: 1e4
|
|
17463
17728
|
});
|
|
17464
|
-
const gitDiff =
|
|
17729
|
+
const gitDiff = execSync16("git diff", {
|
|
17465
17730
|
cwd: this.repoRoot,
|
|
17466
17731
|
encoding: "utf-8",
|
|
17467
17732
|
timeout: 1e4
|
|
17468
17733
|
});
|
|
17469
|
-
const gitHash =
|
|
17734
|
+
const gitHash = execSync16("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
|
|
17470
17735
|
cwd: this.repoRoot,
|
|
17471
17736
|
encoding: "utf-8",
|
|
17472
17737
|
timeout: 5e3
|
package/package.json
CHANGED