open-agents-ai 0.149.0 → 0.151.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 +427 -119
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1315,9 +1315,13 @@ var init_shell = __esm({
1315
1315
  this.workingDir = workingDir;
1316
1316
  this.defaultTimeout = defaultTimeout;
1317
1317
  }
1318
- /** Kill all active child processes immediately (called by /stop) */
1318
+ /** Kill all active child processes and their entire process groups (called by /stop) */
1319
1319
  killAll() {
1320
1320
  for (const child of this._activeChildren) {
1321
+ try {
1322
+ process.kill(-child.pid, "SIGKILL");
1323
+ } catch {
1324
+ }
1321
1325
  try {
1322
1326
  child.kill("SIGKILL");
1323
1327
  } catch {
@@ -1380,8 +1384,14 @@ ${stdinInput ?? ""}`);
1380
1384
  NO_COLOR: "1",
1381
1385
  FORCE_COLOR: "0"
1382
1386
  },
1383
- stdio: ["pipe", "pipe", "pipe"]
1387
+ stdio: ["pipe", "pipe", "pipe"],
1388
+ // Process group: `detached: true` puts the child in its own pgid.
1389
+ // On timeout or cleanup, we kill the entire group with `process.kill(-pid)`,
1390
+ // which recursively kills all descendants (npm → vitest → 48 workers).
1391
+ // Without this, child processes survive parent death as orphans.
1392
+ detached: true
1384
1393
  });
1394
+ child.unref();
1385
1395
  this._activeChildren.add(child);
1386
1396
  let stdout = "";
1387
1397
  let stderr = "";
@@ -1399,11 +1409,22 @@ ${stdinInput ?? ""}`);
1399
1409
  };
1400
1410
  const timer = setTimeout(() => {
1401
1411
  killed = true;
1402
- child.kill("SIGTERM");
1412
+ try {
1413
+ process.kill(-child.pid, "SIGTERM");
1414
+ } catch {
1415
+ try {
1416
+ child.kill("SIGTERM");
1417
+ } catch {
1418
+ }
1419
+ }
1403
1420
  setTimeout(() => {
1404
1421
  try {
1405
- child.kill("SIGKILL");
1422
+ process.kill(-child.pid, "SIGKILL");
1406
1423
  } catch {
1424
+ try {
1425
+ child.kill("SIGKILL");
1426
+ } catch {
1427
+ }
1407
1428
  }
1408
1429
  }, 5e3);
1409
1430
  }, timeout);
@@ -12926,8 +12947,11 @@ except NameError:
12926
12947
  PYTHONUNBUFFERED: "1",
12927
12948
  PYTHONDONTWRITEBYTECODE: "1",
12928
12949
  OA_LLM_QUERY_SOCKET: this.ipcPath ?? ""
12929
- }
12950
+ },
12951
+ detached: true
12952
+ // Own process group — killed cleanly on session end
12930
12953
  });
12954
+ this.proc.unref();
12931
12955
  this.proc.on("error", () => {
12932
12956
  });
12933
12957
  const initCode = this.buildInitCode();
@@ -13225,6 +13249,10 @@ print("${sentinel}")
13225
13249
  if (this.proc && !this.proc.killed) {
13226
13250
  try {
13227
13251
  this.proc.stdin?.end();
13252
+ try {
13253
+ process.kill(-this.proc.pid, "SIGTERM");
13254
+ } catch {
13255
+ }
13228
13256
  this.proc.kill("SIGTERM");
13229
13257
  } catch {
13230
13258
  }
@@ -20496,6 +20524,160 @@ var init_repo_map = __esm({
20496
20524
  }
20497
20525
  });
20498
20526
 
20527
+ // packages/execution/dist/tools/process-health.js
20528
+ import { execSync as execSync22 } from "node:child_process";
20529
+ function getSystemStatus() {
20530
+ const lines = ["# System Health\n"];
20531
+ try {
20532
+ const uptime = execSync22("uptime", { encoding: "utf-8", timeout: 3e3 }).trim();
20533
+ const loadMatch = uptime.match(/load average:\s*([\d.]+),\s*([\d.]+),\s*([\d.]+)/);
20534
+ if (loadMatch) {
20535
+ lines.push(`CPU Load: ${loadMatch[1]} (1m) ${loadMatch[2]} (5m) ${loadMatch[3]} (15m)`);
20536
+ }
20537
+ } catch {
20538
+ }
20539
+ try {
20540
+ const cpuCount = __require("node:os").cpus().length;
20541
+ lines.push(`CPU Cores: ${cpuCount}`);
20542
+ } catch {
20543
+ }
20544
+ try {
20545
+ const mem = execSync22("free -h | head -2", { encoding: "utf-8", timeout: 3e3 }).trim();
20546
+ lines.push(`
20547
+ ${mem}`);
20548
+ } catch {
20549
+ }
20550
+ try {
20551
+ const top = execSync22("ps aux --sort=-%cpu | head -8", { encoding: "utf-8", timeout: 3e3 }).trim();
20552
+ lines.push(`
20553
+ Top processes by CPU:
20554
+ ${top}`);
20555
+ } catch {
20556
+ }
20557
+ try {
20558
+ const nodeCount = execSync22("ps aux | grep 'node ' | grep -v grep | wc -l", { encoding: "utf-8", timeout: 3e3 }).trim();
20559
+ lines.push(`
20560
+ Node.js processes: ${nodeCount}`);
20561
+ } catch {
20562
+ }
20563
+ return lines.join("\n");
20564
+ }
20565
+ function findOrphans() {
20566
+ try {
20567
+ const psOutput = execSync22(`ps -eo pid,ppid,%cpu,%mem,etime,args --no-headers 2>/dev/null | grep -E "${OA_PATTERNS}" | grep -v grep`, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
20568
+ if (!psOutput)
20569
+ return "No OA-related orphan processes found.";
20570
+ const myPid = process.pid;
20571
+ const myPpid = process.ppid;
20572
+ const lines = ["OA-related processes:\n"];
20573
+ lines.push(" PID PPID CPU% MEM% ELAPSED COMMAND");
20574
+ lines.push(" " + "-".repeat(75));
20575
+ for (const line of psOutput.split("\n")) {
20576
+ const parts = line.trim().split(/\s+/);
20577
+ const pid = parseInt(parts[0], 10);
20578
+ if (pid === myPid || pid === myPpid)
20579
+ continue;
20580
+ const ppid = parts[1];
20581
+ const cpu = parts[2];
20582
+ const mem = parts[3];
20583
+ const elapsed = parts[4];
20584
+ const cmd = parts.slice(5).join(" ");
20585
+ const shortCmd = cmd.length > 50 ? cmd.slice(0, 47) + "..." : cmd;
20586
+ const isHot = parseFloat(cpu) > 10 ? " \u26A0 HIGH CPU" : "";
20587
+ lines.push(` ${String(pid).padStart(7)} ${String(ppid).padStart(7)} ${String(cpu).padStart(6)} ${String(mem).padStart(5)} ${String(elapsed).padStart(9)} ${shortCmd}${isHot}`);
20588
+ }
20589
+ lines.push(`
20590
+ To kill a process: process_health(action='kill', pid=PID)`);
20591
+ lines.push(`Or from the prompt: /destroy processes --global`);
20592
+ return lines.join("\n");
20593
+ } catch {
20594
+ return "Could not scan for orphan processes.";
20595
+ }
20596
+ }
20597
+ function killProcess(pid) {
20598
+ try {
20599
+ try {
20600
+ process.kill(-pid, "SIGTERM");
20601
+ } catch {
20602
+ }
20603
+ process.kill(pid, "SIGTERM");
20604
+ try {
20605
+ execSync22(`sleep 1 && kill -0 ${pid} 2>/dev/null && kill -9 ${pid} 2>/dev/null`, {
20606
+ timeout: 3e3,
20607
+ stdio: "pipe"
20608
+ });
20609
+ } catch {
20610
+ }
20611
+ return `Killed PID ${pid} (SIGTERM \u2192 SIGKILL)`;
20612
+ } catch (err) {
20613
+ return `Failed to kill PID ${pid}: ${err instanceof Error ? err.message : String(err)}`;
20614
+ }
20615
+ }
20616
+ var OA_PATTERNS, ProcessHealthTool;
20617
+ var init_process_health = __esm({
20618
+ "packages/execution/dist/tools/process-health.js"() {
20619
+ "use strict";
20620
+ OA_PATTERNS = [
20621
+ "open-agents",
20622
+ "nexus-daemon",
20623
+ "vitest",
20624
+ "jest",
20625
+ "esbuild.*--service",
20626
+ "python3 -u -i",
20627
+ "chromium.*headless",
20628
+ "chrome.*headless",
20629
+ "crawlee-scraper",
20630
+ "web_scrape",
20631
+ "start-moondream",
20632
+ "live-whisper"
20633
+ ].join("|");
20634
+ ProcessHealthTool = class {
20635
+ name = "process_health";
20636
+ description = "Check system CPU/memory load and find orphaned processes. Actions: 'status' (CPU + memory + top processes), 'orphans' (find stale OA-related processes), 'kill' (kill a specific PID). Use this when the system feels slow or when a shell command seems stuck.";
20637
+ parameters = {
20638
+ type: "object",
20639
+ properties: {
20640
+ action: {
20641
+ type: "string",
20642
+ enum: ["status", "orphans", "kill"],
20643
+ description: "Action (default: status)"
20644
+ },
20645
+ pid: {
20646
+ type: "number",
20647
+ description: "Process ID to kill (for 'kill' action)"
20648
+ }
20649
+ },
20650
+ required: []
20651
+ };
20652
+ async execute(args) {
20653
+ const action = String(args["action"] ?? "status");
20654
+ const start = performance.now();
20655
+ try {
20656
+ switch (action) {
20657
+ case "status":
20658
+ return { success: true, output: getSystemStatus(), durationMs: performance.now() - start };
20659
+ case "orphans":
20660
+ return { success: true, output: findOrphans(), durationMs: performance.now() - start };
20661
+ case "kill": {
20662
+ const pid = Number(args["pid"]);
20663
+ if (!pid || pid <= 10)
20664
+ return { success: false, output: "", error: "Valid PID required", durationMs: performance.now() - start };
20665
+ if (pid === process.pid || pid === process.ppid) {
20666
+ return { success: false, output: "", error: "Cannot kill self or parent process", durationMs: performance.now() - start };
20667
+ }
20668
+ return { success: true, output: killProcess(pid), durationMs: performance.now() - start };
20669
+ }
20670
+ default:
20671
+ return { success: false, output: "", error: `Unknown action: ${action}`, durationMs: performance.now() - start };
20672
+ }
20673
+ } catch (err) {
20674
+ return { success: false, output: "", error: String(err instanceof Error ? err.message : err), durationMs: performance.now() - start };
20675
+ }
20676
+ }
20677
+ };
20678
+ }
20679
+ });
20680
+
20499
20681
  // packages/execution/dist/tools/fortemi-bridge.js
20500
20682
  import { existsSync as existsSync27, readFileSync as readFileSync20 } from "node:fs";
20501
20683
  import { join as join41 } from "node:path";
@@ -21293,6 +21475,7 @@ __export(dist_exports, {
21293
21475
  OcrPdfTool: () => OcrPdfTool,
21294
21476
  OpenCodeTool: () => OpenCodeTool,
21295
21477
  PdfToTextTool: () => PdfToTextTool,
21478
+ ProcessHealthTool: () => ProcessHealthTool,
21296
21479
  ReflectionIntegrityTool: () => ReflectionIntegrityTool,
21297
21480
  ReminderTool: () => ReminderTool,
21298
21481
  ReplTool: () => ReplTool,
@@ -21430,6 +21613,7 @@ var init_dist2 = __esm({
21430
21613
  init_semantic_map();
21431
21614
  init_change_log();
21432
21615
  init_repo_map();
21616
+ init_process_health();
21433
21617
  init_nexus();
21434
21618
  init_fortemi_bridge();
21435
21619
  init_system_deps();
@@ -28239,7 +28423,7 @@ __export(listen_exports, {
28239
28423
  isVideoPath: () => isVideoPath,
28240
28424
  waitForTranscribeCli: () => waitForTranscribeCli
28241
28425
  });
28242
- import { spawn as spawn15, execSync as execSync22 } from "node:child_process";
28426
+ import { spawn as spawn15, execSync as execSync23 } from "node:child_process";
28243
28427
  import { existsSync as existsSync31, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, readdirSync as readdirSync7 } from "node:fs";
28244
28428
  import { join as join46, dirname as dirname14 } from "node:path";
28245
28429
  import { homedir as homedir10 } from "node:os";
@@ -28261,7 +28445,7 @@ function findMicCaptureCommand() {
28261
28445
  const platform5 = process.platform;
28262
28446
  if (platform5 === "linux") {
28263
28447
  try {
28264
- execSync22("which arecord", { stdio: "pipe" });
28448
+ execSync23("which arecord", { stdio: "pipe" });
28265
28449
  return {
28266
28450
  cmd: "arecord",
28267
28451
  args: ["-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "raw", "-q", "-"]
@@ -28271,7 +28455,7 @@ function findMicCaptureCommand() {
28271
28455
  }
28272
28456
  if (platform5 === "darwin") {
28273
28457
  try {
28274
- execSync22("which sox", { stdio: "pipe" });
28458
+ execSync23("which sox", { stdio: "pipe" });
28275
28459
  return {
28276
28460
  cmd: "sox",
28277
28461
  args: ["-d", "-t", "raw", "-r", "16000", "-c", "1", "-b", "16", "-e", "signed-integer", "-"]
@@ -28280,7 +28464,7 @@ function findMicCaptureCommand() {
28280
28464
  }
28281
28465
  }
28282
28466
  try {
28283
- execSync22("which ffmpeg", { stdio: "pipe" });
28467
+ execSync23("which ffmpeg", { stdio: "pipe" });
28284
28468
  if (platform5 === "linux") {
28285
28469
  return {
28286
28470
  cmd: "ffmpeg",
@@ -28339,7 +28523,7 @@ function findLiveWhisperScript() {
28339
28523
  return p;
28340
28524
  }
28341
28525
  try {
28342
- const globalRoot = execSync22("npm root -g", {
28526
+ const globalRoot = execSync23("npm root -g", {
28343
28527
  encoding: "utf-8",
28344
28528
  timeout: 5e3,
28345
28529
  stdio: ["pipe", "pipe", "pipe"]
@@ -28372,7 +28556,7 @@ function ensureTranscribeCliBackground() {
28372
28556
  return;
28373
28557
  _bgInstallPromise = (async () => {
28374
28558
  try {
28375
- const globalRoot = execSync22("npm root -g", {
28559
+ const globalRoot = execSync23("npm root -g", {
28376
28560
  encoding: "utf-8",
28377
28561
  timeout: 5e3,
28378
28562
  stdio: ["pipe", "pipe", "pipe"]
@@ -28578,7 +28762,7 @@ var init_listen = __esm({
28578
28762
  }
28579
28763
  if (!this.transcribeCliAvailable) {
28580
28764
  try {
28581
- execSync22("which transcribe-cli", { stdio: "pipe" });
28765
+ execSync23("which transcribe-cli", { stdio: "pipe" });
28582
28766
  this.transcribeCliAvailable = true;
28583
28767
  } catch {
28584
28768
  this.transcribeCliAvailable = false;
@@ -28595,7 +28779,7 @@ var init_listen = __esm({
28595
28779
  } catch {
28596
28780
  }
28597
28781
  try {
28598
- const globalRoot = execSync22("npm root -g", {
28782
+ const globalRoot = execSync23("npm root -g", {
28599
28783
  encoding: "utf-8",
28600
28784
  timeout: 5e3,
28601
28785
  stdio: ["pipe", "pipe", "pipe"]
@@ -28645,7 +28829,7 @@ var init_listen = __esm({
28645
28829
  }
28646
28830
  if (!tc) {
28647
28831
  try {
28648
- execSync22("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
28832
+ execSync23("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
28649
28833
  this.transcribeCliAvailable = null;
28650
28834
  tc = await this.loadTranscribeCli();
28651
28835
  } catch {
@@ -28828,7 +29012,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
28828
29012
  }
28829
29013
  if (!tc) {
28830
29014
  try {
28831
- execSync22("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
29015
+ execSync23("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
28832
29016
  this.transcribeCliAvailable = null;
28833
29017
  tc = await this.loadTranscribeCli();
28834
29018
  } catch {
@@ -28882,7 +29066,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
28882
29066
  }
28883
29067
  if (!tc) {
28884
29068
  try {
28885
- execSync22("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
29069
+ execSync23("npm i -g transcribe-cli", { stdio: "pipe", timeout: 18e4 });
28886
29070
  this.transcribeCliAvailable = null;
28887
29071
  tc = await this.loadTranscribeCli();
28888
29072
  } catch {
@@ -33330,7 +33514,9 @@ var init_render = __esm({
33330
33514
  ["/pause", "Pause after current turn finishes (gentle halt, /resume to continue)"],
33331
33515
  ["/stop", "Kill current inference immediately and save state (/resume to continue)"],
33332
33516
  ["/resume", "Resume a paused or stopped task"],
33333
- ["/destroy", "Remove .oa folder, kill all tasks, clear console, and exit"],
33517
+ ["/destroy processes", "Find and kill orphaned OA child processes (this project)"],
33518
+ ["/destroy processes --global", "Kill ALL orphaned OA processes system-wide"],
33519
+ ["/destroy project", "Remove .oa folder, kill all tasks, clear console, and exit"],
33334
33520
  ["/context save", "Force-save session context to .oa/context/"],
33335
33521
  ["/context restore", "Restore context from previous sessions into next task"],
33336
33522
  ["/context show", "Show saved session context status"],
@@ -33387,7 +33573,7 @@ var init_render = __esm({
33387
33573
 
33388
33574
  // packages/cli/dist/tui/voice-session.js
33389
33575
  import { createServer as createServer2 } from "node:http";
33390
- import { spawn as spawn16, execSync as execSync23 } from "node:child_process";
33576
+ import { spawn as spawn16, execSync as execSync24 } from "node:child_process";
33391
33577
  import { EventEmitter as EventEmitter2 } from "node:events";
33392
33578
  function generateFrontendHTML() {
33393
33579
  return `<!DOCTYPE html>
@@ -38017,7 +38203,7 @@ var init_oa_directory = __esm({
38017
38203
 
38018
38204
  // packages/cli/dist/tui/setup.js
38019
38205
  import * as readline from "node:readline";
38020
- import { execSync as execSync24, spawn as spawn18, exec as exec2 } from "node:child_process";
38206
+ import { execSync as execSync25, spawn as spawn18, exec as exec2 } from "node:child_process";
38021
38207
  import { promisify as promisify6 } from "node:util";
38022
38208
  import { existsSync as existsSync36, writeFileSync as writeFileSync15, readFileSync as readFileSync27, appendFileSync as appendFileSync2, mkdirSync as mkdirSync14 } from "node:fs";
38023
38209
  import { join as join52 } from "node:path";
@@ -38028,7 +38214,7 @@ function detectSystemSpecs() {
38028
38214
  let gpuVramGB = 0;
38029
38215
  let gpuName = "";
38030
38216
  try {
38031
- const memInfo = execSync24("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
38217
+ const memInfo = execSync25("free -b 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
38032
38218
  encoding: "utf8",
38033
38219
  timeout: 5e3
38034
38220
  });
@@ -38048,7 +38234,7 @@ function detectSystemSpecs() {
38048
38234
  } catch {
38049
38235
  }
38050
38236
  try {
38051
- const nvidiaSmi = execSync24("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
38237
+ const nvidiaSmi = execSync25("nvidia-smi --query-gpu=memory.total,name --format=csv,noheader,nounits 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
38052
38238
  const lines = nvidiaSmi.trim().split("\n");
38053
38239
  if (lines.length > 0) {
38054
38240
  for (const line of lines) {
@@ -38227,7 +38413,7 @@ function ensureCurl() {
38227
38413
  for (const s of strategies) {
38228
38414
  if (hasCmd(s.check)) {
38229
38415
  try {
38230
- execSync24(s.install, { stdio: "inherit", timeout: 12e4 });
38416
+ execSync25(s.install, { stdio: "inherit", timeout: 12e4 });
38231
38417
  if (hasCmd("curl")) {
38232
38418
  process.stdout.write(` ${c2.green("\u2714")} curl installed via ${s.label}.
38233
38419
  `);
@@ -38241,7 +38427,7 @@ function ensureCurl() {
38241
38427
  }
38242
38428
  if (plat === "darwin") {
38243
38429
  try {
38244
- execSync24("xcode-select --install", { stdio: "inherit", timeout: 3e5 });
38430
+ execSync25("xcode-select --install", { stdio: "inherit", timeout: 3e5 });
38245
38431
  if (hasCmd("curl"))
38246
38432
  return true;
38247
38433
  } catch {
@@ -38276,7 +38462,7 @@ function installOllamaLinux() {
38276
38462
 
38277
38463
  `);
38278
38464
  try {
38279
- execSync24("curl -fsSL https://ollama.com/install.sh | sh", {
38465
+ execSync25("curl -fsSL https://ollama.com/install.sh | sh", {
38280
38466
  stdio: "inherit",
38281
38467
  timeout: 3e5
38282
38468
  });
@@ -38304,7 +38490,7 @@ async function installOllamaMac(_rl) {
38304
38490
 
38305
38491
  `);
38306
38492
  try {
38307
- execSync24('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
38493
+ execSync25('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', { stdio: "inherit", timeout: 6e5 });
38308
38494
  if (!hasCmd("brew")) {
38309
38495
  try {
38310
38496
  const brewPrefix = existsSync36("/opt/homebrew/bin/brew") ? "/opt/homebrew" : "/usr/local";
@@ -38337,7 +38523,7 @@ async function installOllamaMac(_rl) {
38337
38523
 
38338
38524
  `);
38339
38525
  try {
38340
- execSync24("brew install ollama", {
38526
+ execSync25("brew install ollama", {
38341
38527
  stdio: "inherit",
38342
38528
  timeout: 3e5
38343
38529
  });
@@ -38364,7 +38550,7 @@ function installOllamaWindows() {
38364
38550
 
38365
38551
  `);
38366
38552
  try {
38367
- execSync24('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
38553
+ execSync25('powershell -Command "irm https://ollama.com/install.ps1 | iex"', {
38368
38554
  stdio: "inherit",
38369
38555
  timeout: 3e5
38370
38556
  });
@@ -38445,7 +38631,7 @@ async function ensureOllamaRunning(backendUrl, rl) {
38445
38631
  }
38446
38632
  function pullModelWithAutoUpdate(tag) {
38447
38633
  try {
38448
- execSync24(`ollama pull ${tag}`, {
38634
+ execSync25(`ollama pull ${tag}`, {
38449
38635
  stdio: "inherit",
38450
38636
  timeout: 36e5
38451
38637
  // 1 hour max
@@ -38465,7 +38651,7 @@ function pullModelWithAutoUpdate(tag) {
38465
38651
 
38466
38652
  `);
38467
38653
  try {
38468
- execSync24("curl -fsSL https://ollama.com/install.sh | sh", {
38654
+ execSync25("curl -fsSL https://ollama.com/install.sh | sh", {
38469
38655
  stdio: "inherit",
38470
38656
  timeout: 3e5
38471
38657
  // 5 min max for install
@@ -38476,7 +38662,7 @@ function pullModelWithAutoUpdate(tag) {
38476
38662
  process.stdout.write(` ${c2.cyan("\u25CF")} Retrying pull of ${c2.bold(tag)}...
38477
38663
 
38478
38664
  `);
38479
- execSync24(`ollama pull ${tag}`, {
38665
+ execSync25(`ollama pull ${tag}`, {
38480
38666
  stdio: "inherit",
38481
38667
  timeout: 36e5
38482
38668
  });
@@ -38578,7 +38764,7 @@ function ensurePython3() {
38578
38764
  if (plat === "darwin") {
38579
38765
  if (hasCmd("brew")) {
38580
38766
  try {
38581
- execSync24("brew install python3", { stdio: "inherit", timeout: 3e5 });
38767
+ execSync25("brew install python3", { stdio: "inherit", timeout: 3e5 });
38582
38768
  if (hasCmd("python3")) {
38583
38769
  process.stdout.write(` ${c2.green("\u2714")} Python3 installed via Homebrew.
38584
38770
  `);
@@ -38591,7 +38777,7 @@ function ensurePython3() {
38591
38777
  for (const s of strategies) {
38592
38778
  if (hasCmd(s.check)) {
38593
38779
  try {
38594
- execSync24(s.install, { stdio: "inherit", timeout: 12e4 });
38780
+ execSync25(s.install, { stdio: "inherit", timeout: 12e4 });
38595
38781
  if (hasCmd("python3") || hasCmd("python")) {
38596
38782
  process.stdout.write(` ${c2.green("\u2714")} Python3 installed via ${s.label}.
38597
38783
  `);
@@ -38607,11 +38793,11 @@ function ensurePython3() {
38607
38793
  }
38608
38794
  function checkPythonVenv() {
38609
38795
  try {
38610
- execSync24("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
38796
+ execSync25("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
38611
38797
  return true;
38612
38798
  } catch {
38613
38799
  try {
38614
- execSync24("python -m venv --help", { stdio: "pipe", timeout: 5e3 });
38800
+ execSync25("python -m venv --help", { stdio: "pipe", timeout: 5e3 });
38615
38801
  return true;
38616
38802
  } catch {
38617
38803
  return false;
@@ -38630,7 +38816,7 @@ function ensurePythonVenv() {
38630
38816
  for (const s of strategies) {
38631
38817
  if (hasCmd(s.check)) {
38632
38818
  try {
38633
- execSync24(s.install, { stdio: "inherit", timeout: 12e4 });
38819
+ execSync25(s.install, { stdio: "inherit", timeout: 12e4 });
38634
38820
  if (checkPythonVenv()) {
38635
38821
  process.stdout.write(` ${c2.green("\u2714")} python3-venv installed via ${s.label}.
38636
38822
  `);
@@ -39066,7 +39252,7 @@ async function doSetup(config, rl) {
39066
39252
  const modelfilePath = join52(modelDir2, `Modelfile.${customName}`);
39067
39253
  writeFileSync15(modelfilePath, modelfileContent + "\n", "utf8");
39068
39254
  process.stdout.write(` ${c2.dim("Creating model...")} `);
39069
- execSync24(`ollama create ${customName} -f ${modelfilePath}`, {
39255
+ execSync25(`ollama create ${customName} -f ${modelfilePath}`, {
39070
39256
  stdio: "pipe",
39071
39257
  timeout: 12e4
39072
39258
  });
@@ -39117,7 +39303,7 @@ function isFirstRun() {
39117
39303
  function hasCmd(cmd) {
39118
39304
  try {
39119
39305
  const whichCmd = process.platform === "win32" ? `where ${cmd}` : `which ${cmd}`;
39120
- execSync24(whichCmd, { stdio: "pipe", timeout: 3e3 });
39306
+ execSync25(whichCmd, { stdio: "pipe", timeout: 3e3 });
39121
39307
  return true;
39122
39308
  } catch {
39123
39309
  return false;
@@ -39150,7 +39336,7 @@ function getVenvDir() {
39150
39336
  }
39151
39337
  function hasVenvModule() {
39152
39338
  try {
39153
- execSync24("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
39339
+ execSync25("python3 -m venv --help", { stdio: "pipe", timeout: 5e3 });
39154
39340
  return true;
39155
39341
  } catch {
39156
39342
  return false;
@@ -39172,8 +39358,8 @@ function ensureVenv(log) {
39172
39358
  }
39173
39359
  try {
39174
39360
  mkdirSync14(join52(homedir12(), ".open-agents"), { recursive: true });
39175
- execSync24(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
39176
- execSync24(`"${join52(venvDir, "bin", "pip")}" install --upgrade pip`, {
39361
+ execSync25(`python3 -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
39362
+ execSync25(`"${join52(venvDir, "bin", "pip")}" install --upgrade pip`, {
39177
39363
  stdio: "pipe",
39178
39364
  timeout: 6e4
39179
39365
  });
@@ -39186,7 +39372,7 @@ function ensureVenv(log) {
39186
39372
  }
39187
39373
  function trySudoPasswordless(cmd, timeoutMs = 12e4) {
39188
39374
  try {
39189
- execSync24(`sudo -n ${cmd}`, {
39375
+ execSync25(`sudo -n ${cmd}`, {
39190
39376
  stdio: "pipe",
39191
39377
  timeout: timeoutMs,
39192
39378
  env: { ...process.env, DEBIAN_FRONTEND: "noninteractive" }
@@ -39199,7 +39385,7 @@ function trySudoPasswordless(cmd, timeoutMs = 12e4) {
39199
39385
  function runWithSudo(cmd, password, timeoutMs = 12e4) {
39200
39386
  try {
39201
39387
  const escaped = cmd.replace(/'/g, "'\\''");
39202
- execSync24(`sudo -S bash -c '${escaped}'`, {
39388
+ execSync25(`sudo -S bash -c '${escaped}'`, {
39203
39389
  input: password + "\n",
39204
39390
  stdio: ["pipe", "pipe", "pipe"],
39205
39391
  timeout: timeoutMs,
@@ -39306,7 +39492,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
39306
39492
  ok = await sudoInstall(batchCmd, getPassword, log, cachedPasswordRef, 18e4);
39307
39493
  } else {
39308
39494
  try {
39309
- execSync24(batchCmd, { stdio: "pipe", timeout: 18e4 });
39495
+ execSync25(batchCmd, { stdio: "pipe", timeout: 18e4 });
39310
39496
  ok = true;
39311
39497
  } catch {
39312
39498
  ok = false;
@@ -39343,7 +39529,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
39343
39529
  const venvCmds = {
39344
39530
  apt: () => {
39345
39531
  try {
39346
- const pyVer = execSync24(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
39532
+ const pyVer = execSync25(`python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).trim();
39347
39533
  return `apt-get install -y python3-venv python${pyVer}-venv`;
39348
39534
  } catch {
39349
39535
  return "apt-get install -y python3-venv";
@@ -39371,12 +39557,12 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
39371
39557
  const venvPip = join52(venvBin, "pip");
39372
39558
  log("Installing moondream-station in ~/.open-agents/venv...");
39373
39559
  try {
39374
- execSync24(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
39560
+ execSync25(`"${venvPip}" install moondream-station`, { stdio: "pipe", timeout: 3e5 });
39375
39561
  if (existsSync36(venvMoondream)) {
39376
39562
  log("moondream-station installed successfully.");
39377
39563
  } else {
39378
39564
  try {
39379
- const check = execSync24(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
39565
+ const check = execSync25(`"${venvPip}" show moondream-station`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 });
39380
39566
  if (check.includes("moondream")) {
39381
39567
  log("moondream-station package installed.");
39382
39568
  }
@@ -39393,7 +39579,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
39393
39579
  const venvPip2 = join52(venvBin, "pip");
39394
39580
  let ocrStackInstalled = false;
39395
39581
  try {
39396
- execSync24(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
39582
+ execSync25(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
39397
39583
  ocrStackInstalled = true;
39398
39584
  } catch {
39399
39585
  }
@@ -39401,9 +39587,9 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
39401
39587
  const ocrPackages = "pytesseract Pillow opencv-python-headless numpy";
39402
39588
  log("Installing OCR Python stack (pytesseract, OpenCV, Pillow, numpy)...");
39403
39589
  try {
39404
- execSync24(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
39590
+ execSync25(`"${venvPip2}" install ${ocrPackages}`, { stdio: "pipe", timeout: 3e5 });
39405
39591
  try {
39406
- execSync24(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
39592
+ execSync25(`"${venvPython}" -c "import cv2, pytesseract, numpy, PIL"`, { stdio: "pipe", timeout: 1e4 });
39407
39593
  log("OCR Python stack installed successfully.");
39408
39594
  } catch {
39409
39595
  log("OCR Python stack install completed but import verification failed.");
@@ -39437,7 +39623,7 @@ function ensureCloudflaredBackground(onInfo) {
39437
39623
  const archMap = { x64: "amd64", arm64: "arm64", arm: "arm" };
39438
39624
  const cfArch = archMap[arch] ?? "amd64";
39439
39625
  try {
39440
- execSync24(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir12()}/.local/bin" && mv /tmp/cloudflared "${homedir12()}/.local/bin/cloudflared"`, { stdio: "pipe", timeout: 6e4 });
39626
+ execSync25(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir12()}/.local/bin" && mv /tmp/cloudflared "${homedir12()}/.local/bin/cloudflared"`, { stdio: "pipe", timeout: 6e4 });
39441
39627
  if (!process.env.PATH?.includes(`${homedir12()}/.local/bin`)) {
39442
39628
  process.env.PATH = `${homedir12()}/.local/bin:${process.env.PATH}`;
39443
39629
  }
@@ -39448,7 +39634,7 @@ function ensureCloudflaredBackground(onInfo) {
39448
39634
  } catch {
39449
39635
  }
39450
39636
  try {
39451
- execSync24(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared 2>/dev/null`, { stdio: "pipe", timeout: 6e4 });
39637
+ execSync25(`curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && sudo mv /tmp/cloudflared /usr/local/bin/cloudflared 2>/dev/null`, { stdio: "pipe", timeout: 6e4 });
39452
39638
  if (hasCmd("cloudflared")) {
39453
39639
  log("cloudflared installed.");
39454
39640
  return true;
@@ -39457,7 +39643,7 @@ function ensureCloudflaredBackground(onInfo) {
39457
39643
  }
39458
39644
  } else if (os === "darwin") {
39459
39645
  try {
39460
- execSync24("brew install cloudflared", { stdio: "pipe", timeout: 12e4 });
39646
+ execSync25("brew install cloudflared", { stdio: "pipe", timeout: 12e4 });
39461
39647
  if (hasCmd("cloudflared")) {
39462
39648
  log("cloudflared installed via Homebrew.");
39463
39649
  return true;
@@ -39599,7 +39785,7 @@ async function ensureExpandedContext(modelName, backendUrl) {
39599
39785
  }
39600
39786
  async function ensureNeovim() {
39601
39787
  try {
39602
- const nvimPath = execSync24("which nvim 2>/dev/null || where nvim 2>nul", {
39788
+ const nvimPath = execSync25("which nvim 2>/dev/null || where nvim 2>nul", {
39603
39789
  encoding: "utf8",
39604
39790
  stdio: "pipe",
39605
39791
  timeout: 5e3
@@ -39621,14 +39807,14 @@ async function ensureNeovim() {
39621
39807
  const url = `https://github.com/neovim/neovim/releases/latest/download/${appImageName}`;
39622
39808
  console.log(` Downloading Neovim (${appImageName})...`);
39623
39809
  try {
39624
- execSync24(`curl -fsSL "${url}" -o "${nvimDest}"`, { stdio: "pipe", timeout: 6e4 });
39625
- execSync24(`chmod +x "${nvimDest}"`, { stdio: "pipe", timeout: 3e3 });
39810
+ execSync25(`curl -fsSL "${url}" -o "${nvimDest}"`, { stdio: "pipe", timeout: 6e4 });
39811
+ execSync25(`chmod +x "${nvimDest}"`, { stdio: "pipe", timeout: 3e3 });
39626
39812
  } catch (err) {
39627
39813
  console.log(` Failed to download Neovim: ${err instanceof Error ? err.message : String(err)}`);
39628
39814
  return null;
39629
39815
  }
39630
39816
  try {
39631
- const ver = execSync24(`"${nvimDest}" --version`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).split("\n")[0];
39817
+ const ver = execSync25(`"${nvimDest}" --version`, { encoding: "utf8", stdio: "pipe", timeout: 5e3 }).split("\n")[0];
39632
39818
  console.log(` Installed: ${ver}`);
39633
39819
  } catch {
39634
39820
  console.log(" Warning: nvim binary downloaded but may not work (missing FUSE? Try: nvim --appimage-extract)");
@@ -39643,8 +39829,8 @@ async function ensureNeovim() {
39643
39829
  if (hasCmd("brew")) {
39644
39830
  console.log(" Installing Neovim via Homebrew...");
39645
39831
  try {
39646
- execSync24("brew install neovim", { stdio: "inherit", timeout: 12e4 });
39647
- const nvimPath = execSync24("which nvim", { encoding: "utf8", stdio: "pipe", timeout: 3e3 }).trim();
39832
+ execSync25("brew install neovim", { stdio: "inherit", timeout: 12e4 });
39833
+ const nvimPath = execSync25("which nvim", { encoding: "utf8", stdio: "pipe", timeout: 3e3 }).trim();
39648
39834
  return nvimPath || null;
39649
39835
  } catch {
39650
39836
  console.log(" brew install neovim failed.");
@@ -39658,7 +39844,7 @@ async function ensureNeovim() {
39658
39844
  if (hasCmd("choco")) {
39659
39845
  console.log(" Installing Neovim via Chocolatey...");
39660
39846
  try {
39661
- execSync24("choco install neovim -y", { stdio: "inherit", timeout: 12e4 });
39847
+ execSync25("choco install neovim -y", { stdio: "inherit", timeout: 12e4 });
39662
39848
  return "nvim";
39663
39849
  } catch {
39664
39850
  console.log(" choco install neovim failed.");
@@ -39667,7 +39853,7 @@ async function ensureNeovim() {
39667
39853
  if (hasCmd("winget")) {
39668
39854
  console.log(" Installing Neovim via winget...");
39669
39855
  try {
39670
- execSync24("winget install Neovim.Neovim --accept-source-agreements --accept-package-agreements", {
39856
+ execSync25("winget install Neovim.Neovim --accept-source-agreements --accept-package-agreements", {
39671
39857
  stdio: "inherit",
39672
39858
  timeout: 12e4
39673
39859
  });
@@ -40589,7 +40775,7 @@ var init_drop_panel = __esm({
40589
40775
  import { existsSync as existsSync38, unlinkSync as unlinkSync7 } from "node:fs";
40590
40776
  import { tmpdir as tmpdir8 } from "node:os";
40591
40777
  import { join as join53 } from "node:path";
40592
- import { execSync as execSync25 } from "node:child_process";
40778
+ import { execSync as execSync26 } from "node:child_process";
40593
40779
  function isNeovimActive() {
40594
40780
  return _state !== null && !_state.cleanedUp;
40595
40781
  }
@@ -40607,7 +40793,7 @@ async function startNeovimMode(opts) {
40607
40793
  }
40608
40794
  let nvimPath;
40609
40795
  try {
40610
- nvimPath = execSync25("which nvim 2>/dev/null", { encoding: "utf8" }).trim();
40796
+ nvimPath = execSync26("which nvim 2>/dev/null", { encoding: "utf8" }).trim();
40611
40797
  if (!nvimPath)
40612
40798
  throw new Error();
40613
40799
  } catch {
@@ -41068,7 +41254,7 @@ __export(voice_exports, {
41068
41254
  import { existsSync as existsSync39, mkdirSync as mkdirSync15, writeFileSync as writeFileSync16, readFileSync as readFileSync28, unlinkSync as unlinkSync8, readdirSync as readdirSync10, renameSync, statSync as statSync13 } from "node:fs";
41069
41255
  import { join as join54, dirname as dirname18 } from "node:path";
41070
41256
  import { homedir as homedir13, tmpdir as tmpdir9, platform as platform2 } from "node:os";
41071
- import { execSync as execSync26, spawn as nodeSpawn } from "node:child_process";
41257
+ import { execSync as execSync27, spawn as nodeSpawn } from "node:child_process";
41072
41258
  import { createRequire } from "node:module";
41073
41259
  function sanitizeForTTS(text) {
41074
41260
  return text.replace(/^#{1,6}\s+/gm, "").replace(/\*{1,3}([^*]+)\*{1,3}/g, "$1").replace(/_{1,3}([^_]+)_{1,3}/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/`([^`]+)`/g, "$1").replace(/```[\s\S]*?```/g, "").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/^[\s]*[-*+]\s+/gm, "").replace(/^[\s]*\d+\.\s+/gm, "").replace(/^>\s+/gm, "").replace(/^[-*_]{3,}$/gm, "").replace(/\[[ xX]\]\s*/g, "").replace(/[\u{1F600}-\u{1F64F}]/gu, "").replace(/[\u{1F300}-\u{1F5FF}]/gu, "").replace(/[\u{1F680}-\u{1F6FF}]/gu, "").replace(/[\u{1F1E0}-\u{1F1FF}]/gu, "").replace(/[\u{2600}-\u{26FF}]/gu, "").replace(/[\u{2700}-\u{27BF}]/gu, "").replace(/[\u{FE00}-\u{FE0F}]/gu, "").replace(/[\u{1F900}-\u{1F9FF}]/gu, "").replace(/[\u{1FA00}-\u{1FA6F}]/gu, "").replace(/[\u{1FA70}-\u{1FAFF}]/gu, "").replace(/[\u{200D}]/gu, "").replace(/[\u{20E3}]/gu, "").replace(/[✓✔✗✘✕✖⚠️⏸⏹⏵●○◆◇■□▪▫►▼▲◀⬆⬇⬅➡↑↓←→⇐⇒⇑⇓]/g, "").replace(/[─━│┃┌┐└┘├┤┬┴┼╔╗╚╝╠╣╦╩╬⎿⎾▕▏⏐░▒▓█⠀-⣿]/g, "").replace(/\s{2,}/g, " ").trim();
@@ -42809,7 +42995,7 @@ var init_voice = __esm({
42809
42995
  }
42810
42996
  for (const player of ["paplay", "pw-play", "aplay"]) {
42811
42997
  try {
42812
- execSync26(`which ${player}`, { stdio: "pipe" });
42998
+ execSync27(`which ${player}`, { stdio: "pipe" });
42813
42999
  return [player, path];
42814
43000
  } catch {
42815
43001
  }
@@ -42838,7 +43024,7 @@ var init_voice = __esm({
42838
43024
  return this.python3Path;
42839
43025
  for (const bin of ["python3", "python"]) {
42840
43026
  try {
42841
- const path = execSync26(`which ${bin}`, { stdio: "pipe", timeout: 5e3 }).toString().trim();
43027
+ const path = execSync27(`which ${bin}`, { stdio: "pipe", timeout: 5e3 }).toString().trim();
42842
43028
  if (path) {
42843
43029
  this.python3Path = path;
42844
43030
  return path;
@@ -42904,7 +43090,7 @@ var init_voice = __esm({
42904
43090
  return false;
42905
43091
  }
42906
43092
  try {
42907
- execSync26(`${py} -c "import mlx_audio"`, { stdio: "pipe", timeout: 1e4 });
43093
+ execSync27(`${py} -c "import mlx_audio"`, { stdio: "pipe", timeout: 1e4 });
42908
43094
  this.mlxInstalled = true;
42909
43095
  return true;
42910
43096
  } catch {
@@ -42965,11 +43151,11 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
42965
43151
  `tts_gen.main(["--model", ${JSON.stringify(mlxModelId)}, "--text", text, "--voice", ${JSON.stringify(mlxVoice)}, "--lang_code", ${JSON.stringify(mlxLangCode)}, "--audio_path", ${JSON.stringify(wavPath)}])`
42966
43152
  ].join("; ");
42967
43153
  try {
42968
- execSync26(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
43154
+ execSync27(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
42969
43155
  } catch (err) {
42970
43156
  try {
42971
43157
  const safeText = cleaned.replace(/'/g, "'\\''");
42972
- execSync26(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
43158
+ execSync27(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
42973
43159
  } catch (err2) {
42974
43160
  return;
42975
43161
  }
@@ -43033,11 +43219,11 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`);
43033
43219
  `tts_gen.main(["--model", ${JSON.stringify(mlxModelId)}, "--text", text, "--voice", ${JSON.stringify(mlxVoice)}, "--lang_code", ${JSON.stringify(mlxLangCode)}, "--audio_path", ${JSON.stringify(wavPath)}])`
43034
43220
  ].join("; ");
43035
43221
  try {
43036
- execSync26(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
43222
+ execSync27(`${py} -c ${JSON.stringify(pyScript)} ${JSON.stringify(JSON.stringify(cleaned))}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
43037
43223
  } catch {
43038
43224
  try {
43039
43225
  const safeText = cleaned.replace(/'/g, "'\\''");
43040
- execSync26(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
43226
+ execSync27(`${py} -m mlx_audio.tts.generate --model ${mlxModelId} --text '${safeText}' --voice ${mlxVoice} --lang_code ${mlxLangCode} --audio_path ${JSON.stringify(wavPath)}`, { stdio: "pipe", timeout: 6e4, cwd: tmpdir9() });
43041
43227
  } catch {
43042
43228
  return null;
43043
43229
  }
@@ -43775,6 +43961,109 @@ function safeLog(text) {
43775
43961
  process.stdout.write(text + "\n");
43776
43962
  }
43777
43963
  }
43964
+ async function destroyOrphanProcesses(ctx, global) {
43965
+ const myPid = process.pid;
43966
+ const myPpid = process.ppid;
43967
+ const cwd4 = ctx.repoRoot || process.cwd();
43968
+ const patterns = [
43969
+ "open-agents.*--non-interactive",
43970
+ // Stale eval/cron OA instances
43971
+ "nexus-daemon\\.mjs",
43972
+ // Detached nexus daemons
43973
+ "vitest",
43974
+ // Orphaned test runners
43975
+ "esbuild.*--service.*--ping",
43976
+ // Leaked esbuild services
43977
+ "python3 -u -i -q",
43978
+ // Orphaned REPL processes (ReplTool)
43979
+ "chromium.*--headless",
43980
+ // Headless Chrome from browser_action/web_crawl
43981
+ "chrome.*--headless",
43982
+ // Chrome from Puppeteer/Playwright scrapers
43983
+ "crawlee-scraper\\.py",
43984
+ // Python crawlee scraper
43985
+ "web_scrape\\.py",
43986
+ // Python web scraper
43987
+ "start-moondream\\.py",
43988
+ // Moondream vision server
43989
+ "live-whisper\\.py",
43990
+ // Whisper ASR server
43991
+ "jest.*--forceExit"
43992
+ // Orphaned Jest runners
43993
+ ];
43994
+ const patternArg = patterns.join("|");
43995
+ let killed = 0;
43996
+ try {
43997
+ const psOutput = nodeExecSync(`ps -eo pid,ppid,lstart,args --no-headers 2>/dev/null | grep -E "${patternArg}" | grep -v grep`, { encoding: "utf-8", timeout: 5e3, stdio: ["pipe", "pipe", "pipe"] }).trim();
43998
+ if (!psOutput)
43999
+ return 0;
44000
+ const lines = psOutput.split("\n").filter((l) => l.trim());
44001
+ const candidates = [];
44002
+ for (const line of lines) {
44003
+ const parts = line.trim().split(/\s+/);
44004
+ const pid = parseInt(parts[0], 10);
44005
+ const ppid = parseInt(parts[1], 10);
44006
+ if (pid === myPid || pid === myPpid)
44007
+ continue;
44008
+ if (pid <= 10)
44009
+ continue;
44010
+ const cmd = parts.slice(6).join(" ");
44011
+ candidates.push({ pid, ppid, cmd });
44012
+ }
44013
+ if (!global) {
44014
+ const localCandidates = [];
44015
+ for (const c3 of candidates) {
44016
+ try {
44017
+ const procCwd = nodeExecSync(`readlink /proc/${c3.pid}/cwd 2>/dev/null`, { encoding: "utf-8", timeout: 2e3 }).trim();
44018
+ if (procCwd.startsWith(cwd4)) {
44019
+ localCandidates.push(c3);
44020
+ }
44021
+ } catch {
44022
+ if (/open-agents|nexus-daemon/.test(c3.cmd)) {
44023
+ localCandidates.push(c3);
44024
+ }
44025
+ }
44026
+ }
44027
+ candidates.length = 0;
44028
+ candidates.push(...localCandidates);
44029
+ }
44030
+ if (candidates.length === 0)
44031
+ return 0;
44032
+ renderInfo(`Found ${candidates.length} orphaned OA process(es)${global ? " (system-wide)" : ""}:`);
44033
+ for (const c3 of candidates) {
44034
+ const shortCmd = c3.cmd.length > 80 ? c3.cmd.slice(0, 77) + "..." : c3.cmd;
44035
+ process.stdout.write(` PID ${c3.pid}: ${shortCmd}
44036
+ `);
44037
+ }
44038
+ for (const c3 of candidates) {
44039
+ try {
44040
+ try {
44041
+ process.kill(-c3.pid, "SIGTERM");
44042
+ } catch {
44043
+ }
44044
+ process.kill(c3.pid, "SIGTERM");
44045
+ killed++;
44046
+ } catch {
44047
+ try {
44048
+ process.kill(c3.pid, "SIGKILL");
44049
+ killed++;
44050
+ } catch {
44051
+ }
44052
+ }
44053
+ }
44054
+ if (killed > 0) {
44055
+ await new Promise((r) => setTimeout(r, 2e3));
44056
+ for (const c3 of candidates) {
44057
+ try {
44058
+ process.kill(c3.pid, "SIGKILL");
44059
+ } catch {
44060
+ }
44061
+ }
44062
+ }
44063
+ } catch {
44064
+ }
44065
+ return killed;
44066
+ }
43778
44067
  async function handleSlashCommand(input, ctx) {
43779
44068
  const trimmed = input.trim();
43780
44069
  if (!trimmed.startsWith("/"))
@@ -45494,11 +45783,26 @@ async function handleSlashCommand(input, ctx) {
45494
45783
  return "handled";
45495
45784
  }
45496
45785
  case "destroy": {
45497
- if (ctx.hasActiveTask?.()) {
45498
- ctx.abortTask?.();
45786
+ const subCmd = (arg || "").toLowerCase().trim();
45787
+ if (subCmd.startsWith("processes") || subCmd.startsWith("procs")) {
45788
+ const isGlobal = subCmd.includes("--global") || subCmd.includes("-g");
45789
+ const killed = await destroyOrphanProcesses(ctx, isGlobal);
45790
+ if (killed === 0) {
45791
+ renderInfo("No orphaned OA processes found.");
45792
+ } else {
45793
+ renderInfo(`Killed ${killed} orphaned OA process(es).`);
45794
+ }
45795
+ return "handled";
45499
45796
  }
45500
- ctx.destroyProject?.();
45501
- return "exit";
45797
+ if (subCmd === "project" || subCmd === "") {
45798
+ if (ctx.hasActiveTask?.()) {
45799
+ ctx.abortTask?.();
45800
+ }
45801
+ ctx.destroyProject?.();
45802
+ return "exit";
45803
+ }
45804
+ renderWarning(`Unknown /destroy target: "${subCmd}". Use: /destroy processes [--global] or /destroy project`);
45805
+ return "handled";
45502
45806
  }
45503
45807
  case "context": {
45504
45808
  const subCmd = arg?.toLowerCase().split(/\s+/)[0] || "";
@@ -47007,7 +47311,7 @@ async function handlePeerEndpoint(peerId, authKey, ctx, local) {
47007
47311
  }
47008
47312
  }
47009
47313
  async function handleParallel(arg, ctx) {
47010
- const { execSync: execSync31 } = await import("node:child_process");
47314
+ const { execSync: execSync32 } = await import("node:child_process");
47011
47315
  const baseUrl = ctx.config.backendUrl || "http://localhost:11434";
47012
47316
  const isRemote = ctx.config.backendType === "nexus";
47013
47317
  if (isRemote) {
@@ -47031,7 +47335,7 @@ async function handleParallel(arg, ctx) {
47031
47335
  }
47032
47336
  let systemdVal = "";
47033
47337
  try {
47034
- const out = execSync31("systemctl show ollama.service -p Environment 2>/dev/null || true", { encoding: "utf8" });
47338
+ const out = execSync32("systemctl show ollama.service -p Environment 2>/dev/null || true", { encoding: "utf8" });
47035
47339
  const match = out.match(/OLLAMA_NUM_PARALLEL=(\d+)/);
47036
47340
  if (match)
47037
47341
  systemdVal = match[1];
@@ -47060,7 +47364,7 @@ async function handleParallel(arg, ctx) {
47060
47364
  }
47061
47365
  const isSystemd = (() => {
47062
47366
  try {
47063
- const out = execSync31("systemctl is-active ollama.service 2>/dev/null", { encoding: "utf8" }).trim();
47367
+ const out = execSync32("systemctl is-active ollama.service 2>/dev/null", { encoding: "utf8" }).trim();
47064
47368
  return out === "active" || out === "inactive";
47065
47369
  } catch {
47066
47370
  return false;
@@ -47074,10 +47378,10 @@ async function handleParallel(arg, ctx) {
47074
47378
  const overrideContent = `[Service]
47075
47379
  Environment="OLLAMA_NUM_PARALLEL=${n}"
47076
47380
  `;
47077
- execSync31(`sudo mkdir -p ${overrideDir}`, { stdio: "pipe" });
47078
- execSync31(`echo '${overrideContent}' | sudo tee ${overrideFile} > /dev/null`, { stdio: "pipe" });
47079
- execSync31("sudo systemctl daemon-reload", { stdio: "pipe" });
47080
- execSync31("sudo systemctl restart ollama.service", { stdio: "pipe" });
47381
+ execSync32(`sudo mkdir -p ${overrideDir}`, { stdio: "pipe" });
47382
+ execSync32(`echo '${overrideContent}' | sudo tee ${overrideFile} > /dev/null`, { stdio: "pipe" });
47383
+ execSync32("sudo systemctl daemon-reload", { stdio: "pipe" });
47384
+ execSync32("sudo systemctl restart ollama.service", { stdio: "pipe" });
47081
47385
  let ready = false;
47082
47386
  for (let i = 0; i < 30 && !ready; i++) {
47083
47387
  await new Promise((r) => setTimeout(r, 500));
@@ -47104,7 +47408,7 @@ Environment="OLLAMA_NUM_PARALLEL=${n}"
47104
47408
  renderInfo(`Setting OLLAMA_NUM_PARALLEL=${n}...`);
47105
47409
  try {
47106
47410
  try {
47107
- execSync31("pkill -f 'ollama serve' 2>/dev/null || true", { stdio: "pipe" });
47411
+ execSync32("pkill -f 'ollama serve' 2>/dev/null || true", { stdio: "pipe" });
47108
47412
  } catch {
47109
47413
  }
47110
47414
  await new Promise((r) => setTimeout(r, 1e3));
@@ -47906,18 +48210,18 @@ async function showExposeDashboard(gateway, rl, ctx) {
47906
48210
  const cmd = `/endpoint ${id} --auth ${gateway.authKey ?? ""}`;
47907
48211
  let copied = false;
47908
48212
  try {
47909
- const { execSync: execSync31 } = __require("node:child_process");
48213
+ const { execSync: execSync32 } = __require("node:child_process");
47910
48214
  const platform5 = process.platform;
47911
48215
  if (platform5 === "darwin") {
47912
- execSync31("pbcopy", { input: cmd, timeout: 3e3 });
48216
+ execSync32("pbcopy", { input: cmd, timeout: 3e3 });
47913
48217
  copied = true;
47914
48218
  } else if (platform5 === "win32") {
47915
- execSync31("clip", { input: cmd, timeout: 3e3 });
48219
+ execSync32("clip", { input: cmd, timeout: 3e3 });
47916
48220
  copied = true;
47917
48221
  } else {
47918
48222
  for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
47919
48223
  try {
47920
- execSync31(tool, { input: cmd, timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] });
48224
+ execSync32(tool, { input: cmd, timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] });
47921
48225
  copied = true;
47922
48226
  break;
47923
48227
  } catch {
@@ -48006,7 +48310,7 @@ var init_commands = __esm({
48006
48310
  // packages/cli/dist/tui/project-context.js
48007
48311
  import { existsSync as existsSync41, readFileSync as readFileSync30, readdirSync as readdirSync12 } from "node:fs";
48008
48312
  import { join as join56, basename as basename11 } from "node:path";
48009
- import { execSync as execSync27 } from "node:child_process";
48313
+ import { execSync as execSync28 } from "node:child_process";
48010
48314
  import { homedir as homedir15, platform as platform3, release } from "node:os";
48011
48315
  function getModelTier(modelName) {
48012
48316
  const m = modelName.toLowerCase();
@@ -48052,19 +48356,19 @@ function loadProjectMap(repoRoot) {
48052
48356
  }
48053
48357
  function getGitInfo(repoRoot) {
48054
48358
  try {
48055
- execSync27("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
48359
+ execSync28("git rev-parse --is-inside-work-tree", { cwd: repoRoot, stdio: "pipe" });
48056
48360
  } catch {
48057
48361
  return "";
48058
48362
  }
48059
48363
  const lines = [];
48060
48364
  try {
48061
- const branch = execSync27("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
48365
+ const branch = execSync28("git branch --show-current", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
48062
48366
  if (branch)
48063
48367
  lines.push(`Branch: ${branch}`);
48064
48368
  } catch {
48065
48369
  }
48066
48370
  try {
48067
- const status = execSync27("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
48371
+ const status = execSync28("git status --porcelain", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
48068
48372
  if (status) {
48069
48373
  const changed = status.split("\n").length;
48070
48374
  lines.push(`Working tree: ${changed} changed file(s)`);
@@ -48074,7 +48378,7 @@ function getGitInfo(repoRoot) {
48074
48378
  } catch {
48075
48379
  }
48076
48380
  try {
48077
- const log = execSync27("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
48381
+ const log = execSync28("git log --oneline -5 --no-decorate", { cwd: repoRoot, encoding: "utf-8", stdio: "pipe" }).trim();
48078
48382
  if (log)
48079
48383
  lines.push(`Recent commits:
48080
48384
  ${log}`);
@@ -50626,7 +50930,7 @@ var init_promptLoader3 = __esm({
50626
50930
  // packages/cli/dist/tui/dream-engine.js
50627
50931
  import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync19, readFileSync as readFileSync33, existsSync as existsSync44, cpSync, rmSync as rmSync2, readdirSync as readdirSync14 } from "node:fs";
50628
50932
  import { join as join60, basename as basename13 } from "node:path";
50629
- import { execSync as execSync28 } from "node:child_process";
50933
+ import { execSync as execSync29 } from "node:child_process";
50630
50934
  function loadAutoresearchMemory(repoRoot) {
50631
50935
  const memoryPath = join60(repoRoot, ".oa", "memory", "autoresearch.json");
50632
50936
  if (!existsSync44(memoryPath))
@@ -50990,7 +51294,7 @@ var init_dream_engine = __esm({
50990
51294
  }
50991
51295
  }
50992
51296
  try {
50993
- const output = execSync28(cmd, {
51297
+ const output = execSync29(cmd, {
50994
51298
  cwd: this.repoRoot,
50995
51299
  timeout: 3e4,
50996
51300
  encoding: "utf-8",
@@ -51767,17 +52071,17 @@ ${summaryResult}
51767
52071
  try {
51768
52072
  mkdirSync19(checkpointDir, { recursive: true });
51769
52073
  try {
51770
- const gitStatus = execSync28("git status --porcelain", {
52074
+ const gitStatus = execSync29("git status --porcelain", {
51771
52075
  cwd: this.repoRoot,
51772
52076
  encoding: "utf-8",
51773
52077
  timeout: 1e4
51774
52078
  });
51775
- const gitDiff = execSync28("git diff", {
52079
+ const gitDiff = execSync29("git diff", {
51776
52080
  cwd: this.repoRoot,
51777
52081
  encoding: "utf-8",
51778
52082
  timeout: 1e4
51779
52083
  });
51780
- const gitHash = execSync28("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
52084
+ const gitHash = execSync29("git rev-parse HEAD 2>/dev/null || echo 'no-git'", {
51781
52085
  cwd: this.repoRoot,
51782
52086
  encoding: "utf-8",
51783
52087
  timeout: 5e3
@@ -55587,7 +55891,7 @@ __export(text_selection_exports, {
55587
55891
  stripAnsi: () => stripAnsi3,
55588
55892
  visibleLength: () => visibleLength
55589
55893
  });
55590
- import { execSync as execSync29 } from "node:child_process";
55894
+ import { execSync as execSync30 } from "node:child_process";
55591
55895
  function stripAnsi3(s) {
55592
55896
  return s.replace(/\x1B\[[0-9;]*[A-Za-z]|\x1B\].*?(?:\x07|\x1B\\)/g, "");
55593
55897
  }
@@ -55598,16 +55902,16 @@ function copyText(text) {
55598
55902
  try {
55599
55903
  const platform5 = process.platform;
55600
55904
  if (platform5 === "darwin") {
55601
- execSync29("pbcopy", { input: text, timeout: 3e3 });
55905
+ execSync30("pbcopy", { input: text, timeout: 3e3 });
55602
55906
  return true;
55603
55907
  }
55604
55908
  if (platform5 === "win32") {
55605
- execSync29("clip", { input: text, timeout: 3e3 });
55909
+ execSync30("clip", { input: text, timeout: 3e3 });
55606
55910
  return true;
55607
55911
  }
55608
55912
  for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
55609
55913
  try {
55610
- execSync29(tool, { input: text, timeout: 3e3 });
55914
+ execSync30(tool, { input: text, timeout: 3e3 });
55611
55915
  return true;
55612
55916
  } catch {
55613
55917
  continue;
@@ -55616,10 +55920,10 @@ function copyText(text) {
55616
55920
  if (!_clipboardAutoInstallAttempted) {
55617
55921
  _clipboardAutoInstallAttempted = true;
55618
55922
  try {
55619
- execSync29("which apt-get", { timeout: 2e3, stdio: "pipe" });
55923
+ execSync30("which apt-get", { timeout: 2e3, stdio: "pipe" });
55620
55924
  try {
55621
- execSync29("sudo -n apt-get install -y xclip 2>/dev/null", { timeout: 15e3, stdio: "pipe" });
55622
- execSync29("xclip -selection clipboard", { input: text, timeout: 3e3 });
55925
+ execSync30("sudo -n apt-get install -y xclip 2>/dev/null", { timeout: 15e3, stdio: "pipe" });
55926
+ execSync30("xclip -selection clipboard", { input: text, timeout: 3e3 });
55623
55927
  return true;
55624
55928
  } catch {
55625
55929
  }
@@ -58060,7 +58364,7 @@ import { createRequire as createRequire2 } from "node:module";
58060
58364
  import { fileURLToPath as fileURLToPath12 } from "node:url";
58061
58365
  import { readFileSync as readFileSync37, writeFileSync as writeFileSync21, appendFileSync as appendFileSync4, rmSync as rmSync3, readdirSync as readdirSync18, mkdirSync as mkdirSync22 } from "node:fs";
58062
58366
  import { existsSync as existsSync48 } from "node:fs";
58063
- import { execSync as execSync30 } from "node:child_process";
58367
+ import { execSync as execSync31 } from "node:child_process";
58064
58368
  import { homedir as homedir16 } from "node:os";
58065
58369
  function formatTimeAgo(date) {
58066
58370
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
@@ -58124,11 +58428,13 @@ function createTaskCompleteTool() {
58124
58428
  };
58125
58429
  }
58126
58430
  function buildTools(repoRoot, config, contextWindowSize) {
58431
+ const shellTool = new ShellTool(repoRoot);
58432
+ _shellToolRef = shellTool;
58127
58433
  const executionTools = [
58128
58434
  new FileReadTool(repoRoot),
58129
58435
  new FileWriteTool(repoRoot),
58130
58436
  new FileEditTool(repoRoot),
58131
- new ShellTool(repoRoot),
58437
+ shellTool,
58132
58438
  new GrepSearchTool(repoRoot),
58133
58439
  new GlobFindTool(repoRoot),
58134
58440
  new ListDirectoryTool(repoRoot),
@@ -58215,6 +58521,7 @@ function buildTools(repoRoot, config, contextWindowSize) {
58215
58521
  new WorkingNotesTool(),
58216
58522
  new SemanticMapTool(repoRoot),
58217
58523
  new RepoMapTool(repoRoot),
58524
+ new ProcessHealthTool(),
58218
58525
  // Nexus P2P networking + x402 micropayments
58219
58526
  new NexusTool(repoRoot)
58220
58527
  ];
@@ -59376,15 +59683,15 @@ async function startInteractive(config, repoPath) {
59376
59683
  const restoreScreen = () => {
59377
59684
  process.stdout.write("\x1B[?1002l\x1B[?1003l\x1B[?1006l\x1B[?1015l\x1B[?25h\x1B[?1049l");
59378
59685
  };
59379
- process.on("exit", restoreScreen);
59380
- process.on("SIGINT", () => {
59381
- restoreScreen();
59382
- process.exit(130);
59383
- });
59384
- process.on("SIGTERM", () => {
59686
+ const cleanupAndExit = (code) => {
59687
+ if (_shellToolRef)
59688
+ _shellToolRef.killAll();
59385
59689
  restoreScreen();
59386
- process.exit(143);
59387
- });
59690
+ process.exit(code);
59691
+ };
59692
+ process.on("exit", restoreScreen);
59693
+ process.on("SIGINT", () => cleanupAndExit(130));
59694
+ process.on("SIGTERM", () => cleanupAndExit(143));
59388
59695
  }
59389
59696
  let memoryDb = null;
59390
59697
  let taskMemoryStore = null;
@@ -61330,7 +61637,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
61330
61637
  try {
61331
61638
  if (process.platform === "win32") {
61332
61639
  try {
61333
- execSync30(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
61640
+ execSync31(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
61334
61641
  } catch {
61335
61642
  }
61336
61643
  } else {
@@ -61357,7 +61664,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
61357
61664
  if (pid > 0) {
61358
61665
  if (process.platform === "win32") {
61359
61666
  try {
61360
- execSync30(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
61667
+ execSync31(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
61361
61668
  } catch {
61362
61669
  }
61363
61670
  } else {
@@ -61374,7 +61681,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
61374
61681
  } catch {
61375
61682
  }
61376
61683
  try {
61377
- execSync30(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
61684
+ execSync31(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
61378
61685
  } catch {
61379
61686
  }
61380
61687
  const oaPath = join64(repoRoot, OA_DIR);
@@ -61388,14 +61695,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
61388
61695
  } catch (err) {
61389
61696
  if (attempt < 2) {
61390
61697
  try {
61391
- execSync30(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.3", { timeout: 3e3, stdio: "ignore" });
61698
+ execSync31(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.3", { timeout: 3e3, stdio: "ignore" });
61392
61699
  } catch {
61393
61700
  }
61394
61701
  } else {
61395
61702
  writeContent(() => renderWarning(`Could not fully remove ${OA_DIR}/: ${err instanceof Error ? err.message : String(err)}`));
61396
61703
  if (process.platform === "win32") {
61397
61704
  try {
61398
- execSync30(`rd /s /q "${oaPath}"`, { timeout: 1e4, stdio: "ignore" });
61705
+ execSync31(`rd /s /q "${oaPath}"`, { timeout: 1e4, stdio: "ignore" });
61399
61706
  deleted = true;
61400
61707
  } catch {
61401
61708
  }
@@ -62521,7 +62828,7 @@ Rules:
62521
62828
  process.exit(1);
62522
62829
  }
62523
62830
  }
62524
- var taskManager, SELF_IMPROVE_INTERVAL, _tasksSinceImprove;
62831
+ var taskManager, _shellToolRef, SELF_IMPROVE_INTERVAL, _tasksSinceImprove;
62525
62832
  var init_interactive = __esm({
62526
62833
  "packages/cli/dist/tui/interactive.js"() {
62527
62834
  "use strict";
@@ -62561,6 +62868,7 @@ var init_interactive = __esm({
62561
62868
  init_overlay_lock();
62562
62869
  init_neovim_mode();
62563
62870
  taskManager = new BackgroundTaskManager();
62871
+ _shellToolRef = null;
62564
62872
  SELF_IMPROVE_INTERVAL = 5;
62565
62873
  _tasksSinceImprove = 0;
62566
62874
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.149.0",
3
+ "version": "0.151.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",