open-agents-ai 0.187.334 → 0.187.336

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 +224 -112
  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
  });
@@ -297274,6 +297359,18 @@ async function ensureVoiceDeps(ctx3) {
297274
297359
  const res = mod2.ensureEmbedDeps();
297275
297360
  if (res?.log) renderInfo2(res.log.split("\n").slice(-3).join(" ").slice(0, 200));
297276
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
+ }
297277
297374
  } catch {
297278
297375
  }
297279
297376
  const missing = [];
@@ -299606,51 +299703,66 @@ sleep 1
299606
299703
  done(false);
299607
299704
  return;
299608
299705
  }
299706
+ const isSystemdTimer = String(task.id || "").startsWith("timer:") || task.file === "(systemd)" || task.index === -1;
299609
299707
  (async () => {
299610
299708
  try {
299611
299709
  const r3 = await doFetch(`/v1/scheduled/${encodeURIComponent(task.id)}`, { method: "DELETE", headers: { "Content-Type": "application/json" } });
299612
299710
  if (r3.ok) {
299613
299711
  renderInfo2(`Deleted scheduled task ${task.id}`);
299614
- try {
299615
- const dir = (task.file || "").split("/").slice(0, -1).join("/") || task.file;
299616
- const resp = await doFetch("/v1/scheduled/kill", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pattern: dir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") }) });
299712
+ if (isSystemdTimer) {
299713
+ try {
299714
+ const timerName = String(task.id || "").replace(/^timer:/, "");
299715
+ const { execSync: es } = await import("node:child_process");
299716
+ const userSystemd = `${process.env.HOME}/.config/systemd/user`;
299717
+ for (const suffix of [".timer", ".service"]) {
299718
+ try {
299719
+ es(`rm -f "${userSystemd}/${timerName}${suffix}"`, { stdio: "pipe" });
299720
+ } catch {
299721
+ }
299722
+ }
299723
+ try {
299724
+ es("systemctl --user daemon-reload", { stdio: "pipe" });
299725
+ } catch {
299726
+ }
299727
+ try {
299728
+ es(`pkill -f '${timerName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}' || true`, { stdio: "pipe", timeout: 5e3 });
299729
+ } catch {
299730
+ }
299731
+ renderInfo2(`Cleaned up systemd timer: ${timerName}`);
299732
+ } catch {
299733
+ }
299734
+ } else {
299617
299735
  try {
299618
- const j = await resp.json();
299619
- const cnt = (Array.isArray(j.killed) ? j.killed.length : 0) + (Array.isArray(j.additionally) ? j.additionally.length : 0);
299620
- if (cnt > 0) renderInfo2(`Killed ${cnt} residual process(es).`);
299736
+ const dir = (task.file || "").split("/").slice(0, -1).join("/") || task.file;
299737
+ const resp = await doFetch("/v1/scheduled/kill", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pattern: dir.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") }) });
299738
+ try {
299739
+ const j = await resp.json();
299740
+ const cnt = (Array.isArray(j.killed) ? j.killed.length : 0) + (Array.isArray(j.additionally) ? j.additionally.length : 0);
299741
+ if (cnt > 0) renderInfo2(`Killed ${cnt} residual process(es).`);
299742
+ } catch {
299743
+ }
299621
299744
  } catch {
299622
299745
  }
299623
- } catch {
299624
- }
299625
- try {
299626
- const id = String(task.id || "");
299627
- const dir = (task.file || "").split("/").slice(0, -1).join("/") || task.file;
299628
- const escId = id.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
299629
- const escDir = dir.replace(/['"\\]/g, "\\$&");
299630
- const script = [
299631
- // Disable both naming schemes if present
299632
- `systemctl disable --now "oa-${escId}.timer" 2>/dev/null || true`,
299633
- `systemctl disable --now "oa-${escId}.service" 2>/dev/null || true`,
299634
- `systemctl disable --now "oa-sched-${escId}.timer" 2>/dev/null || true`,
299635
- `systemctl disable --now "oa-sched-${escId}.service" 2>/dev/null || true`,
299636
- // Remove root cron OA markers for this id
299637
- `crontab -l 2>/dev/null | sed '/OPEN-AGENTS-SCHEDULED:${escId}/d' | crontab - || true`,
299638
- // Kill lingering processes broadly
299639
- `pkill -f 'OPEN-AGENTS-SCHEDULED|oa-sched-|open-agents-ai|/bin/oa|nexus-daemon|ollama' || true`,
299640
- `sleep 1`,
299641
- `pkill -9 -f 'OPEN-AGENTS-SCHEDULED|oa-sched-|open-agents-ai|/bin/oa|nexus-daemon|ollama' || true`
299642
- ].join("; ");
299643
- await runSudoScript(ctx3, script);
299644
299746
  try {
299645
- const dir2 = (task.file || "").split("/").slice(0, -1).join("/") || task.file;
299646
- const r22 = await doFetch("/v1/scheduled/kill", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pattern: dir2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") }) });
299647
- const j2 = await r22.json();
299648
- const rem2 = Array.isArray(j2.procs_after) ? j2.procs_after.length : 0;
299649
- if (rem2 > 0) renderWarning2(`Remaining after sudo cleanup: ${rem2}`);
299650
- else renderInfo2("No remaining matched processes after sudo cleanup.");
299747
+ const rawId = String(task.id || "");
299748
+ const dir = (task.file || "").split("/").slice(0, -1).join("/") || task.file;
299749
+ const baseId = rawId.replace(/^timer:/, "").replace(/^oa-sched-/, "").replace(/^oa-/, "");
299750
+ const escBase = baseId.replace(/['"\\]/g, "\\$&");
299751
+ const escDir = dir.replace(/['"\\]/g, "\\$&");
299752
+ const script = [
299753
+ // Disable both naming schemes if present
299754
+ `systemctl disable --now "oa-${escBase}.timer" 2>/dev/null || true`,
299755
+ `systemctl disable --now "oa-${escBase}.service" 2>/dev/null || true`,
299756
+ `systemctl disable --now "oa-sched-${escBase}.timer" 2>/dev/null || true`,
299757
+ `systemctl disable --now "oa-sched-${escBase}.service" 2>/dev/null || true`,
299758
+ // Remove root cron OA markers for this id
299759
+ `crontab -l 2>/dev/null | sed '/OPEN-AGENTS-SCHEDULED.*${escBase}/d' | crontab - || true`,
299760
+ // Kill only processes matching this specific task (not all OA/ollama/nexus)
299761
+ `pkill -f 'OPEN-AGENTS-SCHEDULED.*${escBase}' || true`
299762
+ ].join("; ");
299763
+ await runSudoScript(ctx3, script);
299651
299764
  } catch {
299652
299765
  }
299653
- } catch {
299654
299766
  }
299655
299767
  done(true);
299656
299768
  } else {
@@ -308306,7 +308418,7 @@ var init_types = __esm({
308306
308418
  });
308307
308419
 
308308
308420
  // packages/cli/src/tui/p2p/secret-vault.ts
308309
- import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync2, createHash as createHash5 } from "node:crypto";
308421
+ import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync2, createHash as createHash6 } from "node:crypto";
308310
308422
  import { readFileSync as readFileSync51, writeFileSync as writeFileSync36, existsSync as existsSync66, mkdirSync as mkdirSync38 } from "node:fs";
308311
308423
  import { dirname as dirname24 } from "node:path";
308312
308424
  var PLACEHOLDER_PREFIX, PLACEHOLDER_SUFFIX, CIPHER_ALGO, SALT_LEN, IV_LEN, KEY_LEN, SecretVault;
@@ -308550,7 +308662,7 @@ var init_secret_vault = __esm({
308550
308662
  /** Generate a deterministic fingerprint of vault contents (for sync verification) */
308551
308663
  fingerprint() {
308552
308664
  const names = Array.from(this.secrets.keys()).sort();
308553
- const hash = createHash5("sha256");
308665
+ const hash = createHash6("sha256");
308554
308666
  for (const name11 of names) {
308555
308667
  hash.update(name11 + ":");
308556
308668
  hash.update(this.secrets.get(name11).value);
@@ -308565,7 +308677,7 @@ var init_secret_vault = __esm({
308565
308677
  // packages/cli/src/tui/p2p/peer-mesh.ts
308566
308678
  import { EventEmitter as EventEmitter6 } from "node:events";
308567
308679
  import { createServer as createServer5 } from "node:http";
308568
- import { randomBytes as randomBytes19, createHash as createHash6, generateKeyPairSync } from "node:crypto";
308680
+ import { randomBytes as randomBytes19, createHash as createHash7, generateKeyPairSync } from "node:crypto";
308569
308681
  var PING_INTERVAL_MS, PEER_TIMEOUT_MS, GOSSIP_INTERVAL_MS, MAX_PEERS, PeerMesh;
308570
308682
  var init_peer_mesh = __esm({
308571
308683
  "packages/cli/src/tui/p2p/peer-mesh.ts"() {
@@ -308582,7 +308694,7 @@ var init_peer_mesh = __esm({
308582
308694
  const { publicKey: publicKey2, privateKey } = generateKeyPairSync("ed25519");
308583
308695
  this.publicKey = publicKey2.export({ type: "spki", format: "der" });
308584
308696
  this.privateKey = privateKey.export({ type: "pkcs8", format: "der" });
308585
- this.peerId = createHash6("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
308697
+ this.peerId = createHash7("sha256").update(this.publicKey).digest("base64url").slice(0, 22);
308586
308698
  this.capabilities = options2.capabilities;
308587
308699
  this.displayName = options2.displayName;
308588
308700
  this._authKey = options2.authKey ?? randomBytes19(24).toString("base64url");
@@ -317549,7 +317661,7 @@ var init_disk_task_output = __esm({
317549
317661
  });
317550
317662
 
317551
317663
  // packages/cli/src/api/http.ts
317552
- import { createHash as createHash7 } from "node:crypto";
317664
+ import { createHash as createHash8 } from "node:crypto";
317553
317665
  function problemDetails(opts) {
317554
317666
  const p2 = {
317555
317667
  type: opts.type ?? "about:blank",
@@ -317612,7 +317724,7 @@ function paginated(items, page2, total) {
317612
317724
  }
317613
317725
  function computeEtag(payload) {
317614
317726
  const json = typeof payload === "string" ? payload : JSON.stringify(payload);
317615
- const hash = createHash7("sha1").update(json).digest("hex").slice(0, 16);
317727
+ const hash = createHash8("sha1").update(json).digest("hex").slice(0, 16);
317616
317728
  return `W/"${hash}"`;
317617
317729
  }
317618
317730
  function checkNotModified(req2, res, etag) {
@@ -325258,7 +325370,7 @@ import { homedir as homedir38 } from "node:os";
325258
325370
  import { spawn as spawn25, execSync as execSync55 } from "node:child_process";
325259
325371
  import { mkdirSync as mkdirSync51, writeFileSync as writeFileSync45, readFileSync as readFileSync65, readdirSync as readdirSync28, existsSync as existsSync83, watch as fsWatch3 } from "node:fs";
325260
325372
  import { randomBytes as randomBytes21, randomUUID as randomUUID11 } from "node:crypto";
325261
- import { createHash as createHash9 } from "node:crypto";
325373
+ import { createHash as createHash10 } from "node:crypto";
325262
325374
  function getVersion3() {
325263
325375
  try {
325264
325376
  const require3 = createRequire4(import.meta.url);
@@ -329071,7 +329183,7 @@ function listScheduledTasks() {
329071
329183
  const schedule = String(t2?.schedule || t2?.cron || t2?.when || "");
329072
329184
  const enabled2 = typeof t2?.enabled === "boolean" ? t2.enabled : true;
329073
329185
  const realId = typeof t2?.id === "string" && t2.id ? t2.id : null;
329074
- const fallbackId = createHash9("sha1").update(`${file}#${i2}`).digest("hex").slice(0, 16);
329186
+ const fallbackId = createHash10("sha1").update(`${file}#${i2}`).digest("hex").slice(0, 16);
329075
329187
  const uid = realId || fallbackId;
329076
329188
  const key = `${uid}`;
329077
329189
  if (seen.has(key)) return;
@@ -329188,8 +329300,8 @@ function deleteScheduledById(id) {
329188
329300
  if (id) candidates.push(id);
329189
329301
  if (typeof entry?.id === "string" && entry.id && !candidates.includes(entry.id)) candidates.push(entry.id);
329190
329302
  try {
329191
- const { createHash: createHash11 } = __require("node:crypto");
329192
- const fallback = createHash11("sha1").update(`${target.file}#${target.index}`).digest("hex").slice(0, 16);
329303
+ const { createHash: createHash12 } = __require("node:crypto");
329304
+ const fallback = createHash12("sha1").update(`${target.file}#${target.index}`).digest("hex").slice(0, 16);
329193
329305
  if (!candidates.includes(fallback)) candidates.push(fallback);
329194
329306
  } catch {
329195
329307
  }
@@ -336814,13 +336926,13 @@ ${fullInput}`;
336814
336926
  writeContent(() => renderError2(errMsg));
336815
336927
  if (failureStore) {
336816
336928
  try {
336817
- const { createHash: createHash11 } = await import("node:crypto");
336929
+ const { createHash: createHash12 } = await import("node:crypto");
336818
336930
  failureStore.insert({
336819
336931
  taskId: "",
336820
336932
  sessionId: `${Date.now()}`,
336821
336933
  repoRoot,
336822
336934
  failureType: "runtime-error",
336823
- fingerprint: createHash11("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
336935
+ fingerprint: createHash12("sha256").update(errMsg.slice(0, 200)).digest("hex").slice(0, 16),
336824
336936
  filePath: null,
336825
336937
  errorMessage: errMsg.slice(0, 500),
336826
336938
  context: null,
@@ -337673,7 +337785,7 @@ var init_run = __esm({
337673
337785
  import { glob as glob2 } from "glob";
337674
337786
  import ignore from "ignore";
337675
337787
  import { readFile as readFile23, stat as stat5 } from "node:fs/promises";
337676
- import { createHash as createHash10 } from "node:crypto";
337788
+ import { createHash as createHash11 } from "node:crypto";
337677
337789
  import { join as join102, relative as relative5, extname as extname12, basename as basename18 } from "node:path";
337678
337790
  var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
337679
337791
  var init_codebase_indexer = __esm({
@@ -337739,7 +337851,7 @@ var init_codebase_indexer = __esm({
337739
337851
  if (fileStat.size > this.config.maxFileSize)
337740
337852
  continue;
337741
337853
  const content = await readFile23(fullPath);
337742
- const hash = createHash10("sha256").update(content).digest("hex");
337854
+ const hash = createHash11("sha256").update(content).digest("hex");
337743
337855
  const ext = extname12(relativePath);
337744
337856
  indexed.push({
337745
337857
  path: fullPath,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.334",
3
+ "version": "0.187.336",
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",