open-agents-ai 0.187.148 → 0.187.150

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 +371 -137
  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"() {
@@ -256456,10 +256456,14 @@ var init_gps_location = __esm({
256456
256456
  init_system_auth();
256457
256457
  GPS_USB_IDS = [
256458
256458
  // ── GlobalSat / BU-series (SiRF Star IV, Prolific UART bridge) ──────────
256459
- { vid: "067b", pid: "2303", name: "BU-353N / BU-353S4 (Prolific PL2303)", baud: 4800, notes: "Most popular USB GPS puck" },
256460
- { vid: "067b", pid: "23a3", name: "BU-353S4 (Prolific PL2303GT)", baud: 4800 },
256461
- { vid: "067b", pid: "2304", name: "GlobalSat (Prolific PL2303HXD)", baud: 4800 },
256462
- { vid: "067b", pid: "aaa0", name: "GlobalSat (Prolific PL2303HX Rev A)", baud: 4800 },
256459
+ // BU-353N, BU-353S4, BU-363, BU-503, BU-355 all use Prolific UART chips
256460
+ // The BU-363 specifically is a common USB GPS puck with SiRF Star IV
256461
+ { vid: "067b", pid: "2303", name: "GlobalSat BU-353/363 (Prolific PL2303)", baud: 4800, notes: "Most popular USB GPS puck family" },
256462
+ { vid: "067b", pid: "23a3", name: "GlobalSat BU-353S4/363 (Prolific PL2303GT)", baud: 4800 },
256463
+ { vid: "067b", pid: "2304", name: "GlobalSat BU-series (Prolific PL2303HXD)", baud: 4800 },
256464
+ { vid: "067b", pid: "aaa0", name: "GlobalSat BU-series (Prolific PL2303HX Rev A)", baud: 4800 },
256465
+ { vid: "067b", pid: "aaa2", name: "GlobalSat BU-series (Prolific PL2303 var)", baud: 4800 },
256466
+ { vid: "067b", pid: "2300", name: "Prolific PL2300 (GPS serial)", baud: 4800 },
256463
256467
  // ── U-blox GNSS family (direct USB — ACM devices) ──────────────────────
256464
256468
  { vid: "1546", pid: "01a5", name: "U-blox 5 (LEA-5T)", baud: 9600 },
256465
256469
  { vid: "1546", pid: "01a6", name: "U-blox 6 (NEO-6M)", baud: 9600, notes: "Very common maker GPS" },
@@ -256545,13 +256549,63 @@ var init_gps_location = __esm({
256545
256549
  },
256546
256550
  required: ["action"]
256547
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
+ }
256548
256602
  async execute(args) {
256549
256603
  const action = args["action"];
256550
256604
  const start2 = performance.now();
256551
256605
  try {
256552
256606
  switch (action) {
256553
256607
  case "detect":
256554
- return await this.detectGps(start2);
256608
+ return await this.detectGps(args, start2);
256555
256609
  case "fix":
256556
256610
  return await this.getFix(args, start2);
256557
256611
  case "nmea":
@@ -256572,64 +256626,128 @@ var init_gps_location = __esm({
256572
256626
  // =========================================================================
256573
256627
  // Detect GPS hardware
256574
256628
  // =========================================================================
256575
- 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) {
256576
256728
  const devices = [];
256577
256729
  try {
256578
256730
  const lsusb = execSync36("lsusb 2>/dev/null", { encoding: "utf8", timeout: 5e3 });
256579
256731
  for (const known of GPS_USB_IDS) {
256580
256732
  if (lsusb.toLowerCase().includes(`${known.vid}:${known.pid}`)) {
256581
- const line = lsusb.split("\n").find((l2) => l2.toLowerCase().includes(`${known.vid}:${known.pid}`));
256582
- devices.push(` USB: ${known.name} \u2014 ${line?.trim() || `${known.vid}:${known.pid}`}`);
256583
- }
256584
- }
256585
- for (const line of lsusb.split("\n")) {
256586
- if (/gps|gnss|navsat/i.test(line) && !devices.some((d2) => d2.includes(line.trim()))) {
256587
- devices.push(` USB: ${line.trim()}`);
256733
+ devices.push(` ${known.name}`);
256588
256734
  }
256589
256735
  }
256590
256736
  } catch {
256591
256737
  }
256592
- const serialDevs = [];
256593
- for (const pattern of ["/dev/ttyUSB*", "/dev/ttyACM*"]) {
256594
- try {
256595
- const devs = execSync36(`ls ${pattern} 2>/dev/null`, { encoding: "utf8", timeout: 3e3 }).trim().split("\n").filter(Boolean);
256596
- serialDevs.push(...devs);
256597
- } catch {
256598
- }
256599
- }
256600
- for (const dev of serialDevs) {
256601
- try {
256602
- const udev = execSync36(`udevadm info --query=all --name=${dev} 2>/dev/null`, { encoding: "utf8", timeout: 3e3 });
256603
- const vendor = udev.match(/ID_VENDOR=(.+)/)?.[1] || "";
256604
- const model = udev.match(/ID_MODEL=(.+)/)?.[1] || "";
256605
- const serial = udev.match(/ID_SERIAL_SHORT=(.+)/)?.[1] || "";
256606
- const isGps = GPS_USB_IDS.some((g) => udev.toLowerCase().includes(g.vid)) || /gps|gnss|prolific|cp210x|u-blox|ublox|sirf/i.test(udev);
256607
- if (isGps) {
256608
- 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)`);
256609
256743
  }
256610
- } catch {
256611
256744
  }
256612
- }
256613
- let gpsdRunning = false;
256614
- try {
256615
- execSync36("pgrep gpsd", { timeout: 3e3, stdio: "pipe" });
256616
- gpsdRunning = true;
256617
- devices.push(" Service: gpsd is running");
256618
256745
  } catch {
256619
256746
  }
256620
- if (devices.length === 0) {
256621
- return {
256622
- success: true,
256623
- output: "No GPS devices detected. Connect a USB GPS receiver (BU-353N, U-blox 7, etc.)." + (serialDevs.length > 0 ? `
256624
-
256625
- Serial devices found but not identified as GPS: ${serialDevs.join(", ")}` : ""),
256626
- durationMs: performance.now() - start2
256627
- };
256628
- }
256629
256747
  return {
256630
256748
  success: true,
256631
- output: `GPS devices found:
256632
- ${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.",
256633
256751
  durationMs: performance.now() - start2
256634
256752
  };
256635
256753
  }
@@ -256675,42 +256793,150 @@ Raw: ${JSON.stringify(fix)}`,
256675
256793
  } catch {
256676
256794
  }
256677
256795
  }
256678
- return this.getFixFromNmea(args, start2);
256796
+ return this.getFixPyserial(args, start2);
256679
256797
  }
256680
- /** Parse GPS fix directly from NMEA on serial port */
256681
- getFixFromNmea(args, start2) {
256682
- const device = args["device"] || this.findGpsSerial();
256683
- if (!device) {
256684
- return { success: false, output: "", error: "No GPS device found. Connect a USB GPS receiver.", durationMs: performance.now() - start2 };
256685
- }
256798
+ /** Get GPS fix using pyserial+pynmea2 proven stack from gps_service/server.py */
256799
+ async getFixPyserial(args, start2) {
256800
+ const device = args["device"] || "";
256686
256801
  const timeout2 = args["timeout"] || 30;
256687
- const baud = this.detectBaud(device);
256688
256802
  try {
256689
- execSync36(`stty -F ${device} ${baud} raw -echo -echoe -echok 2>/dev/null`, { timeout: 5e3, stdio: "pipe" });
256690
- const raw = execSync36(`timeout ${timeout2} cat ${device}`, { encoding: "utf8", timeout: (timeout2 + 5) * 1e3 });
256691
- const gga = raw.split("\n").find((l2) => l2.includes("$GPGGA") || l2.includes("$GNGGA"));
256692
- const rmc = raw.split("\n").find((l2) => l2.includes("$GPRMC") || l2.includes("$GNRMC"));
256693
- if (!gga && !rmc) {
256694
- 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 };
256695
- }
256696
- const fix = this.parseGGA(gga) || {};
256697
- 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
+ }
256698
256926
  return {
256699
256927
  success: true,
256700
- output: `GPS Fix (NMEA from ${device} @ ${baud} baud):
256701
- Position: ${fix.lat ?? "no fix"}, ${fix.lon ?? "no fix"}
256702
- Altitude: ${fix.alt ?? "unknown"}m
256703
- Satellites: ${fix.sats ?? "unknown"}
256704
- Fix quality: ${fix.quality ?? "unknown"}
256705
- Speed: ${rmcData.speed ?? "unknown"} knots
256706
- Time (UTC): ${fix.time ?? rmcData.time ?? "unknown"}
256707
-
256708
- Raw GGA: ${gga || "none"}
256709
- 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}`,
256710
256936
  durationMs: performance.now() - start2
256711
256937
  };
256712
256938
  } catch (err) {
256713
- 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 };
256714
256940
  }
256715
256941
  }
256716
256942
  // =========================================================================
@@ -256899,16 +257125,24 @@ ${content.slice(0, 500)}`,
256899
257125
  "/dev/ttyACM1",
256900
257126
  "/dev/ttyACM2"
256901
257127
  ];
257128
+ const GPS_VENDOR_IDS = /* @__PURE__ */ new Set(["1546", "091e", "1163", "0df7", "16d0", "2c7c", "152a"]);
257129
+ const UART_BRIDGE_VIDS = /* @__PURE__ */ new Set(["067b", "10c4", "0403", "1a86"]);
256902
257130
  for (const dev of candidates) {
256903
257131
  if (!existsSync34(dev))
256904
257132
  continue;
256905
257133
  try {
256906
257134
  const udev = execSync36(`udevadm info --query=all --name=${dev} 2>/dev/null`, { encoding: "utf8", timeout: 3e3 });
257135
+ const vidMatch = udev.match(/ID_VENDOR_ID=([0-9a-f]+)/i);
257136
+ const vid = vidMatch?.[1]?.toLowerCase() || "";
257137
+ if (vid && GPS_VENDOR_IDS.has(vid))
257138
+ return dev;
256907
257139
  for (const gps of GPS_USB_IDS) {
256908
257140
  if (udev.toLowerCase().includes(gps.vid) && udev.toLowerCase().includes(gps.pid))
256909
257141
  return dev;
256910
257142
  }
256911
- if (/gps|gnss|sirf|ublox|u-blox|globalsat|garmin|trimble|quectel|septentrio/i.test(udev))
257143
+ if (vid && UART_BRIDGE_VIDS.has(vid) && dev.includes("ttyUSB"))
257144
+ return dev;
257145
+ if (/gps|gnss|sirf|ublox|u-blox|globalsat|garmin|trimble|quectel|septentrio|bu-353|bu-636|navsat/i.test(udev))
256912
257146
  return dev;
256913
257147
  } catch {
256914
257148
  }
@@ -258238,10 +258472,10 @@ var init_client3 = __esm({
258238
258472
  // packages/execution/dist/mcp/manager.js
258239
258473
  import { existsSync as existsSync36, readFileSync as readFileSync26 } from "node:fs";
258240
258474
  import { join as join50 } from "node:path";
258241
- import { homedir as homedir13 } from "node:os";
258475
+ import { homedir as homedir14 } from "node:os";
258242
258476
  function loadMcpConfig(repoRoot) {
258243
258477
  const servers = {};
258244
- const globalPath = join50(homedir13(), ".open-agents", "mcp.json");
258478
+ const globalPath = join50(homedir14(), ".open-agents", "mcp.json");
258245
258479
  if (existsSync36(globalPath)) {
258246
258480
  try {
258247
258481
  const global2 = JSON.parse(readFileSync26(globalPath, "utf8"));
@@ -258545,10 +258779,10 @@ var init_mcp = __esm({
258545
258779
  // packages/execution/dist/plugins/plugin-system.js
258546
258780
  import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync27 } from "node:fs";
258547
258781
  import { join as join51 } from "node:path";
258548
- import { homedir as homedir14 } from "node:os";
258782
+ import { homedir as homedir15 } from "node:os";
258549
258783
  function discoverPlugins(repoRoot) {
258550
258784
  const plugins = [];
258551
- const globalDir = join51(homedir14(), ".open-agents", "plugins");
258785
+ const globalDir = join51(homedir15(), ".open-agents", "plugins");
258552
258786
  if (existsSync37(globalDir)) {
258553
258787
  plugins.push(...loadPluginsFromDir(globalDir));
258554
258788
  }
@@ -259975,10 +260209,10 @@ var init_buildRunner = __esm({
259975
260209
  // packages/execution/dist/constraints.js
259976
260210
  import { existsSync as existsSync42, readFileSync as readFileSync32, writeFileSync as writeFileSync17, mkdirSync as mkdirSync18 } from "node:fs";
259977
260211
  import { join as join55 } from "node:path";
259978
- import { homedir as homedir15 } from "node:os";
260212
+ import { homedir as homedir16 } from "node:os";
259979
260213
  function loadConstraints(projectRoot) {
259980
260214
  projectConstraints = loadFile(join55(projectRoot, ".oa", "constraints.json"));
259981
- globalConstraints = loadFile(join55(homedir15(), ".open-agents", "constraints.json"));
260215
+ globalConstraints = loadFile(join55(homedir16(), ".open-agents", "constraints.json"));
259982
260216
  }
259983
260217
  function loadFile(path5) {
259984
260218
  try {
@@ -269995,7 +270229,7 @@ __export(listen_exports, {
269995
270229
  import { spawn as spawn17, execSync as execSync41 } from "node:child_process";
269996
270230
  import { existsSync as existsSync45, mkdirSync as mkdirSync19, writeFileSync as writeFileSync19, readdirSync as readdirSync9 } from "node:fs";
269997
270231
  import { join as join60, dirname as dirname16 } from "node:path";
269998
- import { homedir as homedir16 } from "node:os";
270232
+ import { homedir as homedir17 } from "node:os";
269999
270233
  import { fileURLToPath as fileURLToPath9 } from "node:url";
270000
270234
  import { EventEmitter as EventEmitter3 } from "node:events";
270001
270235
  import { createInterface as createInterface2 } from "node:readline";
@@ -270105,7 +270339,7 @@ function findLiveWhisperScript() {
270105
270339
  }
270106
270340
  } catch {
270107
270341
  }
270108
- const nvmBase = join60(homedir16(), ".nvm", "versions", "node");
270342
+ const nvmBase = join60(homedir17(), ".nvm", "versions", "node");
270109
270343
  if (existsSync45(nvmBase)) {
270110
270344
  try {
270111
270345
  for (const ver of readdirSync9(nvmBase)) {
@@ -270353,7 +270587,7 @@ var init_listen = __esm({
270353
270587
  }
270354
270588
  } catch {
270355
270589
  }
270356
- const nvmBase = join60(homedir16(), ".nvm", "versions", "node");
270590
+ const nvmBase = join60(homedir17(), ".nvm", "versions", "node");
270357
270591
  if (existsSync45(nvmBase)) {
270358
270592
  try {
270359
270593
  const { readdirSync: readdirSync26 } = await import("node:fs");
@@ -280179,7 +280413,7 @@ __export(oa_directory_exports, {
280179
280413
  });
280180
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";
280181
280415
  import { join as join65, relative as relative4, basename as basename12 } from "node:path";
280182
- import { homedir as homedir17 } from "node:os";
280416
+ import { homedir as homedir18 } from "node:os";
280183
280417
  function initOaDirectory(repoRoot) {
280184
280418
  const oaPath = join65(repoRoot, OA_DIR);
280185
280419
  for (const sub of SUBDIRS) {
@@ -280219,7 +280453,7 @@ function saveProjectSettings(repoRoot, settings) {
280219
280453
  writeFileSync22(join65(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
280220
280454
  }
280221
280455
  function loadGlobalSettings() {
280222
- const settingsPath = join65(homedir17(), ".open-agents", "settings.json");
280456
+ const settingsPath = join65(homedir18(), ".open-agents", "settings.json");
280223
280457
  try {
280224
280458
  if (existsSync49(settingsPath)) {
280225
280459
  return JSON.parse(readFileSync37(settingsPath, "utf-8"));
@@ -280229,7 +280463,7 @@ function loadGlobalSettings() {
280229
280463
  return {};
280230
280464
  }
280231
280465
  function saveGlobalSettings(settings) {
280232
- const dir = join65(homedir17(), ".open-agents");
280466
+ const dir = join65(homedir18(), ".open-agents");
280233
280467
  mkdirSync22(dir, { recursive: true });
280234
280468
  const existing = loadGlobalSettings();
280235
280469
  const merged = { ...existing, ...settings };
@@ -280727,13 +280961,13 @@ function recordUsage(kind, value2, opts) {
280727
280961
  }
280728
280962
  saveUsageFile(filePath, data);
280729
280963
  };
280730
- update2(join65(homedir17(), ".open-agents", USAGE_HISTORY_FILE));
280964
+ update2(join65(homedir18(), ".open-agents", USAGE_HISTORY_FILE));
280731
280965
  if (opts?.repoRoot) {
280732
280966
  update2(join65(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
280733
280967
  }
280734
280968
  }
280735
280969
  function loadUsageHistory(kind, repoRoot) {
280736
- const globalPath = join65(homedir17(), ".open-agents", USAGE_HISTORY_FILE);
280970
+ const globalPath = join65(homedir18(), ".open-agents", USAGE_HISTORY_FILE);
280737
280971
  const globalData = loadUsageFile(globalPath);
280738
280972
  const localData = repoRoot ? loadUsageFile(join65(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
280739
280973
  const map2 = /* @__PURE__ */ new Map();
@@ -280764,7 +280998,7 @@ function deleteUsageRecord(kind, value2, repoRoot) {
280764
280998
  saveUsageFile(filePath, data);
280765
280999
  }
280766
281000
  };
280767
- remove(join65(homedir17(), ".open-agents", USAGE_HISTORY_FILE));
281001
+ remove(join65(homedir18(), ".open-agents", USAGE_HISTORY_FILE));
280768
281002
  if (repoRoot) {
280769
281003
  remove(join65(repoRoot, OA_DIR, USAGE_HISTORY_FILE));
280770
281004
  }
@@ -285320,7 +285554,7 @@ __export(personaplex_exports, {
285320
285554
  });
285321
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";
285322
285556
  import { join as join66, dirname as dirname20 } from "node:path";
285323
- import { homedir as homedir18 } from "node:os";
285557
+ import { homedir as homedir19 } from "node:os";
285324
285558
  import { execSync as execSync44, spawn as spawn20 } from "node:child_process";
285325
285559
  import { fileURLToPath as fileURLToPath12 } from "node:url";
285326
285560
  function execAsync(cmd, opts = {}) {
@@ -285915,7 +286149,7 @@ print('Converted')
285915
286149
  let ollamaModel = process.env["HYBRID_LLM_MODEL"] || "";
285916
286150
  if (!ollamaModel) {
285917
286151
  try {
285918
- 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"));
285919
286153
  if (oaConfig.model) ollamaModel = oaConfig.model;
285920
286154
  } catch {
285921
286155
  }
@@ -286186,7 +286420,7 @@ function provisionShippedVoices(onInfo) {
286186
286420
  return deployed;
286187
286421
  }
286188
286422
  function getHFVoicesDir() {
286189
- 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");
286190
286424
  if (!existsSync50(hfBase)) return null;
286191
286425
  try {
286192
286426
  const snapshots = join66(hfBase, "snapshots");
@@ -286202,7 +286436,7 @@ function getHFVoicesDir() {
286202
286436
  function patchFrontendVoiceList(onInfo) {
286203
286437
  const log22 = onInfo ?? (() => {
286204
286438
  });
286205
- 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");
286206
286440
  if (!existsSync50(hfBase)) return;
286207
286441
  try {
286208
286442
  const snapshots = join66(hfBase, "snapshots");
@@ -286280,7 +286514,7 @@ var init_personaplex = __esm({
286280
286514
  nf4: { repo: "cudabenchmarktest/personaplex-7b-nf4", file: "model-nf4.safetensors", sizeGB: 4.1, needsToken: false },
286281
286515
  "nf4-distilled": { repo: "cudabenchmarktest/personaplex-7b-nf4-distilled", file: "student_best.pt", sizeGB: 16.7, needsToken: false }
286282
286516
  };
286283
- PERSONAPLEX_DIR = join66(homedir18(), ".open-agents", "voice", "personaplex");
286517
+ PERSONAPLEX_DIR = join66(homedir19(), ".open-agents", "voice", "personaplex");
286284
286518
  PID_FILE = join66(PERSONAPLEX_DIR, "daemon.pid");
286285
286519
  PORT_FILE = join66(PERSONAPLEX_DIR, "daemon.port");
286286
286520
  LOG_FILE = join66(PERSONAPLEX_DIR, "daemon.log");
@@ -286327,7 +286561,7 @@ import { execSync as execSync45, spawn as spawn21, exec as exec4 } from "node:ch
286327
286561
  import { promisify as promisify7 } from "node:util";
286328
286562
  import { existsSync as existsSync51, writeFileSync as writeFileSync24, readFileSync as readFileSync40, appendFileSync as appendFileSync2, mkdirSync as mkdirSync24 } from "node:fs";
286329
286563
  import { join as join67 } from "node:path";
286330
- import { homedir as homedir19, platform as platform3 } from "node:os";
286564
+ import { homedir as homedir20, platform as platform3 } from "node:os";
286331
286565
  async function checkToolSupport(modelName, backendUrl = "http://localhost:11434") {
286332
286566
  if (_toolSupportCache.has(modelName)) return _toolSupportCache.get(modelName);
286333
286567
  try {
@@ -287426,7 +287660,7 @@ async function doSetup(config, rl) {
287426
287660
  `PARAMETER num_predict ${numPredict}`,
287427
287661
  `PARAMETER stop "<|endoftext|>"`
287428
287662
  ].join("\n");
287429
- const modelDir2 = join67(homedir19(), ".open-agents", "models");
287663
+ const modelDir2 = join67(homedir20(), ".open-agents", "models");
287430
287664
  mkdirSync24(modelDir2, { recursive: true });
287431
287665
  const modelfilePath = join67(modelDir2, `Modelfile.${customName}`);
287432
287666
  writeFileSync24(modelfilePath, modelfileContent + "\n", "utf8");
@@ -287474,7 +287708,7 @@ async function isModelAvailable(config) {
287474
287708
  }
287475
287709
  function isFirstRun() {
287476
287710
  try {
287477
- return !existsSync51(join67(homedir19(), ".open-agents", "config.json"));
287711
+ return !existsSync51(join67(homedir20(), ".open-agents", "config.json"));
287478
287712
  } catch {
287479
287713
  return true;
287480
287714
  }
@@ -287522,7 +287756,7 @@ function detectPkgManager() {
287522
287756
  return null;
287523
287757
  }
287524
287758
  function getVenvDir() {
287525
- return join67(homedir19(), ".open-agents", "venv");
287759
+ return join67(homedir20(), ".open-agents", "venv");
287526
287760
  }
287527
287761
  function hasVenvModule() {
287528
287762
  try {
@@ -287548,7 +287782,7 @@ function ensureVenv(log22) {
287548
287782
  return null;
287549
287783
  }
287550
287784
  try {
287551
- mkdirSync24(join67(homedir19(), ".open-agents"), { recursive: true });
287785
+ mkdirSync24(join67(homedir20(), ".open-agents"), { recursive: true });
287552
287786
  const pyCmd = hasCmd(pythonCmd) ? pythonCmd : "python3";
287553
287787
  execSync45(`${pyCmd} -m venv "${venvDir}"`, { stdio: "pipe", timeout: 3e4 });
287554
287788
  execSync45(`"${pipPath}" install --upgrade pip`, {
@@ -287648,7 +287882,7 @@ async function ensureVisionDeps(onInfo, getSudoPassword) {
287648
287882
  ];
287649
287883
  {
287650
287884
  const pm2 = detectPkgManager();
287651
- const _visionMarkerDir = join67(homedir19(), ".open-agents");
287885
+ const _visionMarkerDir = join67(homedir20(), ".open-agents");
287652
287886
  const _visionMarkerFile = join67(_visionMarkerDir, "vision-deps-installed.json");
287653
287887
  let _visionPreviouslyInstalled = /* @__PURE__ */ new Set();
287654
287888
  try {
@@ -287901,11 +288135,11 @@ function ensureCloudflaredBackground(onInfo) {
287901
288135
  const cfArch = archMap[arch2] ?? "amd64";
287902
288136
  try {
287903
288137
  execSync45(
287904
- `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"`,
287905
288139
  { stdio: "pipe", timeout: 6e4 }
287906
288140
  );
287907
- if (!process.env.PATH?.includes(`${homedir19()}/.local/bin`)) {
287908
- 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}`;
287909
288143
  }
287910
288144
  if (hasCmd("cloudflared")) {
287911
288145
  log22("cloudflared installed.");
@@ -288002,7 +288236,7 @@ function createExpandedVariant(baseModel, specs, sizeGB, kvBytesPerToken, archMa
288002
288236
  `PARAMETER num_predict ${numPredict}`,
288003
288237
  `PARAMETER stop "<|endoftext|>"`
288004
288238
  ].join("\n");
288005
- const modelDir2 = join67(homedir19(), ".open-agents", "models");
288239
+ const modelDir2 = join67(homedir20(), ".open-agents", "models");
288006
288240
  mkdirSync24(modelDir2, { recursive: true });
288007
288241
  const modelfilePath = join67(modelDir2, `Modelfile.${customName}`);
288008
288242
  writeFileSync24(modelfilePath, modelfileContent + "\n", "utf8");
@@ -288027,7 +288261,7 @@ async function createExpandedVariantAsync(baseModel, specs, sizeGB, kvBytesPerTo
288027
288261
  `PARAMETER num_predict ${numPredict}`,
288028
288262
  `PARAMETER stop "<|endoftext|>"`
288029
288263
  ].join("\n");
288030
- const modelDir2 = join67(homedir19(), ".open-agents", "models");
288264
+ const modelDir2 = join67(homedir20(), ".open-agents", "models");
288031
288265
  mkdirSync24(modelDir2, { recursive: true });
288032
288266
  const modelfilePath = join67(modelDir2, `Modelfile.${customName}`);
288033
288267
  writeFileSync24(modelfilePath, modelfileContent + "\n", "utf8");
@@ -288103,7 +288337,7 @@ async function ensureNeovim() {
288103
288337
  const platform6 = process.platform;
288104
288338
  const arch2 = process.arch;
288105
288339
  if (platform6 === "linux") {
288106
- const binDir = join67(homedir19(), ".local", "bin");
288340
+ const binDir = join67(homedir20(), ".local", "bin");
288107
288341
  const nvimDest = join67(binDir, "nvim");
288108
288342
  try {
288109
288343
  mkdirSync24(binDir, { recursive: true });
@@ -288175,7 +288409,7 @@ async function ensureNeovim() {
288175
288409
  }
288176
288410
  function ensurePathInShellRc(binDir) {
288177
288411
  const shell = process.env.SHELL ?? "";
288178
- const rcFile = shell.includes("zsh") ? join67(homedir19(), ".zshrc") : join67(homedir19(), ".bashrc");
288412
+ const rcFile = shell.includes("zsh") ? join67(homedir20(), ".zshrc") : join67(homedir20(), ".bashrc");
288179
288413
  try {
288180
288414
  const rcContent = existsSync51(rcFile) ? readFileSync40(rcFile, "utf8") : "";
288181
288415
  if (rcContent.includes(binDir)) return;
@@ -288918,7 +289152,7 @@ __export(daemon_exports, {
288918
289152
  import { spawn as spawn22 } from "node:child_process";
288919
289153
  import { existsSync as existsSync54, readFileSync as readFileSync41, writeFileSync as writeFileSync25, mkdirSync as mkdirSync25, unlinkSync as unlinkSync13 } from "node:fs";
288920
289154
  import { join as join69 } from "node:path";
288921
- import { homedir as homedir20 } from "node:os";
289155
+ import { homedir as homedir21 } from "node:os";
288922
289156
  import { fileURLToPath as fileURLToPath13 } from "node:url";
288923
289157
  import { dirname as dirname21 } from "node:path";
288924
289158
  function getDaemonPort() {
@@ -289069,7 +289303,7 @@ var OA_DIR2, PID_FILE2, DEFAULT_PORT2;
289069
289303
  var init_daemon = __esm({
289070
289304
  "packages/cli/src/daemon.ts"() {
289071
289305
  "use strict";
289072
- OA_DIR2 = join69(homedir20(), ".open-agents");
289306
+ OA_DIR2 = join69(homedir21(), ".open-agents");
289073
289307
  PID_FILE2 = join69(OA_DIR2, "daemon.pid");
289074
289308
  DEFAULT_PORT2 = 11435;
289075
289309
  }
@@ -290369,7 +290603,7 @@ __export(voice_exports, {
290369
290603
  });
290370
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";
290371
290605
  import { join as join71, dirname as dirname22 } from "node:path";
290372
- 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";
290373
290607
  import { execSync as execSync47, spawn as nodeSpawn } from "node:child_process";
290374
290608
  import { createRequire as createRequire2 } from "node:module";
290375
290609
  function sanitizeForTTS(text) {
@@ -290393,7 +290627,7 @@ function listVoiceModels() {
290393
290627
  }));
290394
290628
  }
290395
290629
  function voiceDir() {
290396
- return join71(homedir21(), ".open-agents", "voice");
290630
+ return join71(homedir22(), ".open-agents", "voice");
290397
290631
  }
290398
290632
  function modelsDir() {
290399
290633
  return join71(voiceDir(), "models");
@@ -291325,7 +291559,7 @@ var init_voice = __esm({
291325
291559
  }
291326
291560
  p2 = p2.replace(/\\ /g, " ");
291327
291561
  if (p2.startsWith("~/") || p2 === "~") {
291328
- p2 = join71(homedir21(), p2.slice(1));
291562
+ p2 = join71(homedir22(), p2.slice(1));
291329
291563
  }
291330
291564
  if (!existsSync56(p2)) {
291331
291565
  return `File not found: ${p2}
@@ -293675,9 +293909,9 @@ async function handleSlashCommand(input, ctx3) {
293675
293909
  renderInfo("No wallet configured. Ask the agent to create one via the nexus tool.");
293676
293910
  }
293677
293911
  } else if (sub === "name") {
293678
- const { homedir: homedir28 } = __require("node:os");
293912
+ const { homedir: homedir29 } = __require("node:os");
293679
293913
  const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
293680
- const namePath = __require("node:path").join(homedir28(), ".open-agents", "agent-name");
293914
+ const namePath = __require("node:path").join(homedir29(), ".open-agents", "agent-name");
293681
293915
  if (rest2) {
293682
293916
  const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
293683
293917
  if (!customName) {
@@ -295376,8 +295610,8 @@ The session corrections MUST become hard rules in the SKILL.md Rules section.`;
295376
295610
  let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
295377
295611
  if (!sponsorName || sponsorName.length < 2) {
295378
295612
  try {
295379
- const { homedir: homedir28 } = __require("os");
295380
- const namePath = __require("path").join(homedir28(), ".open-agents", "agent-name");
295613
+ const { homedir: homedir29 } = __require("os");
295614
+ const namePath = __require("path").join(homedir29(), ".open-agents", "agent-name");
295381
295615
  if (existsSync57(namePath)) sponsorName = readFileSync44(namePath, "utf8").trim();
295382
295616
  } catch {
295383
295617
  }
@@ -296837,9 +297071,9 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
296837
297071
  }
296838
297072
  const { basename: basename19, join: pathJoin } = await import("node:path");
296839
297073
  const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync43, existsSync: exists2 } = await import("node:fs");
296840
- const { homedir: homedir28 } = await import("node:os");
297074
+ const { homedir: homedir29 } = await import("node:os");
296841
297075
  const modelName = basename19(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
296842
- const destDir = pathJoin(homedir28(), ".open-agents", "voice", "models", modelName);
297076
+ const destDir = pathJoin(homedir29(), ".open-agents", "voice", "models", modelName);
296843
297077
  if (!exists2(destDir)) mkdirSync43(destDir, { recursive: true });
296844
297078
  copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
296845
297079
  copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
@@ -299061,7 +299295,7 @@ var init_commands = __esm({
299061
299295
  import { existsSync as existsSync58, readFileSync as readFileSync45, readdirSync as readdirSync15 } from "node:fs";
299062
299296
  import { join as join73, basename as basename13 } from "node:path";
299063
299297
  import { execSync as execSync48 } from "node:child_process";
299064
- import { homedir as homedir23, platform as platform5, release } from "node:os";
299298
+ import { homedir as homedir24, platform as platform5, release } from "node:os";
299065
299299
  function getModelTier(modelName) {
299066
299300
  const m2 = modelName.toLowerCase();
299067
299301
  const sizeMatch = m2.match(/\b(\d+)b\b/);
@@ -299140,7 +299374,7 @@ function loadMemoryContext(repoRoot) {
299140
299374
  const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
299141
299375
  if (legacyEntries) sections.push(legacyEntries);
299142
299376
  }
299143
- const globalMemDir = join73(homedir23(), ".open-agents", "memory");
299377
+ const globalMemDir = join73(homedir24(), ".open-agents", "memory");
299144
299378
  const globalEntries = loadMemoryDir(globalMemDir, "global");
299145
299379
  if (globalEntries) sections.push(globalEntries);
299146
299380
  return sections.join("\n\n");
@@ -308431,10 +308665,10 @@ var init_usage_tracker = __esm({
308431
308665
  // packages/cli/src/api/profiles.ts
308432
308666
  import { existsSync as existsSync69, readFileSync as readFileSync55, writeFileSync as writeFileSync34, mkdirSync as mkdirSync37, readdirSync as readdirSync22, unlinkSync as unlinkSync17 } from "node:fs";
308433
308667
  import { join as join85 } from "node:path";
308434
- import { homedir as homedir24 } from "node:os";
308668
+ import { homedir as homedir25 } from "node:os";
308435
308669
  import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync3 } from "node:crypto";
308436
308670
  function globalProfileDir() {
308437
- return join85(homedir24(), ".open-agents", "profiles");
308671
+ return join85(homedir25(), ".open-agents", "profiles");
308438
308672
  }
308439
308673
  function projectProfileDir(projectDir) {
308440
308674
  return join85(projectDir || process.cwd(), ".oa", "profiles");
@@ -308626,7 +308860,7 @@ var init_profiles = __esm({
308626
308860
  import { execSync as execSync50, spawn as spawn23 } from "node:child_process";
308627
308861
  import { existsSync as existsSync70, mkdirSync as mkdirSync38, writeFileSync as writeFileSync35 } from "node:fs";
308628
308862
  import { join as join86, resolve as resolve33, dirname as dirname24 } from "node:path";
308629
- import { homedir as homedir25 } from "node:os";
308863
+ import { homedir as homedir26 } from "node:os";
308630
308864
  import { fileURLToPath as fileURLToPath15 } from "node:url";
308631
308865
  function getDockerDir() {
308632
308866
  try {
@@ -308774,7 +309008,7 @@ async function ensureOaImage(force = false) {
308774
309008
  if (existsSync70(join86(dockerDir, "Dockerfile"))) {
308775
309009
  buildContext = dockerDir;
308776
309010
  } else {
308777
- buildContext = join86(homedir25(), ".oa", "docker-build");
309011
+ buildContext = join86(homedir26(), ".oa", "docker-build");
308778
309012
  mkdirSync38(buildContext, { recursive: true });
308779
309013
  writeDockerfiles(buildContext);
308780
309014
  }
@@ -310847,7 +311081,7 @@ import { fileURLToPath as fileURLToPath17 } from "node:url";
310847
311081
  import { readFileSync as readFileSync57, writeFileSync as writeFileSync37, appendFileSync as appendFileSync6, rmSync as rmSync4, readdirSync as readdirSync24, mkdirSync as mkdirSync40 } from "node:fs";
310848
311082
  import { existsSync as existsSync72 } from "node:fs";
310849
311083
  import { execSync as execSync52 } from "node:child_process";
310850
- import { homedir as homedir26 } from "node:os";
311084
+ import { homedir as homedir27 } from "node:os";
310851
311085
  function formatTimeAgo(date) {
310852
311086
  const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
310853
311087
  if (seconds < 60) return "just now";
@@ -313409,7 +313643,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
313409
313643
  const hits = allCompletions.filter((c7) => c7.toLowerCase().startsWith(lower));
313410
313644
  return [hits, line];
313411
313645
  }
313412
- const HISTORY_DIR = join88(homedir26(), ".open-agents");
313646
+ const HISTORY_DIR = join88(homedir27(), ".open-agents");
313413
313647
  const HISTORY_FILE = join88(HISTORY_DIR, "repl-history");
313414
313648
  const MAX_HISTORY_LINES = 500;
313415
313649
  let savedHistory = [];
@@ -315195,7 +315429,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
315195
315429
  } catch {
315196
315430
  }
315197
315431
  try {
315198
- const voiceDir2 = join88(homedir26(), ".open-agents", "voice");
315432
+ const voiceDir2 = join88(homedir27(), ".open-agents", "voice");
315199
315433
  const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
315200
315434
  for (const pf of voicePidFiles) {
315201
315435
  const pidPath = join88(voiceDir2, pf);
@@ -315308,8 +315542,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
315308
315542
  try {
315309
315543
  const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
315310
315544
  if (isPersonaPlexRunning2()) {
315311
- const ppPidFile = join88(homedir26(), ".open-agents", "voice", "personaplex", "daemon.pid");
315312
- const ppPortFile = join88(homedir26(), ".open-agents", "voice", "personaplex", "daemon.port");
315545
+ const ppPidFile = join88(homedir27(), ".open-agents", "voice", "personaplex", "daemon.pid");
315546
+ const ppPortFile = join88(homedir27(), ".open-agents", "voice", "personaplex", "daemon.port");
315313
315547
  if (existsSync72(ppPidFile)) {
315314
315548
  const ppPid = parseInt(readFileSync57(ppPidFile, "utf8").trim(), 10);
315315
315549
  const ppPort = existsSync72(ppPortFile) ? parseInt(readFileSync57(ppPortFile, "utf8").trim(), 10) : void 0;
@@ -317229,7 +317463,7 @@ __export(config_exports2, {
317229
317463
  configCommand: () => configCommand
317230
317464
  });
317231
317465
  import { join as join91, resolve as resolve38 } from "node:path";
317232
- import { homedir as homedir27 } from "node:os";
317466
+ import { homedir as homedir28 } from "node:os";
317233
317467
  import { cwd as cwd3 } from "node:process";
317234
317468
  function redactIfSensitive(key, value2) {
317235
317469
  if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
@@ -317310,7 +317544,7 @@ function handleShow(opts, config) {
317310
317544
  }
317311
317545
  }
317312
317546
  printSection("Config File");
317313
- printInfo(`~/.open-agents/config.json (${join91(homedir27(), ".open-agents", "config.json")})`);
317547
+ printInfo(`~/.open-agents/config.json (${join91(homedir28(), ".open-agents", "config.json")})`);
317314
317548
  printSection("Priority Chain");
317315
317549
  printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
317316
317550
  printInfo(" 2. Project .oa/settings.json (--local)");
@@ -318115,8 +318349,8 @@ function crashLog(label, err) {
318115
318349
  try {
318116
318350
  const { appendFileSync: appendFileSync7, mkdirSync: mkdirSync43 } = __require("node:fs");
318117
318351
  const { join: join94 } = __require("node:path");
318118
- const { homedir: homedir28 } = __require("node:os");
318119
- const logDir = join94(homedir28(), ".open-agents");
318352
+ const { homedir: homedir29 } = __require("node:os");
318353
+ const logDir = join94(homedir29(), ".open-agents");
318120
318354
  mkdirSync43(logDir, { recursive: true });
318121
318355
  appendFileSync7(join94(logDir, "crash.log"), logLine);
318122
318356
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.148",
3
+ "version": "0.187.150",
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",