open-agents-ai 0.187.149 → 0.187.151

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 +378 -138
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -256448,7 +256448,7 @@ ${output}`, durationMs: performance.now() - start2 };
256448
256448
  import { execSync as execSync36, spawnSync as spawnSync2 } from "node:child_process";
256449
256449
  import { existsSync as existsSync34, readFileSync as readFileSync25, writeFileSync as writeFileSync13, mkdirSync as mkdirSync14 } from "node:fs";
256450
256450
  import { join as join48 } from "node:path";
256451
- import { tmpdir as tmpdir12 } from "node:os";
256451
+ import { tmpdir as tmpdir12, homedir as homedir13 } from "node:os";
256452
256452
  var GPS_USB_IDS, GpsLocationTool;
256453
256453
  var init_gps_location = __esm({
256454
256454
  "packages/execution/dist/tools/gps-location.js"() {
@@ -256549,13 +256549,63 @@ var init_gps_location = __esm({
256549
256549
  },
256550
256550
  required: ["action"]
256551
256551
  };
256552
+ /** Venv for pyserial + pynmea2 (same stack as proven gps_service) */
256553
+ GPS_VENV = join48(homedir13(), ".open-agents", "gps-venv");
256554
+ GPS_PYTHON = join48(this.GPS_VENV, "bin", "python3");
256555
+ GPS_PIP = join48(this.GPS_VENV, "bin", "pip");
256556
+ /** Ensure pyserial + pynmea2 venv exists */
256557
+ async ensureGpsVenv() {
256558
+ if (existsSync34(this.GPS_PYTHON)) {
256559
+ try {
256560
+ execSync36(`${this.GPS_PYTHON} -c "import serial, pynmea2"`, { timeout: 5e3, stdio: "pipe" });
256561
+ return true;
256562
+ } catch {
256563
+ }
256564
+ }
256565
+ try {
256566
+ execSync36(`python3 -m venv ${this.GPS_VENV}`, { timeout: 3e4, stdio: "pipe" });
256567
+ execSync36(`${this.GPS_PIP} install pyserial pynmea2`, { timeout: 6e4, stdio: "pipe" });
256568
+ return true;
256569
+ } catch {
256570
+ return false;
256571
+ }
256572
+ }
256573
+ /** Run a Python GPS script using pyserial+pynmea2 and return JSON result */
256574
+ async runGpsPython(script, timeoutMs = 3e4) {
256575
+ await this.ensureGpsVenv();
256576
+ const scriptFile = join48(tmpdir12(), `oa-gps-${Date.now()}.py`);
256577
+ writeFileSync13(scriptFile, script);
256578
+ try {
256579
+ const output = execSync36(`${this.GPS_PYTHON} ${scriptFile}`, {
256580
+ encoding: "utf8",
256581
+ timeout: timeoutMs,
256582
+ stdio: ["pipe", "pipe", "pipe"]
256583
+ });
256584
+ const lastLine = output.trim().split("\n").pop() || "{}";
256585
+ return JSON.parse(lastLine);
256586
+ } catch (err) {
256587
+ const stderr = err.stderr?.toString() || "";
256588
+ const stdout = err.stdout?.toString() || "";
256589
+ for (const src2 of [stdout, stderr]) {
256590
+ const lines = src2.trim().split("\n");
256591
+ for (let i2 = lines.length - 1; i2 >= 0; i2--) {
256592
+ try {
256593
+ return JSON.parse(lines[i2]);
256594
+ } catch {
256595
+ continue;
256596
+ }
256597
+ }
256598
+ }
256599
+ throw new Error(stderr.slice(0, 300) || stdout.slice(0, 300) || "GPS Python script failed");
256600
+ }
256601
+ }
256552
256602
  async execute(args) {
256553
256603
  const action = args["action"];
256554
256604
  const start2 = performance.now();
256555
256605
  try {
256556
256606
  switch (action) {
256557
256607
  case "detect":
256558
- return await this.detectGps(start2);
256608
+ return await this.detectGps(args, start2);
256559
256609
  case "fix":
256560
256610
  return await this.getFix(args, start2);
256561
256611
  case "nmea":
@@ -256576,64 +256626,128 @@ var init_gps_location = __esm({
256576
256626
  // =========================================================================
256577
256627
  // Detect GPS hardware
256578
256628
  // =========================================================================
256579
- async detectGps(start2) {
256629
+ async detectGps(args, start2) {
256630
+ try {
256631
+ const result = await this.runGpsPython(`
256632
+ import json, sys
256633
+ try:
256634
+ from serial.tools import list_ports
256635
+ import serial
256636
+
256637
+ candidates = []
256638
+ for p in list_ports.comports():
256639
+ dev = p.device or ""
256640
+ desc = (p.description or "").lower()
256641
+ hwid = (p.hwid or "").lower()
256642
+ vid = getattr(p, 'vid', None)
256643
+ pid = getattr(p, 'pid', None)
256644
+ manufacturer = getattr(p, 'manufacturer', '') or ''
256645
+ product = getattr(p, 'product', '') or ''
256646
+
256647
+ score = 0
256648
+ label = f"{dev}: {p.description or 'unknown'}"
256649
+ if vid: label += f" [VID:PID={vid:04x}:{pid:04x}]"
256650
+
256651
+ # GPS-specific keywords
256652
+ if "gps" in desc or "gnss" in desc or "gps" in manufacturer.lower():
256653
+ score += 10
256654
+ # Known GPS vendors (u-blox=0x1546, Garmin=0x091e, GlobalSat/Prolific=0x067b)
256655
+ if vid in (0x1546, 0x091e, 0x2c7c, 0x152a, 0x0df7, 0x16d0):
256656
+ score += 8
256657
+ # UART bridges commonly used for GPS (Prolific, FTDI, CP210x, CH340)
256658
+ if vid in (0x067b, 0x0403, 0x10c4, 0x1a86):
256659
+ score += 4
256660
+ # ttyUSB devices are very often GPS
256661
+ if "ttyUSB" in dev:
256662
+ score += 3
256663
+ # USB serial in general
256664
+ if "usb" in hwid:
256665
+ score += 2
256666
+ if any(k in dev for k in ("ttyUSB", "ttyACM", "cu.usb", "COM")):
256667
+ score += 1
256668
+
256669
+ if score > 0:
256670
+ candidates.append({"device": dev, "label": label, "score": score,
256671
+ "vid": f"{vid:04x}" if vid else None,
256672
+ "pid": f"{pid:04x}" if pid else None,
256673
+ "manufacturer": manufacturer, "product": product})
256674
+
256675
+ candidates.sort(key=lambda x: -x["score"])
256676
+
256677
+ # Also try to read NMEA from top candidate to confirm it's GPS
256678
+ gps_confirmed = None
256679
+ for c in candidates[:3]:
256680
+ try:
256681
+ with serial.Serial(c["device"], 4800, timeout=2) as ser:
256682
+ ser.reset_input_buffer()
256683
+ for _ in range(20):
256684
+ line = ser.readline().decode(errors="ignore").strip()
256685
+ if line.startswith("$G"):
256686
+ c["nmea_confirmed"] = True
256687
+ gps_confirmed = c["device"]
256688
+ break
256689
+ except: pass
256690
+ if not gps_confirmed:
256691
+ try:
256692
+ with serial.Serial(c["device"], 9600, timeout=2) as ser:
256693
+ ser.reset_input_buffer()
256694
+ for _ in range(20):
256695
+ line = ser.readline().decode(errors="ignore").strip()
256696
+ if line.startswith("$G"):
256697
+ c["nmea_confirmed"] = True
256698
+ gps_confirmed = c["device"]
256699
+ break
256700
+ except: pass
256701
+
256702
+ print(json.dumps({"success": True, "candidates": candidates, "gps_confirmed": gps_confirmed}))
256703
+ except Exception as e:
256704
+ print(json.dumps({"success": False, "error": str(e)}))
256705
+ `, 15e3);
256706
+ if (!result.success) {
256707
+ return { success: false, output: "", error: `GPS detect failed: ${result.error}`, durationMs: performance.now() - start2 };
256708
+ }
256709
+ const candidates = result.candidates || [];
256710
+ if (candidates.length === 0) {
256711
+ return { success: true, output: "No GPS devices detected. Connect a USB GPS receiver (BU-353N, BU-363, U-blox 7, etc.).", durationMs: performance.now() - start2 };
256712
+ }
256713
+ const lines = candidates.map((c7) => ` ${c7.device}: ${c7.label}${c7.nmea_confirmed ? " \u2713 NMEA confirmed" : ""} (score: ${c7.score})`);
256714
+ return {
256715
+ success: true,
256716
+ output: `GPS device(s) found:
256717
+ ${lines.join("\n")}` + (result.gps_confirmed ? `
256718
+
256719
+ Confirmed GPS on: ${result.gps_confirmed} (NMEA sentences detected)` : "\n\nNo NMEA confirmed yet \u2014 device may need time to initialize."),
256720
+ durationMs: performance.now() - start2
256721
+ };
256722
+ } catch (err) {
256723
+ return this.detectGpsFallback(start2);
256724
+ }
256725
+ }
256726
+ /** Fallback detection using lsusb + udevadm (no Python) */
256727
+ detectGpsFallback(start2) {
256580
256728
  const devices = [];
256581
256729
  try {
256582
256730
  const lsusb = execSync36("lsusb 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
256583
256731
  for (const known of GPS_USB_IDS) {
256584
256732
  if (lsusb.toLowerCase().includes(`${known.vid}:${known.pid}`)) {
256585
- const line = lsusb.split("\n").find((l2) => l2.toLowerCase().includes(`${known.vid}:${known.pid}`));
256586
- devices.push(` USB: ${known.name} \u2014 ${line?.trim() || `${known.vid}:${known.pid}`}`);
256587
- }
256588
- }
256589
- for (const line of lsusb.split("\n")) {
256590
- if (/gps|gnss|navsat/i.test(line) && !devices.some((d2) => d2.includes(line.trim()))) {
256591
- devices.push(` USB: ${line.trim()}`);
256733
+ devices.push(` ${known.name}`);
256592
256734
  }
256593
256735
  }
256594
256736
  } catch {
256595
256737
  }
256596
- const serialDevs = [];
256597
- for (const pattern of ["/dev/ttyUSB*", "/dev/ttyACM*"]) {
256598
- try {
256599
- const devs = execSync36(`ls ${pattern} 2>/dev/null`, { encoding: "utf8", timeout: 3e3 }).trim().split("\n").filter(Boolean);
256600
- serialDevs.push(...devs);
256601
- } catch {
256602
- }
256603
- }
256604
- for (const dev of serialDevs) {
256605
- try {
256606
- const udev = execSync36(`udevadm info --query=all --name=${dev} 2>/dev/null`, { encoding: "utf8", timeout: 3e3 });
256607
- const vendor = udev.match(/ID_VENDOR=(.+)/)?.[1] || "";
256608
- const model = udev.match(/ID_MODEL=(.+)/)?.[1] || "";
256609
- const serial = udev.match(/ID_SERIAL_SHORT=(.+)/)?.[1] || "";
256610
- const isGps = GPS_USB_IDS.some((g) => udev.toLowerCase().includes(g.vid)) || /gps|gnss|prolific|cp210x|u-blox|ublox|sirf/i.test(udev);
256611
- if (isGps) {
256612
- devices.push(` Serial: ${dev} \u2014 ${model || vendor} ${serial ? `(SN: ${serial})` : ""}`);
256738
+ try {
256739
+ const serialDevs = execSync36("ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null", { encoding: "utf8", timeout: 3e3 }).trim().split("\n").filter(Boolean);
256740
+ for (const dev of serialDevs) {
256741
+ if (!devices.some((d2) => d2.includes(dev))) {
256742
+ devices.push(` Serial: ${dev} (unidentified \u2014 may be GPS)`);
256613
256743
  }
256614
- } catch {
256615
256744
  }
256616
- }
256617
- let gpsdRunning = false;
256618
- try {
256619
- execSync36("pgrep gpsd", { timeout: 3e3, stdio: "pipe" });
256620
- gpsdRunning = true;
256621
- devices.push(" Service: gpsd is running");
256622
256745
  } catch {
256623
256746
  }
256624
- if (devices.length === 0) {
256625
- return {
256626
- success: true,
256627
- output: "No GPS devices detected. Connect a USB GPS receiver (BU-353N, U-blox 7, etc.)." + (serialDevs.length > 0 ? `
256628
-
256629
- Serial devices found but not identified as GPS: ${serialDevs.join(", ")}` : ""),
256630
- durationMs: performance.now() - start2
256631
- };
256632
- }
256633
256747
  return {
256634
256748
  success: true,
256635
- output: `GPS devices found:
256636
- ${devices.join("\n")}` + (!gpsdRunning ? "\n\nTip: Start gpsd for best results: gps_location will auto-install and start it." : ""),
256749
+ output: devices.length > 0 ? `Potential GPS devices:
256750
+ ${devices.join("\n")}` : "No GPS devices found. Connect a USB GPS receiver.",
256637
256751
  durationMs: performance.now() - start2
256638
256752
  };
256639
256753
  }
@@ -256679,42 +256793,150 @@ Raw: ${JSON.stringify(fix)}`,
256679
256793
  } catch {
256680
256794
  }
256681
256795
  }
256682
- return this.getFixFromNmea(args, start2);
256796
+ return this.getFixPyserial(args, start2);
256683
256797
  }
256684
- /** Parse GPS fix directly from NMEA on serial port */
256685
- getFixFromNmea(args, start2) {
256686
- const device = args["device"] || this.findGpsSerial();
256687
- if (!device) {
256688
- return { success: false, output: "", error: "No GPS device found. Connect a USB GPS receiver.", durationMs: performance.now() - start2 };
256689
- }
256798
+ /** Get GPS fix using pyserial+pynmea2 proven stack from gps_service/server.py */
256799
+ async getFixPyserial(args, start2) {
256800
+ const device = args["device"] || "";
256690
256801
  const timeout2 = args["timeout"] || 30;
256691
- const baud = this.detectBaud(device);
256692
256802
  try {
256693
- execSync36(`stty -F ${device} ${baud} raw -echo -echoe -echok 2>/dev/null`, { timeout: 5e3, stdio: "pipe" });
256694
- const raw = execSync36(`timeout ${timeout2} cat ${device}`, { encoding: "utf8", timeout: (timeout2 + 5) * 1e3 });
256695
- const gga = raw.split("\n").find((l2) => l2.includes("$GPGGA") || l2.includes("$GNGGA"));
256696
- const rmc = raw.split("\n").find((l2) => l2.includes("$GPRMC") || l2.includes("$GNRMC"));
256697
- if (!gga && !rmc) {
256698
- return { success: true, output: `GPS device responding on ${device} but no fix yet (${timeout2}s timeout). Try again \u2014 cold start can take 30-60s.`, durationMs: performance.now() - start2 };
256699
- }
256700
- const fix = this.parseGGA(gga) || {};
256701
- const rmcData = this.parseRMC(rmc) || {};
256803
+ const result = await this.runGpsPython(`
256804
+ import json, sys, time
256805
+ import serial
256806
+ import pynmea2
256807
+
256808
+ def guess_port():
256809
+ try:
256810
+ from serial.tools import list_ports
256811
+ for p in list_ports.comports():
256812
+ dev = p.device or ""
256813
+ desc = (p.description or "").lower()
256814
+ vid = getattr(p, 'vid', None)
256815
+ if vid in (0x1546, 0x091e, 0x067b, 0x0403, 0x10c4, 0x1a86, 0x2c7c, 0x152a, 0x0df7):
256816
+ return dev, vid
256817
+ if "gps" in desc or "gnss" in desc:
256818
+ return dev, vid
256819
+ if "ttyUSB" in dev:
256820
+ return dev, vid
256821
+ return None, None
256822
+ except:
256823
+ import os
256824
+ for p in ("/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyACM0"):
256825
+ if os.path.exists(p):
256826
+ return p, None
256827
+ return None, None
256828
+
256829
+ port = "${device}" if "${device}" else None
256830
+ vid = None
256831
+ if not port:
256832
+ port, vid = guess_port()
256833
+ if not port:
256834
+ print(json.dumps({"success": False, "error": "No GPS serial device found. Connect a USB GPS receiver."}))
256835
+ sys.exit(0)
256836
+
256837
+ # Try common baud rates \u2014 BU-353/363 use 4800, U-blox uses 9600
256838
+ last_lat = last_lon = last_alt = last_sats = last_hdop = last_speed = last_track = None
256839
+ fix_valid = False
256840
+ raw_sentences = []
256841
+ found_nmea = False
256842
+
256843
+ for baud in [4800, 9600, 38400, 115200]:
256844
+ try:
256845
+ with serial.Serial(port, baud, timeout=2) as ser:
256846
+ ser.reset_input_buffer()
256847
+ deadline = time.time() + min(${timeout2}, 15)
256848
+ while time.time() < deadline:
256849
+ try:
256850
+ line = ser.readline().decode(errors="ignore").strip()
256851
+ except: continue
256852
+ if not line.startswith("$"):
256853
+ continue
256854
+ found_nmea = True
256855
+ raw_sentences.append(line)
256856
+
256857
+ try:
256858
+ msg = pynmea2.parse(line, check=True)
256859
+ except: continue
256860
+
256861
+ if msg.sentence_type == "GGA":
256862
+ try:
256863
+ fix_valid = int(getattr(msg, 'gps_qual', 0) or 0) > 0
256864
+ if msg.latitude is not None: last_lat = float(msg.latitude)
256865
+ if msg.longitude is not None: last_lon = float(msg.longitude)
256866
+ if msg.altitude not in (None, ""): last_alt = float(msg.altitude)
256867
+ if msg.num_sats not in (None, ""): last_sats = int(msg.num_sats)
256868
+ if msg.horizontal_dil not in (None, ""): last_hdop = float(msg.horizontal_dil)
256869
+ except: pass
256870
+
256871
+ elif msg.sentence_type == "RMC":
256872
+ try:
256873
+ rmc_valid = getattr(msg, 'status', '') == 'A'
256874
+ if rmc_valid: fix_valid = True
256875
+ if msg.latitude is not None: last_lat = float(msg.latitude)
256876
+ if msg.longitude is not None: last_lon = float(msg.longitude)
256877
+ if msg.spd_over_grnd not in (None, ""): last_speed = float(msg.spd_over_grnd)
256878
+ if msg.true_course not in (None, ""): last_track = float(msg.true_course)
256879
+ except: pass
256880
+
256881
+ # If we have a valid fix with lat/lon, we're done
256882
+ if fix_valid and last_lat is not None and last_lon is not None:
256883
+ break
256884
+
256885
+ if found_nmea:
256886
+ break # found NMEA at this baud rate, stop trying others
256887
+ except Exception as e:
256888
+ continue
256889
+
256890
+ if not found_nmea:
256891
+ print(json.dumps({"success": False, "error": f"No NMEA data from {port}. Device may not be a GPS or needs different permissions."}))
256892
+ elif last_lat is None or last_lon is None:
256893
+ print(json.dumps({
256894
+ "success": True,
256895
+ "fix": False,
256896
+ "port": port,
256897
+ "baud": baud,
256898
+ "message": f"GPS on {port} responding but no fix yet. Sentences seen: {len(raw_sentences)}. Try again \u2014 cold start takes 30-60s.",
256899
+ "sample_nmea": raw_sentences[:3],
256900
+ }))
256901
+ else:
256902
+ print(json.dumps({
256903
+ "success": True,
256904
+ "fix": True,
256905
+ "port": port,
256906
+ "baud": baud,
256907
+ "lat": last_lat,
256908
+ "lon": last_lon,
256909
+ "alt_m": last_alt,
256910
+ "speed_knots": last_speed,
256911
+ "track_deg": last_track,
256912
+ "sats": last_sats,
256913
+ "hdop": last_hdop,
256914
+ "fix_valid": fix_valid,
256915
+ "sentences_read": len(raw_sentences),
256916
+ }))
256917
+ `, (timeout2 + 20) * 1e3);
256918
+ if (!result.success) {
256919
+ return { success: false, output: "", error: result.error || "GPS fix failed", durationMs: performance.now() - start2 };
256920
+ }
256921
+ if (!result.fix) {
256922
+ return { success: true, output: result.message + (result.sample_nmea ? `
256923
+
256924
+ Sample: ${result.sample_nmea.join("\n")}` : ""), durationMs: performance.now() - start2 };
256925
+ }
256702
256926
  return {
256703
256927
  success: true,
256704
- output: `GPS Fix (NMEA from ${device} @ ${baud} baud):
256705
- Position: ${fix.lat ?? "no fix"}, ${fix.lon ?? "no fix"}
256706
- Altitude: ${fix.alt ?? "unknown"}m
256707
- Satellites: ${fix.sats ?? "unknown"}
256708
- Fix quality: ${fix.quality ?? "unknown"}
256709
- Speed: ${rmcData.speed ?? "unknown"} knots
256710
- Time (UTC): ${fix.time ?? rmcData.time ?? "unknown"}
256711
-
256712
- Raw GGA: ${gga || "none"}
256713
- Raw RMC: ${rmc || "none"}`,
256928
+ output: `GPS Fix (${result.port} @ ${result.baud} baud):
256929
+ Position: ${result.lat}, ${result.lon}
256930
+ Altitude: ${result.alt_m != null ? result.alt_m + "m" : "unknown"}
256931
+ Speed: ${result.speed_knots != null ? (result.speed_knots * 1.852).toFixed(1) + " km/h" : "unknown"}
256932
+ Heading: ${result.track_deg != null ? result.track_deg + "\xB0" : "unknown"}
256933
+ Satellites: ${result.sats ?? "unknown"}${result.hdop ? ` (HDOP: ${result.hdop})` : ""}
256934
+ Fix valid: ${result.fix_valid ? "yes" : "no"}
256935
+ Sentences read: ${result.sentences_read}`,
256714
256936
  durationMs: performance.now() - start2
256715
256937
  };
256716
256938
  } catch (err) {
256717
- return { success: false, output: "", error: `NMEA read failed on ${device}: ${err instanceof Error ? err.message : String(err)}`, durationMs: performance.now() - start2 };
256939
+ return { success: false, output: "", error: `GPS fix error: ${err instanceof Error ? err.message : String(err)}`, durationMs: performance.now() - start2 };
256718
256940
  }
256719
256941
  }
256720
256942
  // =========================================================================
@@ -258250,10 +258472,10 @@ var init_client3 = __esm({
258250
258472
  // packages/execution/dist/mcp/manager.js
258251
258473
  import { existsSync as existsSync36, readFileSync as readFileSync26 } from "node:fs";
258252
258474
  import { join as join50 } from "node:path";
258253
- import { homedir as homedir13 } from "node:os";
258475
+ import { homedir as homedir14 } from "node:os";
258254
258476
  function loadMcpConfig(repoRoot) {
258255
258477
  const servers = {};
258256
- const globalPath = join50(homedir13(), ".open-agents", "mcp.json");
258478
+ const globalPath = join50(homedir14(), ".open-agents", "mcp.json");
258257
258479
  if (existsSync36(globalPath)) {
258258
258480
  try {
258259
258481
  const global2 = JSON.parse(readFileSync26(globalPath, "utf8"));
@@ -258557,10 +258779,10 @@ var init_mcp = __esm({
258557
258779
  // packages/execution/dist/plugins/plugin-system.js
258558
258780
  import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync27 } from "node:fs";
258559
258781
  import { join as join51 } from "node:path";
258560
- import { homedir as homedir14 } from "node:os";
258782
+ import { homedir as homedir15 } from "node:os";
258561
258783
  function discoverPlugins(repoRoot) {
258562
258784
  const plugins = [];
258563
- const globalDir = join51(homedir14(), ".open-agents", "plugins");
258785
+ const globalDir = join51(homedir15(), ".open-agents", "plugins");
258564
258786
  if (existsSync37(globalDir)) {
258565
258787
  plugins.push(...loadPluginsFromDir(globalDir));
258566
258788
  }
@@ -259987,10 +260209,10 @@ var init_buildRunner = __esm({
259987
260209
  // packages/execution/dist/constraints.js
259988
260210
  import { existsSync as existsSync42, readFileSync as readFileSync32, writeFileSync as writeFileSync17, mkdirSync as mkdirSync18 } from "node:fs";
259989
260211
  import { join as join55 } from "node:path";
259990
- import { homedir as homedir15 } from "node:os";
260212
+ import { homedir as homedir16 } from "node:os";
259991
260213
  function loadConstraints(projectRoot) {
259992
260214
  projectConstraints = loadFile(join55(projectRoot, ".oa", "constraints.json"));
259993
- globalConstraints = loadFile(join55(homedir15(), ".open-agents", "constraints.json"));
260215
+ globalConstraints = loadFile(join55(homedir16(), ".open-agents", "constraints.json"));
259994
260216
  }
259995
260217
  function loadFile(path5) {
259996
260218
  try {
@@ -270007,7 +270229,7 @@ __export(listen_exports, {
270007
270229
  import { spawn as spawn17, execSync as execSync41 } from "node:child_process";
270008
270230
  import { existsSync as existsSync45, mkdirSync as mkdirSync19, writeFileSync as writeFileSync19, readdirSync as readdirSync9 } from "node:fs";
270009
270231
  import { join as join60, dirname as dirname16 } from "node:path";
270010
- import { homedir as homedir16 } from "node:os";
270232
+ import { homedir as homedir17 } from "node:os";
270011
270233
  import { fileURLToPath as fileURLToPath9 } from "node:url";
270012
270234
  import { EventEmitter as EventEmitter3 } from "node:events";
270013
270235
  import { createInterface as createInterface2 } from "node:readline";
@@ -270117,7 +270339,7 @@ function findLiveWhisperScript() {
270117
270339
  }
270118
270340
  } catch {
270119
270341
  }
270120
- const nvmBase = join60(homedir16(), ".nvm", "versions", "node");
270342
+ const nvmBase = join60(homedir17(), ".nvm", "versions", "node");
270121
270343
  if (existsSync45(nvmBase)) {
270122
270344
  try {
270123
270345
  for (const ver of readdirSync9(nvmBase)) {
@@ -270365,7 +270587,7 @@ var init_listen = __esm({
270365
270587
  }
270366
270588
  } catch {
270367
270589
  }
270368
- const nvmBase = join60(homedir16(), ".nvm", "versions", "node");
270590
+ const nvmBase = join60(homedir17(), ".nvm", "versions", "node");
270369
270591
  if (existsSync45(nvmBase)) {
270370
270592
  try {
270371
270593
  const { readdirSync: readdirSync26 } = await import("node:fs");
@@ -280191,7 +280413,7 @@ __export(oa_directory_exports, {
280191
280413
  });
280192
280414
  import { existsSync as existsSync49, mkdirSync as mkdirSync22, readFileSync as readFileSync37, writeFileSync as writeFileSync22, readdirSync as readdirSync11, statSync as statSync16, unlinkSync as unlinkSync11 } from "node:fs";
280193
280415
  import { join as join65, relative as relative4, basename as basename12 } from "node:path";
280194
- import { homedir as homedir17 } from "node:os";
280416
+ import { homedir as homedir18 } from "node:os";
280195
280417
  function initOaDirectory(repoRoot) {
280196
280418
  const oaPath = join65(repoRoot, OA_DIR);
280197
280419
  for (const sub of SUBDIRS) {
@@ -280231,7 +280453,7 @@ function saveProjectSettings(repoRoot, settings) {
280231
280453
  writeFileSync22(join65(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
280232
280454
  }
280233
280455
  function loadGlobalSettings() {
280234
- const settingsPath = join65(homedir17(), ".open-agents", "settings.json");
280456
+ const settingsPath = join65(homedir18(), ".open-agents", "settings.json");
280235
280457
  try {
280236
280458
  if (existsSync49(settingsPath)) {
280237
280459
  return JSON.parse(readFileSync37(settingsPath, "utf-8"));
@@ -280241,7 +280463,7 @@ function loadGlobalSettings() {
280241
280463
  return {};
280242
280464
  }
280243
280465
  function saveGlobalSettings(settings) {
280244
- const dir = join65(homedir17(), ".open-agents");
280466
+ const dir = join65(homedir18(), ".open-agents");
280245
280467
  mkdirSync22(dir, { recursive: true });
280246
280468
  const existing = loadGlobalSettings();
280247
280469
  const merged = { ...existing, ...settings };
@@ -280739,13 +280961,13 @@ function recordUsage(kind, value2, opts) {
280739
280961
  }
280740
280962
  saveUsageFile(filePath, data);
280741
280963
  };
280742
- update2(join65(homedir17(), ".open-agents", USAGE_HISTORY_FILE));
280964
+ update2(join65(homedir18(), ".open-agents", USAGE_HISTORY_FILE));
280743
280965
  if (opts?.repoRoot) {
280744
280966
  update2(join65(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
280745
280967
  }
280746
280968
  }
280747
280969
  function loadUsageHistory(kind, repoRoot) {
280748
- const globalPath = join65(homedir17(), ".open-agents", USAGE_HISTORY_FILE);
280970
+ const globalPath = join65(homedir18(), ".open-agents", USAGE_HISTORY_FILE);
280749
280971
  const globalData = loadUsageFile(globalPath);
280750
280972
  const localData = repoRoot ? loadUsageFile(join65(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
280751
280973
  const map2 = /* @__PURE__ */ new Map();
@@ -280776,7 +280998,7 @@ function deleteUsageRecord(kind, value2, repoRoot) {
280776
280998
  saveUsageFile(filePath, data);
280777
280999
  }
280778
281000
  };
280779
- remove(join65(homedir17(), ".open-agents", USAGE_HISTORY_FILE));
281001
+ remove(join65(homedir18(), ".open-agents", USAGE_HISTORY_FILE));
280780
281002
  if (repoRoot) {
280781
281003
  remove(join65(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
280782
281004
  }
@@ -285332,7 +285554,7 @@ __export(personaplex_exports, {
285332
285554
  });
285333
285555
  import { existsSync as existsSync50, writeFileSync as writeFileSync23, readFileSync as readFileSync39, mkdirSync as mkdirSync23, copyFileSync as copyFileSync2, readdirSync as readdirSync12, statSync as statSync17 } from "node:fs";
285334
285556
  import { join as join66, dirname as dirname20 } from "node:path";
285335
- import { homedir as homedir18 } from "node:os";
285557
+ import { homedir as homedir19 } from "node:os";
285336
285558
  import { execSync as execSync44, spawn as spawn20 } from "node:child_process";
285337
285559
  import { fileURLToPath as fileURLToPath12 } from "node:url";
285338
285560
  function execAsync(cmd, opts = {}) {
@@ -285927,7 +286149,7 @@ print('Converted')
285927
286149
  let ollamaModel = process.env["HYBRID_LLM_MODEL"] || "";
285928
286150
  if (!ollamaModel) {
285929
286151
  try {
285930
- const oaConfig = JSON.parse(readFileSync39(join66(homedir18(), ".open-agents", "config.json"), "utf8"));
286152
+ const oaConfig = JSON.parse(readFileSync39(join66(homedir19(), ".open-agents", "config.json"), "utf8"));
285931
286153
  if (oaConfig.model) ollamaModel = oaConfig.model;
285932
286154
  } catch {
285933
286155
  }
@@ -286198,7 +286420,7 @@ function provisionShippedVoices(onInfo) {
286198
286420
  return deployed;
286199
286421
  }
286200
286422
  function getHFVoicesDir() {
286201
- const hfBase = join66(homedir18(), ".cache", "huggingface", "hub", "models--nvidia--personaplex-7b-v1");
286423
+ const hfBase = join66(homedir19(), ".cache", "huggingface", "hub", "models--nvidia--personaplex-7b-v1");
286202
286424
  if (!existsSync50(hfBase)) return null;
286203
286425
  try {
286204
286426
  const snapshots = join66(hfBase, "snapshots");
@@ -286214,7 +286436,7 @@ function getHFVoicesDir() {
286214
286436
  function patchFrontendVoiceList(onInfo) {
286215
286437
  const log22 = onInfo ?? (() => {
286216
286438
  });
286217
- const hfBase = join66(homedir18(), ".cache", "huggingface", "hub", "models--nvidia--personaplex-7b-v1");
286439
+ const hfBase = join66(homedir19(), ".cache", "huggingface", "hub", "models--nvidia--personaplex-7b-v1");
286218
286440
  if (!existsSync50(hfBase)) return;
286219
286441
  try {
286220
286442
  const snapshots = join66(hfBase, "snapshots");
@@ -286292,7 +286514,7 @@ var init_personaplex = __esm({
286292
286514
  nf4: { repo: "cudabenchmarktest/personaplex-7b-nf4", file: "model-nf4.safetensors", sizeGB: 4.1, needsToken: false },
286293
286515
  "nf4-distilled": { repo: "cudabenchmarktest/personaplex-7b-nf4-distilled", file: "student_best.pt", sizeGB: 16.7, needsToken: false }
286294
286516
  };
286295
- PERSONAPLEX_DIR = join66(homedir18(), ".open-agents", "voice", "personaplex");
286517
+ PERSONAPLEX_DIR = join66(homedir19(), ".open-agents", "voice", "personaplex");
286296
286518
  PID_FILE = join66(PERSONAPLEX_DIR, "daemon.pid");
286297
286519
  PORT_FILE = join66(PERSONAPLEX_DIR, "daemon.port");
286298
286520
  LOG_FILE = join66(PERSONAPLEX_DIR, "daemon.log");
@@ -286339,7 +286561,7 @@ import { execSync as execSync45, spawn as spawn21, exec as exec4 } from "node:ch
286339
286561
  import { promisify as promisify7 } from "node:util";
286340
286562
  import { existsSync as existsSync51, writeFileSync as writeFileSync24, readFileSync as readFileSync40, appendFileSync as appendFileSync2, mkdirSync as mkdirSync24 } from "node:fs";
286341
286563
  import { join as join67 } from "node:path";
286342
- import { homedir as homedir19, platform as platform3 } from "node:os";
286564
+ import { homedir as homedir20, platform as platform3 } from "node:os";
286343
286565
  async function checkToolSupport(modelName, backendUrl = "http://localhost:11434") {
286344
286566
  if (_toolSupportCache.has(modelName)) return _toolSupportCache.get(modelName);
286345
286567
  try {
@@ -287438,7 +287660,7 @@ async function doSetup(config, rl) {
287438
287660
  `PARAMETER num_predict ${numPredict}`,
287439
287661
  `PARAMETER stop "<|endoftext|>"`
287440
287662
  ].join("\n");
287441
- const modelDir2 = join67(homedir19(), ".open-agents", "models");
287663
+ const modelDir2 = join67(homedir20(), ".open-agents", "models");
287442
287664
  mkdirSync24(modelDir2, { recursive: true });
287443
287665
  const modelfilePath = join67(modelDir2, `Modelfile.${customName}`);
287444
287666
  writeFileSync24(modelfilePath, modelfileContent + "\n", "utf8");
@@ -287486,7 +287708,7 @@ async function isModelAvailable(config) {
287486
287708
  }
287487
287709
  function isFirstRun() {
287488
287710
  try {
287489
- return !existsSync51(join67(homedir19(), ".open-agents", "config.json"));
287711
+ return !existsSync51(join67(homedir20(), ".open-agents", "config.json"));
287490
287712
  } catch {
287491
287713
  return true;
287492
287714
  }
@@ -287534,7 +287756,7 @@ function detectPkgManager() {
287534
287756
  return null;
287535
287757
  }
287536
287758
  function getVenvDir() {
287537
- return join67(homedir19(), ".open-agents", "venv");
287759
+ return join67(homedir20(), ".open-agents", "venv");
287538
287760
  }
287539
287761
  function hasVenvModule() {
287540
287762
  try {
@@ -287560,7 +287782,7 @@ function ensureVenv(log22) {
287560
287782
  return null;
287561
287783
  }
287562
287784
  try {
287563
- mkdirSync24(join67(homedir19(), ".open-agents"), { recursive: true });
287785
+ mkdirSync24(join67(homedir20(), ".open-agents"), { recursive: true });
287564
287786
  const pyCmd = hasCmd(pythonCmd) ? pythonCmd : "python3";
287565
287787
  execSync45(`${pyCmd} -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
287566
287788
  execSync45(`"${pipPath}" install --upgrade pip`, {
@@ -287660,7 +287882,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
287660
287882
  ];
287661
287883
  {
287662
287884
  const pm2 = detectPkgManager();
287663
- const _visionMarkerDir = join67(homedir19(), ".open-agents");
287885
+ const _visionMarkerDir = join67(homedir20(), ".open-agents");
287664
287886
  const _visionMarkerFile = join67(_visionMarkerDir, "vision-deps-installed.json");
287665
287887
  let _visionPreviouslyInstalled = /* @__PURE__ */ new Set();
287666
287888
  try {
@@ -287913,11 +288135,11 @@ function ensureCloudflaredBackground(onInfo) {
287913
288135
  const cfArch = archMap[arch2] ?? "amd64";
287914
288136
  try {
287915
288137
  execSync45(
287916
- `curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir19()}/.local/bin" && mv /tmp/cloudflared "${homedir19()}/.local/bin/cloudflared"`,
288138
+ `curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${cfArch}" -o /tmp/cloudflared && chmod +x /tmp/cloudflared && mkdir -p "${homedir20()}/.local/bin" && mv /tmp/cloudflared "${homedir20()}/.local/bin/cloudflared"`,
287917
288139
  { stdio: "pipe", timeout: 6e4 }
287918
288140
  );
287919
- if (!process.env.PATH?.includes(`${homedir19()}/.local/bin`)) {
287920
- process.env.PATH = `${homedir19()}/.local/bin:${process.env.PATH}`;
288141
+ if (!process.env.PATH?.includes(`${homedir20()}/.local/bin`)) {
288142
+ process.env.PATH = `${homedir20()}/.local/bin:${process.env.PATH}`;
287921
288143
  }
287922
288144
  if (hasCmd("cloudflared")) {
287923
288145
  log22("cloudflared installed.");
@@ -288014,7 +288236,7 @@ function createExpandedVariant(baseModel, specs, sizeGB, kvBytesPerToken, archMa
288014
288236
  `PARAMETER num_predict ${numPredict}`,
288015
288237
  `PARAMETER stop "<|endoftext|>"`
288016
288238
  ].join("\n");
288017
- const modelDir2 = join67(homedir19(), ".open-agents", "models");
288239
+ const modelDir2 = join67(homedir20(), ".open-agents", "models");
288018
288240
  mkdirSync24(modelDir2, { recursive: true });
288019
288241
  const modelfilePath = join67(modelDir2, `Modelfile.${customName}`);
288020
288242
  writeFileSync24(modelfilePath, modelfileContent + "\n", "utf8");
@@ -288039,7 +288261,7 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
288039
288261
  `PARAMETER num_predict ${numPredict}`,
288040
288262
  `PARAMETER stop "<|endoftext|>"`
288041
288263
  ].join("\n");
288042
- const modelDir2 = join67(homedir19(), ".open-agents", "models");
288264
+ const modelDir2 = join67(homedir20(), ".open-agents", "models");
288043
288265
  mkdirSync24(modelDir2, { recursive: true });
288044
288266
  const modelfilePath = join67(modelDir2, `Modelfile.${customName}`);
288045
288267
  writeFileSync24(modelfilePath, modelfileContent + "\n", "utf8");
@@ -288115,7 +288337,7 @@ async function ensureNeovim() {
288115
288337
  const platform6 = process.platform;
288116
288338
  const arch2 = process.arch;
288117
288339
  if (platform6 === "linux") {
288118
- const binDir = join67(homedir19(), ".local", "bin");
288340
+ const binDir = join67(homedir20(), ".local", "bin");
288119
288341
  const nvimDest = join67(binDir, "nvim");
288120
288342
  try {
288121
288343
  mkdirSync24(binDir, { recursive: true });
@@ -288187,7 +288409,7 @@ async function ensureNeovim() {
288187
288409
  }
288188
288410
  function ensurePathInShellRc(binDir) {
288189
288411
  const shell = process.env.SHELL ?? "";
288190
- const rcFile = shell.includes("zsh") ? join67(homedir19(), ".zshrc") : join67(homedir19(), ".bashrc");
288412
+ const rcFile = shell.includes("zsh") ? join67(homedir20(), ".zshrc") : join67(homedir20(), ".bashrc");
288191
288413
  try {
288192
288414
  const rcContent = existsSync51(rcFile) ? readFileSync40(rcFile, "utf8") : "";
288193
288415
  if (rcContent.includes(binDir)) return;
@@ -288930,7 +289152,7 @@ __export(daemon_exports, {
288930
289152
  import { spawn as spawn22 } from "node:child_process";
288931
289153
  import { existsSync as existsSync54, readFileSync as readFileSync41, writeFileSync as writeFileSync25, mkdirSync as mkdirSync25, unlinkSync as unlinkSync13 } from "node:fs";
288932
289154
  import { join as join69 } from "node:path";
288933
- import { homedir as homedir20 } from "node:os";
289155
+ import { homedir as homedir21 } from "node:os";
288934
289156
  import { fileURLToPath as fileURLToPath13 } from "node:url";
288935
289157
  import { dirname as dirname21 } from "node:path";
288936
289158
  function getDaemonPort() {
@@ -289081,7 +289303,7 @@ var OA_DIR2, PID_FILE2, DEFAULT_PORT2;
289081
289303
  var init_daemon = __esm({
289082
289304
  "packages/cli/src/daemon.ts"() {
289083
289305
  "use strict";
289084
- OA_DIR2 = join69(homedir20(), ".open-agents");
289306
+ OA_DIR2 = join69(homedir21(), ".open-agents");
289085
289307
  PID_FILE2 = join69(OA_DIR2, "daemon.pid");
289086
289308
  DEFAULT_PORT2 = 11435;
289087
289309
  }
@@ -290381,7 +290603,7 @@ __export(voice_exports, {
290381
290603
  });
290382
290604
  import { existsSync as existsSync56, mkdirSync as mkdirSync27, writeFileSync as writeFileSync27, readFileSync as readFileSync43, unlinkSync as unlinkSync14, readdirSync as readdirSync13, statSync as statSync18 } from "node:fs";
290383
290605
  import { join as join71, dirname as dirname22 } from "node:path";
290384
- import { homedir as homedir21, tmpdir as tmpdir15, platform as platform4 } from "node:os";
290606
+ import { homedir as homedir22, tmpdir as tmpdir15, platform as platform4 } from "node:os";
290385
290607
  import { execSync as execSync47, spawn as nodeSpawn } from "node:child_process";
290386
290608
  import { createRequire as createRequire2 } from "node:module";
290387
290609
  function sanitizeForTTS(text) {
@@ -290405,7 +290627,7 @@ function listVoiceModels() {
290405
290627
  }));
290406
290628
  }
290407
290629
  function voiceDir() {
290408
- return join71(homedir21(), ".open-agents", "voice");
290630
+ return join71(homedir22(), ".open-agents", "voice");
290409
290631
  }
290410
290632
  function modelsDir() {
290411
290633
  return join71(voiceDir(), "models");
@@ -291337,7 +291559,7 @@ var init_voice = __esm({
291337
291559
  }
291338
291560
  p2 = p2.replace(/\\ /g, " ");
291339
291561
  if (p2.startsWith("~/") || p2 === "~") {
291340
- p2 = join71(homedir21(), p2.slice(1));
291562
+ p2 = join71(homedir22(), p2.slice(1));
291341
291563
  }
291342
291564
  if (!existsSync56(p2)) {
291343
291565
  return `File not found: ${p2}
@@ -292541,11 +292763,27 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
292541
292763
  // ARM: install individually so we get clear error messages per package.
292542
292764
  // ALL are fatal because LuxTTS hard-imports them (no lazy/optional imports).
292543
292765
  { cmd: `${pipCmd} -m pip install --quiet "setuptools<81" wheel`, fatal: true, label: "setuptools" },
292544
- // Jetson: try NVIDIA's prebuilt PyTorch wheel first (has CUDA support)
292545
- ...isJetson ? [
292546
- { cmd: `${pipCmd} -m pip install --quiet torch --index-url https://developer.download.nvidia.com/compute/redist/jp/v60/pytorch/ 2>/dev/null || ${pipCmd} -m pip install --quiet torch`, fatal: true, label: "PyTorch (Jetson L4T)" },
292547
- { cmd: `${pipCmd} -m pip install --quiet onnxruntime-gpu 2>/dev/null || true`, fatal: false, label: "onnxruntime-gpu (Jetson, optional)" }
292548
- ] : [
292766
+ // Jetson: try NVIDIA's prebuilt PyTorch wheel for detected JetPack version.
292767
+ // JetPack versions have different PyTorch wheel URLs:
292768
+ // JP6.x: https://developer.download.nvidia.com/compute/redist/jp/v60/pytorch/
292769
+ // JP5.x: https://developer.download.nvidia.com/compute/redist/jp/v51/pytorch/
292770
+ // Auto-detect JetPack version from /etc/nv_tegra_release or dpkg.
292771
+ ...isJetson ? (() => {
292772
+ let jpVer = "v60";
292773
+ try {
292774
+ const tegra = existsSync56("/etc/nv_tegra_release") ? execSync47("cat /etc/nv_tegra_release 2>/dev/null", { encoding: "utf8", timeout: 3e3 }).trim() : "";
292775
+ const dpkg = execSync47("dpkg -l nvidia-jetpack 2>/dev/null | grep nvidia-jetpack | awk '{print $3}'", { encoding: "utf8", timeout: 5e3 }).trim();
292776
+ const ver = dpkg || process.env.JETSON_L4T_VERSION || "";
292777
+ if (ver.startsWith("5.") || tegra.includes("R35") || tegra.includes("R34")) jpVer = "v51";
292778
+ else if (ver.startsWith("6.1") || tegra.includes("R36.4")) jpVer = "v61";
292779
+ else if (ver.startsWith("6.") || tegra.includes("R36")) jpVer = "v60";
292780
+ } catch {
292781
+ }
292782
+ return [
292783
+ { cmd: `${pipCmd} -m pip install --quiet torch torchvision torchaudio --index-url https://developer.download.nvidia.com/compute/redist/jp/${jpVer}/pytorch/ 2>/dev/null || ${pipCmd} -m pip install --quiet torch torchaudio`, fatal: true, label: `PyTorch (Jetson JP ${jpVer})` },
292784
+ { cmd: `${pipCmd} -m pip install --quiet onnxruntime-gpu 2>/dev/null || true`, fatal: false, label: "onnxruntime-gpu (Jetson, optional)" }
292785
+ ];
292786
+ })() : [
292549
292787
  // Non-Jetson ARM: use default PyPI (has aarch64 wheels).
292550
292788
  // DO NOT use --index-url https://download.pytorch.org/whl/cpu — that index
292551
292789
  // only has x86_64 wheels. ARM needs the standard PyPI torch package.
@@ -292563,7 +292801,9 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
292563
292801
  { cmd: `${pipCmd} -m pip install --quiet lhotse`, fatal: true, label: "lhotse" },
292564
292802
  // vocos: try pip, fallback to building from source if wheels missing
292565
292803
  { cmd: `${pipCmd} -m pip install --quiet vocos 2>/dev/null || ${pipCmd} -m pip install --quiet --no-build-isolation vocos`, fatal: true, label: "vocos" },
292566
- { cmd: `${pipCmd} -m pip install --quiet "git+https://github.com/ysharma3501/LinaCodec.git"`, fatal: true, label: "LinaCodec" },
292804
+ // LinaCodec: needs C++ build tools on ARM. Install with --no-build-isolation
292805
+ // and fallback to CPU-only if CUDA compilation fails.
292806
+ { cmd: `${pipCmd} -m pip install --quiet "git+https://github.com/ysharma3501/LinaCodec.git" 2>/dev/null || ${pipCmd} -m pip install --quiet --no-build-isolation "git+https://github.com/ysharma3501/LinaCodec.git"`, fatal: true, label: "LinaCodec (voice cloning codec)" },
292567
292807
  // Non-fatal (not hard-imported by LuxTTS):
292568
292808
  { cmd: `${pipCmd} -m pip install --quiet piper-phonemize --find-links https://k2-fsa.github.io/icefall/piper_phonemize.html`, fatal: false, label: "piper-phonemize (optional)" },
292569
292809
  { cmd: `${pipCmd} -m pip install --quiet jieba pypinyin cn2an`, fatal: true, label: "Chinese text processing" },
@@ -293687,9 +293927,9 @@ async function handleSlashCommand(input, ctx3) {
293687
293927
  renderInfo("No wallet configured. Ask the agent to create one via the nexus tool.");
293688
293928
  }
293689
293929
  } else if (sub === "name") {
293690
- const { homedir: homedir28 } = __require("node:os");
293930
+ const { homedir: homedir29 } = __require("node:os");
293691
293931
  const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
293692
- const namePath = __require("node:path").join(homedir28(), ".open-agents", "agent-name");
293932
+ const namePath = __require("node:path").join(homedir29(), ".open-agents", "agent-name");
293693
293933
  if (rest2) {
293694
293934
  const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
293695
293935
  if (!customName) {
@@ -295388,8 +295628,8 @@ The session corrections MUST become hard rules in the SKILL.md Rules section.`;
295388
295628
  let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
295389
295629
  if (!sponsorName || sponsorName.length < 2) {
295390
295630
  try {
295391
- const { homedir: homedir28 } = __require("os");
295392
- const namePath = __require("path").join(homedir28(), ".open-agents", "agent-name");
295631
+ const { homedir: homedir29 } = __require("os");
295632
+ const namePath = __require("path").join(homedir29(), ".open-agents", "agent-name");
295393
295633
  if (existsSync57(namePath)) sponsorName = readFileSync44(namePath, "utf8").trim();
295394
295634
  } catch {
295395
295635
  }
@@ -296849,9 +297089,9 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
296849
297089
  }
296850
297090
  const { basename: basename19, join: pathJoin } = await import("node:path");
296851
297091
  const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync43, existsSync: exists2 } = await import("node:fs");
296852
- const { homedir: homedir28 } = await import("node:os");
297092
+ const { homedir: homedir29 } = await import("node:os");
296853
297093
  const modelName = basename19(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
296854
- const destDir = pathJoin(homedir28(), ".open-agents", "voice", "models", modelName);
297094
+ const destDir = pathJoin(homedir29(), ".open-agents", "voice", "models", modelName);
296855
297095
  if (!exists2(destDir)) mkdirSync43(destDir, { recursive: true });
296856
297096
  copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
296857
297097
  copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
@@ -299073,7 +299313,7 @@ var init_commands = __esm({
299073
299313
  import { existsSync as existsSync58, readFileSync as readFileSync45, readdirSync as readdirSync15 } from "node:fs";
299074
299314
  import { join as join73, basename as basename13 } from "node:path";
299075
299315
  import { execSync as execSync48 } from "node:child_process";
299076
- import { homedir as homedir23, platform as platform5, release } from "node:os";
299316
+ import { homedir as homedir24, platform as platform5, release } from "node:os";
299077
299317
  function getModelTier(modelName) {
299078
299318
  const m2 = modelName.toLowerCase();
299079
299319
  const sizeMatch = m2.match(/\b(\d+)b\b/);
@@ -299152,7 +299392,7 @@ function loadMemoryContext(repoRoot) {
299152
299392
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
299153
299393
  if (legacyEntries) sections.push(legacyEntries);
299154
299394
  }
299155
- const globalMemDir = join73(homedir23(), ".open-agents", "memory");
299395
+ const globalMemDir = join73(homedir24(), ".open-agents", "memory");
299156
299396
  const globalEntries = loadMemoryDir(globalMemDir, "global");
299157
299397
  if (globalEntries) sections.push(globalEntries);
299158
299398
  return sections.join("\n\n");
@@ -308443,10 +308683,10 @@ var init_usage_tracker = __esm({
308443
308683
  // packages/cli/src/api/profiles.ts
308444
308684
  import { existsSync as existsSync69, readFileSync as readFileSync55, writeFileSync as writeFileSync34, mkdirSync as mkdirSync37, readdirSync as readdirSync22, unlinkSync as unlinkSync17 } from "node:fs";
308445
308685
  import { join as join85 } from "node:path";
308446
- import { homedir as homedir24 } from "node:os";
308686
+ import { homedir as homedir25 } from "node:os";
308447
308687
  import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync3 } from "node:crypto";
308448
308688
  function globalProfileDir() {
308449
- return join85(homedir24(), ".open-agents", "profiles");
308689
+ return join85(homedir25(), ".open-agents", "profiles");
308450
308690
  }
308451
308691
  function projectProfileDir(projectDir) {
308452
308692
  return join85(projectDir || process.cwd(), ".oa", "profiles");
@@ -308638,7 +308878,7 @@ var init_profiles = __esm({
308638
308878
  import { execSync as execSync50, spawn as spawn23 } from "node:child_process";
308639
308879
  import { existsSync as existsSync70, mkdirSync as mkdirSync38, writeFileSync as writeFileSync35 } from "node:fs";
308640
308880
  import { join as join86, resolve as resolve33, dirname as dirname24 } from "node:path";
308641
- import { homedir as homedir25 } from "node:os";
308881
+ import { homedir as homedir26 } from "node:os";
308642
308882
  import { fileURLToPath as fileURLToPath15 } from "node:url";
308643
308883
  function getDockerDir() {
308644
308884
  try {
@@ -308786,7 +309026,7 @@ async function ensureOaImage(force = false) {
308786
309026
  if (existsSync70(join86(dockerDir, "Dockerfile"))) {
308787
309027
  buildContext = dockerDir;
308788
309028
  } else {
308789
- buildContext = join86(homedir25(), ".oa", "docker-build");
309029
+ buildContext = join86(homedir26(), ".oa", "docker-build");
308790
309030
  mkdirSync38(buildContext, { recursive: true });
308791
309031
  writeDockerfiles(buildContext);
308792
309032
  }
@@ -310859,7 +311099,7 @@ import { fileURLToPath as fileURLToPath17 } from "node:url";
310859
311099
  import { readFileSync as readFileSync57, writeFileSync as writeFileSync37, appendFileSync as appendFileSync6, rmSync as rmSync4, readdirSync as readdirSync24, mkdirSync as mkdirSync40 } from "node:fs";
310860
311100
  import { existsSync as existsSync72 } from "node:fs";
310861
311101
  import { execSync as execSync52 } from "node:child_process";
310862
- import { homedir as homedir26 } from "node:os";
311102
+ import { homedir as homedir27 } from "node:os";
310863
311103
  function formatTimeAgo(date) {
310864
311104
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
310865
311105
  if (seconds < 60) return "just now";
@@ -313421,7 +313661,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
313421
313661
  const hits = allCompletions.filter((c7) => c7.toLowerCase().startsWith(lower));
313422
313662
  return [hits, line];
313423
313663
  }
313424
- const HISTORY_DIR = join88(homedir26(), ".open-agents");
313664
+ const HISTORY_DIR = join88(homedir27(), ".open-agents");
313425
313665
  const HISTORY_FILE = join88(HISTORY_DIR, "repl-history");
313426
313666
  const MAX_HISTORY_LINES = 500;
313427
313667
  let savedHistory = [];
@@ -315207,7 +315447,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
315207
315447
  } catch {
315208
315448
  }
315209
315449
  try {
315210
- const voiceDir2 = join88(homedir26(), ".open-agents", "voice");
315450
+ const voiceDir2 = join88(homedir27(), ".open-agents", "voice");
315211
315451
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
315212
315452
  for (const pf of voicePidFiles) {
315213
315453
  const pidPath = join88(voiceDir2, pf);
@@ -315320,8 +315560,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
315320
315560
  try {
315321
315561
  const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
315322
315562
  if (isPersonaPlexRunning2()) {
315323
- const ppPidFile = join88(homedir26(), ".open-agents", "voice", "personaplex", "daemon.pid");
315324
- const ppPortFile = join88(homedir26(), ".open-agents", "voice", "personaplex", "daemon.port");
315563
+ const ppPidFile = join88(homedir27(), ".open-agents", "voice", "personaplex", "daemon.pid");
315564
+ const ppPortFile = join88(homedir27(), ".open-agents", "voice", "personaplex", "daemon.port");
315325
315565
  if (existsSync72(ppPidFile)) {
315326
315566
  const ppPid = parseInt(readFileSync57(ppPidFile, "utf8").trim(), 10);
315327
315567
  const ppPort = existsSync72(ppPortFile) ? parseInt(readFileSync57(ppPortFile, "utf8").trim(), 10) : void 0;
@@ -317241,7 +317481,7 @@ __export(config_exports2, {
317241
317481
  configCommand: () => configCommand
317242
317482
  });
317243
317483
  import { join as join91, resolve as resolve38 } from "node:path";
317244
- import { homedir as homedir27 } from "node:os";
317484
+ import { homedir as homedir28 } from "node:os";
317245
317485
  import { cwd as cwd3 } from "node:process";
317246
317486
  function redactIfSensitive(key, value2) {
317247
317487
  if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
@@ -317322,7 +317562,7 @@ function handleShow(opts, config) {
317322
317562
  }
317323
317563
  }
317324
317564
  printSection("Config File");
317325
- printInfo(`~/.open-agents/config.json (${join91(homedir27(), ".open-agents", "config.json")})`);
317565
+ printInfo(`~/.open-agents/config.json (${join91(homedir28(), ".open-agents", "config.json")})`);
317326
317566
  printSection("Priority Chain");
317327
317567
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
317328
317568
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -318127,8 +318367,8 @@ function crashLog(label, err) {
318127
318367
  try {
318128
318368
  const { appendFileSync: appendFileSync7, mkdirSync: mkdirSync43 } = __require("node:fs");
318129
318369
  const { join: join94 } = __require("node:path");
318130
- const { homedir: homedir28 } = __require("node:os");
318131
- const logDir = join94(homedir28(), ".open-agents");
318370
+ const { homedir: homedir29 } = __require("node:os");
318371
+ const logDir = join94(homedir29(), ".open-agents");
318132
318372
  mkdirSync43(logDir, { recursive: true });
318133
318373
  appendFileSync7(join94(logDir, "crash.log"), logLine);
318134
318374
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.149",
3
+ "version": "0.187.151",
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",