open-agents-ai 0.187.333 → 0.187.335

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 +236 -78
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -88532,7 +88532,7 @@ var require_auto = __commonJS({
88532
88532
  // ../node_modules/acme-client/src/client.js
88533
88533
  var require_client = __commonJS({
88534
88534
  "../node_modules/acme-client/src/client.js"(exports, module) {
88535
- var { createHash: createHash11 } = __require("crypto");
88535
+ var { createHash: createHash12 } = __require("crypto");
88536
88536
  var { getPemBodyAsB64u } = require_crypto();
88537
88537
  var { log: log22 } = require_logger();
88538
88538
  var HttpClient = require_http();
@@ -88843,14 +88843,14 @@ var require_client = __commonJS({
88843
88843
  */
88844
88844
  async getChallengeKeyAuthorization(challenge) {
88845
88845
  const jwk = this.http.getJwk();
88846
- const keysum = createHash11("sha256").update(JSON.stringify(jwk));
88846
+ const keysum = createHash12("sha256").update(JSON.stringify(jwk));
88847
88847
  const thumbprint = keysum.digest("base64url");
88848
88848
  const result = `${challenge.token}.${thumbprint}`;
88849
88849
  if (challenge.type === "http-01") {
88850
88850
  return result;
88851
88851
  }
88852
88852
  if (challenge.type === "dns-01") {
88853
- return createHash11("sha256").update(result).digest("base64url");
88853
+ return createHash12("sha256").update(result).digest("base64url");
88854
88854
  }
88855
88855
  if (challenge.type === "tls-alpn-01") {
88856
88856
  return result;
@@ -231530,7 +231530,7 @@ var require_websocket2 = __commonJS({
231530
231530
  var http6 = __require("http");
231531
231531
  var net5 = __require("net");
231532
231532
  var tls2 = __require("tls");
231533
- var { randomBytes: randomBytes23, createHash: createHash11 } = __require("crypto");
231533
+ var { randomBytes: randomBytes23, createHash: createHash12 } = __require("crypto");
231534
231534
  var { Duplex: Duplex3, Readable } = __require("stream");
231535
231535
  var { URL: URL3 } = __require("url");
231536
231536
  var PerMessageDeflate2 = require_permessage_deflate2();
@@ -232190,7 +232190,7 @@ var require_websocket2 = __commonJS({
232190
232190
  abortHandshake(websocket, socket, "Invalid Upgrade header");
232191
232191
  return;
232192
232192
  }
232193
- const digest3 = createHash11("sha1").update(key + GUID).digest("base64");
232193
+ const digest3 = createHash12("sha1").update(key + GUID).digest("base64");
232194
232194
  if (res.headers["sec-websocket-accept"] !== digest3) {
232195
232195
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
232196
232196
  return;
@@ -232557,7 +232557,7 @@ var require_websocket_server = __commonJS({
232557
232557
  var EventEmitter11 = __require("events");
232558
232558
  var http6 = __require("http");
232559
232559
  var { Duplex: Duplex3 } = __require("stream");
232560
- var { createHash: createHash11 } = __require("crypto");
232560
+ var { createHash: createHash12 } = __require("crypto");
232561
232561
  var extension2 = require_extension2();
232562
232562
  var PerMessageDeflate2 = require_permessage_deflate2();
232563
232563
  var subprotocol2 = require_subprotocol();
@@ -232858,7 +232858,7 @@ var require_websocket_server = __commonJS({
232858
232858
  );
232859
232859
  }
232860
232860
  if (this._state > RUNNING) return abortHandshake(socket, 503);
232861
- const digest3 = createHash11("sha1").update(key + GUID).digest("base64");
232861
+ const digest3 = createHash12("sha1").update(key + GUID).digest("base64");
232862
232862
  const headers = [
232863
232863
  "HTTP/1.1 101 Switching Protocols",
232864
232864
  "Upgrade: websocket",
@@ -245665,13 +245665,13 @@ Justification: ${justification || "(none provided)"}`,
245665
245665
  }
245666
245666
  const snapshot = JSON.stringify(this.selfState, null, 2);
245667
245667
  try {
245668
- const { createHash: createHash11 } = await import("node:crypto");
245668
+ const { createHash: createHash12 } = await import("node:crypto");
245669
245669
  const snapshotDir = join23(this.cwd, ".oa", "identity", "snapshots");
245670
245670
  await mkdir6(snapshotDir, { recursive: true });
245671
245671
  const version4 = this.selfState.version;
245672
245672
  const snapshotPath = join23(snapshotDir, `v${version4}.json`);
245673
245673
  await writeFile11(snapshotPath, snapshot, "utf8");
245674
- const hash = createHash11("sha256").update(snapshot).digest("hex");
245674
+ const hash = createHash12("sha256").update(snapshot).digest("hex");
245675
245675
  await writeFile11(join23(this.cwd, ".oa", "identity", "latest-hash.txt"), hash, "utf8");
245676
245676
  let ipfsCid = "";
245677
245677
  try {
@@ -245804,8 +245804,8 @@ New: ${newNarrative.slice(0, 200)}...`,
245804
245804
  }
245805
245805
  // ── Helpers ──────────────────────────────────────────────────────────────
245806
245806
  createDefaultState() {
245807
- const { createHash: createHash11 } = __require("node:crypto");
245808
- const machineId = createHash11("sha256").update(this.cwd).digest("hex").slice(0, 12);
245807
+ const { createHash: createHash12 } = __require("node:crypto");
245808
+ const machineId = createHash12("sha256").update(this.cwd).digest("hex").slice(0, 12);
245809
245809
  return {
245810
245810
  self_id: `oa-${machineId}`,
245811
245811
  version: 1,
@@ -245887,9 +245887,9 @@ New: ${newNarrative.slice(0, 200)}...`,
245887
245887
  let cid;
245888
245888
  if (this.selfState.version > prevVersion) {
245889
245889
  try {
245890
- const { createHash: createHash11 } = await import("node:crypto");
245890
+ const { createHash: createHash12 } = await import("node:crypto");
245891
245891
  const stateJson = JSON.stringify(this.selfState);
245892
- const hash = createHash11("sha256").update(stateJson).digest("hex").slice(0, 32);
245892
+ const hash = createHash12("sha256").update(stateJson).digest("hex").slice(0, 32);
245893
245893
  const cidsPath = join23(this.cwd, ".oa", "identity", "cids.json");
245894
245894
  const cidsData = { latest: "", hash, version: this.selfState.version };
245895
245895
  try {
@@ -251359,7 +251359,7 @@ import { execSync as execSync22, exec as execCb, spawnSync as spawnSync2 } from
251359
251359
  import { readFile as readFile15, writeFile as writeFile17, mkdir as mkdir12 } from "node:fs/promises";
251360
251360
  import { resolve as resolve24, join as join37 } from "node:path";
251361
251361
  import { homedir as homedir10 } from "node:os";
251362
- import { randomBytes as randomBytes10 } from "node:crypto";
251362
+ import { randomBytes as randomBytes10, createHash as createHash3 } from "node:crypto";
251363
251363
  function isValidCron(expr) {
251364
251364
  const parts = expr.trim().split(/\s+/);
251365
251365
  if (parts.length !== 5)
@@ -251449,7 +251449,25 @@ function findOaBinary() {
251449
251449
  }
251450
251450
  return "npx open-agents-ai";
251451
251451
  }
251452
+ function pruneCronForTask(workingDir, taskId) {
251453
+ const lines = getCurrentCrontab();
251454
+ const marker = `${CRON_MARKER}${taskId}`;
251455
+ const dirQuoted = `cd "${workingDir}"`;
251456
+ const dirSingle = `cd '${workingDir}'`;
251457
+ const filtered = lines.filter((l2) => {
251458
+ if (!l2.includes(CRON_MARKER))
251459
+ return true;
251460
+ if (l2.includes(marker))
251461
+ return false;
251462
+ if ((l2.includes(dirQuoted) || l2.includes(dirSingle)) && l2.includes(CRON_MARKER))
251463
+ return false;
251464
+ return true;
251465
+ });
251466
+ if (filtered.length !== lines.length)
251467
+ writeCrontab(filtered);
251468
+ }
251452
251469
  function installCronJob(task, workingDir) {
251470
+ pruneCronForTask(workingDir, task.id);
251453
251471
  const lines = getCurrentCrontab();
251454
251472
  const oaBin = findOaBinary();
251455
251473
  const logDir = resolve24(workingDir, ".oa", "scheduled", "logs");
@@ -251662,10 +251680,11 @@ var init_scheduler = __esm({
251662
251680
  durationMs: performance.now() - start2
251663
251681
  };
251664
251682
  }
251665
- const id = `sched-${randomBytes10(4).toString("hex")}`;
251683
+ const scope = String(args2["scope"] ?? "local");
251684
+ const fingerprint = `${resolve24(this.workingDir)}|${task}|${cronExpr}|${scope}`;
251685
+ const id = `sched-${createHash3("sha1").update(fingerprint).digest("hex").slice(0, 8)}`;
251666
251686
  const oneShot = Boolean(args2["one_shot"]);
251667
251687
  const maxRuns = typeof args2["max_runs"] === "number" ? args2["max_runs"] : void 0;
251668
- const scope = String(args2["scope"] ?? "local");
251669
251688
  const newTask = {
251670
251689
  id,
251671
251690
  task,
@@ -251681,18 +251700,36 @@ var init_scheduler = __esm({
251681
251700
  };
251682
251701
  if (scope === "global") {
251683
251702
  const store2 = await loadGlobalStore();
251684
- store2.tasks.push(newTask);
251685
- await saveGlobalStore(store2);
251703
+ const existing = store2.tasks.find((t2) => t2.id === id) || store2.tasks.find((t2) => t2.task === task && t2.schedule === cronExpr && (t2.projectDir || resolve24(this.workingDir)) === resolve24(this.workingDir));
251704
+ if (existing) {
251705
+ existing.task = task;
251706
+ existing.schedule = cronExpr;
251707
+ existing.nextRunDescription = describeCron(cronExpr);
251708
+ existing.enabled = true;
251709
+ await saveGlobalStore(store2);
251710
+ } else {
251711
+ store2.tasks.push(newTask);
251712
+ await saveGlobalStore(store2);
251713
+ }
251686
251714
  } else {
251687
251715
  const store2 = await loadStore(this.workingDir);
251688
- store2.tasks.push(newTask);
251689
- await saveStore(this.workingDir, store2);
251716
+ const existing = store2.tasks.find((t2) => t2.id === id) || store2.tasks.find((t2) => t2.task === task && t2.schedule === cronExpr);
251717
+ if (existing) {
251718
+ existing.task = task;
251719
+ existing.schedule = cronExpr;
251720
+ existing.nextRunDescription = describeCron(cronExpr);
251721
+ existing.enabled = true;
251722
+ await saveStore(this.workingDir, store2);
251723
+ } else {
251724
+ store2.tasks.push(newTask);
251725
+ await saveStore(this.workingDir, store2);
251726
+ }
251690
251727
  }
251691
251728
  installCronJob(newTask, this.workingDir);
251692
251729
  return {
251693
251730
  success: true,
251694
251731
  output: [
251695
- `Scheduled task created:`,
251732
+ `Scheduled task created (or updated):`,
251696
251733
  ` ID: ${id}`,
251697
251734
  ` Task: ${task}`,
251698
251735
  ` Schedule: ${describeCron(cronExpr)} (${cronExpr})`,
@@ -262373,7 +262410,7 @@ var init_environment_snapshot = __esm({
262373
262410
  import { execSync as execSync42 } from "node:child_process";
262374
262411
  import { existsSync as existsSync43, mkdirSync as mkdirSync22, writeFileSync as writeFileSync21, readFileSync as readFileSync34, readdirSync as readdirSync10, unlinkSync as unlinkSync11 } from "node:fs";
262375
262412
  import { join as join57, basename as basename11 } from "node:path";
262376
- import { createHash as createHash3 } from "node:crypto";
262413
+ import { createHash as createHash4 } from "node:crypto";
262377
262414
  function isYouTubeUrl2(url) {
262378
262415
  return /(?:youtube\.com\/(?:watch|shorts|live|embed|v\/)|youtu\.be\/)/i.test(url);
262379
262416
  }
@@ -262401,7 +262438,7 @@ function ensureFfmpeg() {
262401
262438
  function imageHash(imagePath) {
262402
262439
  try {
262403
262440
  const data = readFileSync34(imagePath);
262404
- return createHash3("md5").update(data).digest("hex").slice(0, 12);
262441
+ return createHash4("md5").update(data).digest("hex").slice(0, 12);
262405
262442
  } catch {
262406
262443
  return "unknown";
262407
262444
  }
@@ -267655,7 +267692,7 @@ var init_toolPatternStore = __esm({
267655
267692
  import { join as join64 } from "node:path";
267656
267693
  import { mkdirSync as mkdirSync25, existsSync as existsSync48 } from "node:fs";
267657
267694
  import { randomUUID as randomUUID7 } from "node:crypto";
267658
- import { createHash as createHash4 } from "node:crypto";
267695
+ import { createHash as createHash5 } from "node:crypto";
267659
267696
  function sanitizeImportance(raw, fallback = 5) {
267660
267697
  if (typeof raw !== "number" || !Number.isFinite(raw))
267661
267698
  return fallback;
@@ -267763,7 +267800,7 @@ var init_episodeStore = __esm({
267763
267800
  insert(ep) {
267764
267801
  const id = randomUUID7();
267765
267802
  const now = Date.now();
267766
- const contentHash = createHash4("sha256").update(ep.content).digest("hex").slice(0, 16);
267803
+ const contentHash = createHash5("sha256").update(ep.content).digest("hex").slice(0, 16);
267767
267804
  const modality = ep.modality ?? "text";
267768
267805
  const rawImportance = ep.importance ?? autoImportance(ep.toolName ?? null, modality, ep.content);
267769
267806
  const importance = sanitizeImportance(rawImportance);
@@ -278083,6 +278120,22 @@ function findLiveWhisperScript() {
278083
278120
  }
278084
278121
  return null;
278085
278122
  }
278123
+ function ensureVenvOnPath() {
278124
+ const bin = process.platform === "win32" ? "Scripts" : "bin";
278125
+ const venvBin = join69(homedir24(), ".open-agents", "venv", bin);
278126
+ if (!existsSync53(venvBin)) return false;
278127
+ const pathSep2 = process.platform === "win32" ? ";" : ":";
278128
+ const currentPath = process.env.PATH || "";
278129
+ if (!currentPath.split(pathSep2).includes(venvBin)) {
278130
+ process.env.PATH = `${venvBin}${pathSep2}${currentPath}`;
278131
+ }
278132
+ try {
278133
+ execSync44('python3 -c "import numpy"', { stdio: "pipe", timeout: 1e4 });
278134
+ return true;
278135
+ } catch {
278136
+ return false;
278137
+ }
278138
+ }
278086
278139
  function ensureTranscribeCliBackground() {
278087
278140
  if (_bgInstallPromise) return;
278088
278141
  _bgInstallPromise = (async () => {
@@ -278408,42 +278461,62 @@ var init_listen = __esm({
278408
278461
  if (tc) {
278409
278462
  const TranscribeLive = tc.TranscribeLive;
278410
278463
  if (TranscribeLive) {
278411
- try {
278412
- this.liveTranscriber = new TranscribeLive({
278413
- model: this.config.model,
278414
- sampleRate: 16e3,
278415
- channels: 1,
278416
- sampleWidth: 2,
278417
- chunkDuration: 3
278418
- });
278419
- this.liveTranscriber.on("transcript", (evt) => {
278420
- if (!evt.text.trim()) return;
278421
- this.lastTranscriptTime = Date.now();
278422
- this.pendingText = evt.text.trim();
278423
- this.emit("transcript", this.pendingText, evt.isFinal);
278424
- if (this.config.mode === "auto") this.resetSilenceTimer();
278425
- });
278426
- this.liveTranscriber.on("error", (err) => {
278427
- this.emit("error", err);
278428
- });
278429
- await new Promise((resolve40, reject) => {
278430
- const timeout2 = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
278431
- this.liveTranscriber.on("ready", () => {
278432
- clearTimeout(timeout2);
278433
- resolve40();
278464
+ const venvReady = ensureVenvOnPath();
278465
+ if (!venvReady) {
278466
+ transcribeCliError = "venv Python missing numpy (required by transcribe-cli) — using whisper fallback";
278467
+ } else {
278468
+ let caughtUncaught = null;
278469
+ const uncaughtHandler = (err) => {
278470
+ const msg = err?.message || String(err);
278471
+ if (msg.includes("live_worker") || msg.includes("numpy") || msg.includes("Traceback")) {
278472
+ caughtUncaught = err;
278473
+ } else {
278474
+ throw err;
278475
+ }
278476
+ };
278477
+ process.on("uncaughtException", uncaughtHandler);
278478
+ try {
278479
+ this.liveTranscriber = new TranscribeLive({
278480
+ model: this.config.model,
278481
+ sampleRate: 16e3,
278482
+ channels: 1,
278483
+ sampleWidth: 2,
278484
+ chunkDuration: 3
278485
+ });
278486
+ this.liveTranscriber.on("transcript", (evt) => {
278487
+ if (!evt.text.trim()) return;
278488
+ this.lastTranscriptTime = Date.now();
278489
+ this.pendingText = evt.text.trim();
278490
+ this.emit("transcript", this.pendingText, evt.isFinal);
278491
+ if (this.config.mode === "auto") this.resetSilenceTimer();
278434
278492
  });
278435
278493
  this.liveTranscriber.on("error", (err) => {
278436
- clearTimeout(timeout2);
278437
- reject(err);
278494
+ this.emit("error", err);
278438
278495
  });
278439
- });
278440
- } catch (err) {
278441
- try {
278442
- this.liveTranscriber?.stop();
278443
- } catch {
278496
+ await new Promise((resolve40, reject) => {
278497
+ const timeout2 = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
278498
+ this.liveTranscriber.on("ready", () => {
278499
+ clearTimeout(timeout2);
278500
+ resolve40();
278501
+ });
278502
+ this.liveTranscriber.on("error", (err) => {
278503
+ clearTimeout(timeout2);
278504
+ reject(err);
278505
+ });
278506
+ });
278507
+ if (caughtUncaught) {
278508
+ throw caughtUncaught;
278509
+ }
278510
+ } catch (err) {
278511
+ try {
278512
+ this.liveTranscriber?.stop();
278513
+ } catch {
278514
+ }
278515
+ this.liveTranscriber = null;
278516
+ transcribeCliError = err instanceof Error ? err.message : String(err);
278517
+ } finally {
278518
+ process.removeListener("uncaughtException", uncaughtHandler);
278444
278519
  }
278445
- this.liveTranscriber = null;
278446
- transcribeCliError = err instanceof Error ? err.message : String(err);
278447
278520
  }
278448
278521
  }
278449
278522
  }
@@ -278580,7 +278653,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
278580
278653
  } catch {
278581
278654
  }
278582
278655
  }
278583
- if (tc?.TranscribeLive) {
278656
+ if (tc?.TranscribeLive && ensureVenvOnPath()) {
278584
278657
  try {
278585
278658
  const transcriber = new tc.TranscribeLive({
278586
278659
  model: this.config.model,
@@ -278634,6 +278707,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
278634
278707
  }
278635
278708
  }
278636
278709
  if (!tc) return null;
278710
+ ensureVenvOnPath();
278637
278711
  try {
278638
278712
  const result = await tc.transcribe(filePath, {
278639
278713
  model: this.config.model,
@@ -280892,7 +280966,7 @@ var require_websocket3 = __commonJS({
280892
280966
  var http6 = __require("http");
280893
280967
  var net5 = __require("net");
280894
280968
  var tls2 = __require("tls");
280895
- var { randomBytes: randomBytes23, createHash: createHash11 } = __require("crypto");
280969
+ var { randomBytes: randomBytes23, createHash: createHash12 } = __require("crypto");
280896
280970
  var { Duplex: Duplex3, Readable } = __require("stream");
280897
280971
  var { URL: URL3 } = __require("url");
280898
280972
  var PerMessageDeflate2 = require_permessage_deflate3();
@@ -281552,7 +281626,7 @@ var require_websocket3 = __commonJS({
281552
281626
  abortHandshake(websocket, socket, "Invalid Upgrade header");
281553
281627
  return;
281554
281628
  }
281555
- const digest3 = createHash11("sha1").update(key + GUID).digest("base64");
281629
+ const digest3 = createHash12("sha1").update(key + GUID).digest("base64");
281556
281630
  if (res.headers["sec-websocket-accept"] !== digest3) {
281557
281631
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
281558
281632
  return;
@@ -281919,7 +281993,7 @@ var require_websocket_server2 = __commonJS({
281919
281993
  var EventEmitter11 = __require("events");
281920
281994
  var http6 = __require("http");
281921
281995
  var { Duplex: Duplex3 } = __require("stream");
281922
- var { createHash: createHash11 } = __require("crypto");
281996
+ var { createHash: createHash12 } = __require("crypto");
281923
281997
  var extension2 = require_extension3();
281924
281998
  var PerMessageDeflate2 = require_permessage_deflate3();
281925
281999
  var subprotocol2 = require_subprotocol2();
@@ -282220,7 +282294,7 @@ var require_websocket_server2 = __commonJS({
282220
282294
  );
282221
282295
  }
282222
282296
  if (this._state > RUNNING) return abortHandshake(socket, 503);
282223
- const digest3 = createHash11("sha1").update(key + GUID).digest("base64");
282297
+ const digest3 = createHash12("sha1").update(key + GUID).digest("base64");
282224
282298
  const headers = [
282225
282299
  "HTTP/1.1 101 Switching Protocols",
282226
282300
  "Upgrade: websocket",
@@ -297248,9 +297322,20 @@ async function runSudoScript(ctx3, script) {
297248
297322
  }
297249
297323
  try {
297250
297324
  const { spawn: spawn27 } = await import("node:child_process");
297251
- const full = `set -e; sudo -v; ${script}`;
297325
+ const full = `set -e; ${script}`;
297252
297326
  await new Promise((resolve40) => {
297253
- const child = spawn27("bash", ["-lc", full], { stdio: "inherit" });
297327
+ const usePkexec = process.platform === "linux";
297328
+ const cmd = usePkexec ? "pkexec" : "sudo";
297329
+ const args2 = usePkexec ? ["bash", "-lc", full] : ["-n", "bash", "-lc", full];
297330
+ const child = spawn27(cmd, args2, { stdio: ["ignore", "pipe", "pipe"] });
297331
+ let stdout = "";
297332
+ let stderr = "";
297333
+ child.stdout?.on("data", (data) => {
297334
+ stdout += data.toString();
297335
+ });
297336
+ child.stderr?.on("data", (data) => {
297337
+ stderr += data.toString();
297338
+ });
297254
297339
  child.on("exit", () => resolve40());
297255
297340
  child.on("error", () => resolve40());
297256
297341
  });
@@ -297267,6 +297352,75 @@ async function runSudoScript(ctx3, script) {
297267
297352
  } catch {
297268
297353
  }
297269
297354
  }
297355
+ async function ensureVoiceDeps(ctx3) {
297356
+ try {
297357
+ const mod2 = await Promise.resolve().then(() => (init_py_embed(), py_embed_exports));
297358
+ if (typeof mod2.ensureEmbedDeps === "function") {
297359
+ const res = mod2.ensureEmbedDeps();
297360
+ if (res?.log) renderInfo2(res.log.split("\n").slice(-3).join(" ").slice(0, 200));
297361
+ }
297362
+ if (typeof mod2.getVenvPython === "function") {
297363
+ const { dirname: dirname32 } = await import("node:path");
297364
+ const { existsSync: existsSync87 } = await import("node:fs");
297365
+ const venvBin = dirname32(mod2.getVenvPython());
297366
+ if (existsSync87(venvBin)) {
297367
+ const sep = process.platform === "win32" ? ";" : ":";
297368
+ const cur = process.env.PATH || "";
297369
+ if (!cur.split(sep).includes(venvBin)) {
297370
+ process.env.PATH = `${venvBin}${sep}${cur}`;
297371
+ }
297372
+ }
297373
+ }
297374
+ } catch {
297375
+ }
297376
+ const missing = [];
297377
+ const has = (cmd) => {
297378
+ try {
297379
+ nodeExecSync(`which ${cmd}`, { stdio: "pipe" });
297380
+ return true;
297381
+ } catch {
297382
+ return false;
297383
+ }
297384
+ };
297385
+ const isLinux = process.platform === "linux";
297386
+ const isDarwin = process.platform === "darwin";
297387
+ if (isLinux) {
297388
+ if (!has("arecord") && !has("ffmpeg")) missing.push("ffmpeg");
297389
+ try {
297390
+ nodeExecSync("python3 -m venv --help", { stdio: "pipe" });
297391
+ } catch {
297392
+ missing.push("python3-venv");
297393
+ }
297394
+ } else if (isDarwin) {
297395
+ if (!has("sox") && !has("ffmpeg")) missing.push("sox", "ffmpeg");
297396
+ }
297397
+ if (missing.length === 0) return;
297398
+ let script = "";
297399
+ if (isLinux) {
297400
+ if (has("apt-get")) {
297401
+ const pkgs = missing.join(" ");
297402
+ script = `apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y ${pkgs}`;
297403
+ } else if (has("dnf")) {
297404
+ const pkgs = missing.map((p2) => p2 === "python3-venv" ? "python3-venv" : p2).join(" ");
297405
+ script = `dnf install -y ${pkgs}`;
297406
+ } else if (has("pacman")) {
297407
+ const pkgs = missing.map((p2) => p2 === "python3-venv" ? "python-virtualenv" : p2).join(" ");
297408
+ script = `pacman -Sy --noconfirm ${pkgs}`;
297409
+ } else if (has("zypper")) {
297410
+ const pkgs = missing.map((p2) => p2 === "python3-venv" ? "python311-venv" : p2).join(" ");
297411
+ script = `zypper install -y ${pkgs}`;
297412
+ }
297413
+ } else if (isDarwin && has("brew")) {
297414
+ const pkgs = [...new Set(missing)].join(" ");
297415
+ script = `brew install ${pkgs}`;
297416
+ }
297417
+ if (script) {
297418
+ renderInfo2(`Installing OS dependencies: ${missing.join(", ")}`);
297419
+ await runSudoScript(ctx3, script);
297420
+ } else {
297421
+ renderWarning2(`Missing tools: ${missing.join(", ")}. Please install them manually.`);
297422
+ }
297423
+ }
297270
297424
  function findPidsByPattern(pattern) {
297271
297425
  const isWin2 = process.platform === "win32";
297272
297426
  try {
@@ -299862,6 +300016,10 @@ sleep 1
299862
300016
  return "handled";
299863
300017
  }
299864
300018
  renderInfo2("Starting voice chat — mic will capture your speech, agent will respond via TTS...");
300019
+ try {
300020
+ await ensureVoiceDeps(ctx3);
300021
+ } catch {
300022
+ }
299865
300023
  try {
299866
300024
  await ctx3.voiceChatStart();
299867
300025
  renderInfo2("Voice chat active. Speak naturally — agent hears you and responds. /hangup to stop.");
@@ -308245,7 +308403,7 @@ var init_types = __esm({
308245
308403
  });
308246
308404
 
308247
308405
  // packages/cli/src/tui/p2p/secret-vault.ts
308248
- import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync2, createHash as createHash5 } from "node:crypto";
308406
+ import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync2, createHash as createHash6 } from "node:crypto";
308249
308407
  import { readFileSync as readFileSync51, writeFileSync as writeFileSync36, existsSync as existsSync66, mkdirSync as mkdirSync38 } from "node:fs";
308250
308408
  import { dirname as dirname24 } from "node:path";
308251
308409
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
@@ -308489,7 +308647,7 @@ var init_secret_vault = __esm({
308489
308647
  /** Generate a deterministic fingerprint of vault contents (for sync verification) */
308490
308648
  fingerprint() {
308491
308649
  const names = Array.from(this.secrets.keys()).sort();
308492
- const hash = createHash5("sha256");
308650
+ const hash = createHash6("sha256");
308493
308651
  for (const name11 of names) {
308494
308652
  hash.update(name11 + ":");
308495
308653
  hash.update(this.secrets.get(name11).value);
@@ -308504,7 +308662,7 @@ var init_secret_vault = __esm({
308504
308662
  // packages/cli/src/tui/p2p/peer-mesh.ts
308505
308663
  import { EventEmitter as EventEmitter6 } from "node:events";
308506
308664
  import { createServer as createServer5 } from "node:http";
308507
- import { randomBytes as randomBytes19, createHash as createHash6, generateKeyPairSync } from "node:crypto";
308665
+ import { randomBytes as randomBytes19, createHash as createHash7, generateKeyPairSync } from "node:crypto";
308508
308666
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
308509
308667
  var init_peer_mesh = __esm({
308510
308668
  "packages/cli/src/tui/p2p/peer-mesh.ts"() {
@@ -308521,7 +308679,7 @@ var init_peer_mesh = __esm({
308521
308679
  const { publicKey: publicKey2, privateKey } = generateKeyPairSync("ed25519");
308522
308680
  this.publicKey = publicKey2.export({ type: "spki", format: "der" });
308523
308681
  this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
308524
- this.peerId = createHash6("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
308682
+ this.peerId = createHash7("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
308525
308683
  this.capabilities = options2.capabilities;
308526
308684
  this.displayName = options2.displayName;
308527
308685
  this._authKey = options2.authKey ?? randomBytes19(24).toString("base64url");
@@ -317488,7 +317646,7 @@ var init_disk_task_output = __esm({
317488
317646
  });
317489
317647
 
317490
317648
  // packages/cli/src/api/http.ts
317491
- import { createHash as createHash7 } from "node:crypto";
317649
+ import { createHash as createHash8 } from "node:crypto";
317492
317650
  function problemDetails(opts) {
317493
317651
  const p2 = {
317494
317652
  type: opts.type ?? "about:blank",
@@ -317551,7 +317709,7 @@ function paginated(items, page2, total) {
317551
317709
  }
317552
317710
  function computeEtag(payload) {
317553
317711
  const json = typeof payload === "string" ? payload : JSON.stringify(payload);
317554
- const hash = createHash7("sha1").update(json).digest("hex").slice(0, 16);
317712
+ const hash = createHash8("sha1").update(json).digest("hex").slice(0, 16);
317555
317713
  return `W/"${hash}"`;
317556
317714
  }
317557
317715
  function checkNotModified(req2, res, etag) {
@@ -325197,7 +325355,7 @@ import { homedir as homedir38 } from "node:os";
325197
325355
  import { spawn as spawn25, execSync as execSync55 } from "node:child_process";
325198
325356
  import { mkdirSync as mkdirSync51, writeFileSync as writeFileSync45, readFileSync as readFileSync65, readdirSync as readdirSync28, existsSync as existsSync83, watch as fsWatch3 } from "node:fs";
325199
325357
  import { randomBytes as randomBytes21, randomUUID as randomUUID11 } from "node:crypto";
325200
- import { createHash as createHash9 } from "node:crypto";
325358
+ import { createHash as createHash10 } from "node:crypto";
325201
325359
  function getVersion3() {
325202
325360
  try {
325203
325361
  const require3 = createRequire4(import.meta.url);
@@ -329010,7 +329168,7 @@ function listScheduledTasks() {
329010
329168
  const schedule = String(t2?.schedule || t2?.cron || t2?.when || "");
329011
329169
  const enabled2 = typeof t2?.enabled === "boolean" ? t2.enabled : true;
329012
329170
  const realId = typeof t2?.id === "string" && t2.id ? t2.id : null;
329013
- const fallbackId = createHash9("sha1").update(`${file}#${i2}`).digest("hex").slice(0, 16);
329171
+ const fallbackId = createHash10("sha1").update(`${file}#${i2}`).digest("hex").slice(0, 16);
329014
329172
  const uid = realId || fallbackId;
329015
329173
  const key = `${uid}`;
329016
329174
  if (seen.has(key)) return;
@@ -329127,8 +329285,8 @@ function deleteScheduledById(id) {
329127
329285
  if (id) candidates.push(id);
329128
329286
  if (typeof entry?.id === "string" && entry.id && !candidates.includes(entry.id)) candidates.push(entry.id);
329129
329287
  try {
329130
- const { createHash: createHash11 } = __require("node:crypto");
329131
- const fallback = createHash11("sha1").update(`${target.file}#${target.index}`).digest("hex").slice(0, 16);
329288
+ const { createHash: createHash12 } = __require("node:crypto");
329289
+ const fallback = createHash12("sha1").update(`${target.file}#${target.index}`).digest("hex").slice(0, 16);
329132
329290
  if (!candidates.includes(fallback)) candidates.push(fallback);
329133
329291
  } catch {
329134
329292
  }
@@ -336753,13 +336911,13 @@ ${fullInput}`;
336753
336911
  writeContent(() => renderError2(errMsg));
336754
336912
  if (failureStore) {
336755
336913
  try {
336756
- const { createHash: createHash11 } = await import("node:crypto");
336914
+ const { createHash: createHash12 } = await import("node:crypto");
336757
336915
  failureStore.insert({
336758
336916
  taskId: "",
336759
336917
  sessionId: `${Date.now()}`,
336760
336918
  repoRoot,
336761
336919
  failureType: "runtime-error",
336762
- fingerprint: createHash11("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
336920
+ fingerprint: createHash12("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
336763
336921
  filePath: null,
336764
336922
  errorMessage: errMsg.slice(0, 500),
336765
336923
  context: null,
@@ -337612,7 +337770,7 @@ var init_run = __esm({
337612
337770
  import { glob as glob2 } from "glob";
337613
337771
  import ignore from "ignore";
337614
337772
  import { readFile as readFile23, stat as stat5 } from "node:fs/promises";
337615
- import { createHash as createHash10 } from "node:crypto";
337773
+ import { createHash as createHash11 } from "node:crypto";
337616
337774
  import { join as join102, relative as relative5, extname as extname12, basename as basename18 } from "node:path";
337617
337775
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
337618
337776
  var init_codebase_indexer = __esm({
@@ -337678,7 +337836,7 @@ var init_codebase_indexer = __esm({
337678
337836
  if (fileStat.size > this.config.maxFileSize)
337679
337837
  continue;
337680
337838
  const content = await readFile23(fullPath);
337681
- const hash = createHash10("sha256").update(content).digest("hex");
337839
+ const hash = createHash11("sha256").update(content).digest("hex");
337682
337840
  const ext = extname12(relativePath);
337683
337841
  indexed.push({
337684
337842
  path: fullPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.333",
3
+ "version": "0.187.335",
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",