open-agents-ai 0.187.321 → 0.187.323

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 +135 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -299366,8 +299366,56 @@ The session corrections MUST become hard rules in the SKILL.md Rules section.`;
299366
299366
  } else if (arg === "start") {
299367
299367
  const ok2 = await ensureDaemon2();
299368
299368
  renderInfo2(ok2 ? "Daemon started." : "Daemon already running or failed to start.");
299369
+ } else if (arg === "takeover") {
299370
+ try {
299371
+ renderInfo2("Requesting sudo to migrate daemon to current user and restart...");
299372
+ const nodeBin = process.execPath;
299373
+ const { execSync: execSync57 } = await import("node:child_process");
299374
+ let npmRoot = "";
299375
+ try {
299376
+ npmRoot = execSync57("npm root -g", { encoding: "utf8" }).trim();
299377
+ } catch {
299378
+ }
299379
+ const launcher = npmRoot ? `${npmRoot}/open-agents-ai/dist/launcher.cjs` : "";
299380
+ const svc = [
299381
+ "[Unit]",
299382
+ "Description=Open Agents API Daemon",
299383
+ "After=default.target",
299384
+ "",
299385
+ "[Service]",
299386
+ "Type=simple",
299387
+ `ExecStart=${nodeBin} ${launcher} serve --daemon --quiet`,
299388
+ `WorkingDirectory=${process.cwd()}`,
299389
+ "Restart=always",
299390
+ "RestartSec=2",
299391
+ "Environment=OA_DAEMON=1",
299392
+ "",
299393
+ "[Install]",
299394
+ "WantedBy=default.target",
299395
+ ""
299396
+ ].join("\n").replace(/[$`]/g, "\\$&");
299397
+ const takeover = `set -e
299398
+ sudo -v
299399
+ sudo systemctl disable --now open-agents-daemon.service || true
299400
+ sudo pkill -f 'open-agents-ai.*serve' || true
299401
+ mkdir -p "$HOME/.config/systemd/user"
299402
+ printf '%s' "${svc}" > "$HOME/.config/systemd/user/open-agents-daemon.service"
299403
+ systemctl --user daemon-reload || true
299404
+ systemctl --user enable --now open-agents-daemon.service || true
299405
+ sleep 1
299406
+ `;
299407
+ const { spawn: spawn27 } = await import("node:child_process");
299408
+ await new Promise((resolve40) => {
299409
+ const child = spawn27("bash", ["-lc", takeover], { stdio: "inherit" });
299410
+ child.on("exit", () => resolve40());
299411
+ });
299412
+ renderInfo2("Daemon takeover complete.");
299413
+ } catch (e2) {
299414
+ renderError2(`Takeover failed: ${e2?.message || e2}`);
299415
+ }
299416
+ return "handled";
299369
299417
  } else {
299370
- renderInfo2("Usage: /daemon [status|start|stop|restart]");
299418
+ renderInfo2("Usage: /daemon [status|start|stop|restart|takeover]");
299371
299419
  }
299372
299420
  return "handled";
299373
299421
  }
@@ -327818,26 +327866,42 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
327818
327866
  const body = await parseJsonBody(req2);
327819
327867
  const pids = Array.isArray(body?.pids) ? body.pids.filter((n2) => Number.isInteger(n2)) : void 0;
327820
327868
  const pattern = typeof body?.pattern === "string" && body.pattern.trim() ? body.pattern.trim() : "(/bin/oa|open-agents-ai|nexus-daemon|OPEN-AGENTS-SCHEDULED|ollama)";
327869
+ const timersDisabled = disableAllOaTimers();
327870
+ const cronRemoved = removeAllOaCrons();
327821
327871
  const procsBefore = listMatchingProcesses(pattern);
327822
327872
  const gpuBefore = sampleGpuUtil();
327823
- const killed = killScheduledProcesses(pids, pattern);
327873
+ const killed = killProcessGroups(pids, pattern);
327824
327874
  const additionally = [];
327825
327875
  try {
327826
327876
  for (const [rid, child] of Array.from(runningProcesses.entries())) {
327827
327877
  const pid = child?.pid ?? 0;
327828
327878
  if (pid > 0) {
327829
327879
  try {
327830
- process.kill(pid, "SIGTERM");
327831
- additionally.push({ pid, ok: true, signal: "TERM", run_id: rid });
327880
+ process.kill(-child.pid, "SIGTERM");
327881
+ additionally.push({ pid, ok: true, signal: "PGRP-TERM", run_id: rid });
327882
+ } catch {
327883
+ try {
327884
+ process.kill(pid, "SIGTERM");
327885
+ additionally.push({ pid, ok: true, signal: "TERM", run_id: rid });
327886
+ } catch {
327887
+ additionally.push({ pid, ok: false, signal: "TERM", run_id: rid });
327888
+ }
327889
+ }
327890
+ try {
327891
+ await new Promise((r2) => setTimeout(r2, 250));
327832
327892
  } catch {
327833
- additionally.push({ pid, ok: false, signal: "TERM", run_id: rid });
327834
327893
  }
327835
327894
  try {
327836
327895
  process.kill(pid, 0);
327837
327896
  try {
327838
- process.kill(pid, "SIGKILL");
327839
- additionally.push({ pid, ok: true, signal: "KILL", run_id: rid });
327897
+ process.kill(-child.pid, "SIGKILL");
327898
+ additionally.push({ pid, ok: true, signal: "PGRP-KILL", run_id: rid });
327840
327899
  } catch {
327900
+ try {
327901
+ process.kill(pid, "SIGKILL");
327902
+ additionally.push({ pid, ok: true, signal: "KILL", run_id: rid });
327903
+ } catch {
327904
+ }
327841
327905
  }
327842
327906
  } catch {
327843
327907
  }
@@ -327847,12 +327911,14 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
327847
327911
  } catch {
327848
327912
  }
327849
327913
  try {
327850
- await new Promise((r2) => setTimeout(r2, 600));
327914
+ await new Promise((r2) => setTimeout(r2, 800));
327851
327915
  } catch {
327852
327916
  }
327853
327917
  const procsAfter = listMatchingProcesses(pattern);
327854
327918
  const gpuAfter = sampleGpuUtil();
327855
327919
  jsonResponse(res, 200, {
327920
+ timers_disabled: timersDisabled,
327921
+ cron_lines_removed: cronRemoved,
327856
327922
  killed_count: killed.length + additionally.length,
327857
327923
  killed,
327858
327924
  additionally,
@@ -328887,47 +328953,59 @@ function setScheduledEnabled(id, enabled2) {
328887
328953
  return false;
328888
328954
  }
328889
328955
  }
328890
- function killScheduledProcesses(pids, pattern) {
328956
+ function killProcessGroups(pids, pattern) {
328891
328957
  const killed = [];
328892
328958
  try {
328893
328959
  const { execSync: es } = __require("node:child_process");
328894
- const targets = /* @__PURE__ */ new Set();
328960
+ const targets = /* @__PURE__ */ new Map();
328895
328961
  if (pids && pids.length > 0) {
328896
- for (const pid of pids) if (Number.isInteger(pid)) targets.add(pid);
328962
+ for (const pid of pids) {
328963
+ try {
328964
+ const out = es(`ps -o pgid= -p ${pid}`, { encoding: "utf8", stdio: "pipe" }).trim();
328965
+ const pg = parseInt(out, 10);
328966
+ if (pg > 0) targets.set(pid, pg);
328967
+ } catch {
328968
+ }
328969
+ }
328897
328970
  } else {
328898
328971
  try {
328899
- const ps = es("ps -eo pid,command", { encoding: "utf8", stdio: "pipe" });
328972
+ const ps = es("ps -eo pid,pgid,command", { encoding: "utf8", stdio: "pipe" });
328900
328973
  const re = new RegExp(pattern, "i");
328901
328974
  for (const line of ps.split("\n")) {
328902
- const m2 = line.trim().match(/^(\d+)\s+(.*)$/);
328975
+ const m2 = line.trim().match(/^(\d+)\s+(\d+)\s+(.+)$/);
328903
328976
  if (!m2) continue;
328904
328977
  const pid = parseInt(m2[1], 10);
328905
- const cmd = m2[2] || "";
328906
- if (!isFinite(pid)) continue;
328907
- if (re.test(cmd)) targets.add(pid);
328978
+ const pg = parseInt(m2[2], 10);
328979
+ const cmd = m2[3] || "";
328980
+ if (!isFinite(pid) || !isFinite(pg)) continue;
328981
+ if (!re.test(cmd)) continue;
328982
+ targets.set(pid, pg);
328908
328983
  }
328909
328984
  } catch {
328910
328985
  }
328911
328986
  }
328912
- for (const pid of targets) {
328987
+ const seenPg = /* @__PURE__ */ new Set();
328988
+ for (const [, pg] of targets) {
328989
+ if (seenPg.has(pg)) continue;
328990
+ seenPg.add(pg);
328913
328991
  try {
328914
- process.kill(pid, "SIGTERM");
328915
- killed.push({ pid, ok: true, signal: "TERM" });
328992
+ process.kill(-pg, "SIGTERM");
328993
+ killed.push({ pid: -pg, ok: true, signal: "PGRP-TERM" });
328916
328994
  } catch {
328917
- killed.push({ pid, ok: false, signal: "TERM" });
328995
+ killed.push({ pid: -pg, ok: false, signal: "PGRP-TERM" });
328918
328996
  }
328919
328997
  }
328920
328998
  const start2 = Date.now();
328921
- while (Date.now() - start2 < 500) {
328999
+ while (Date.now() - start2 < 600) {
328922
329000
  }
328923
- for (const pid of targets) {
329001
+ for (const pg of seenPg) {
328924
329002
  try {
328925
- process.kill(pid, 0);
329003
+ process.kill(-pg, 0);
328926
329004
  try {
328927
- process.kill(pid, "SIGKILL");
328928
- killed.push({ pid, ok: true, signal: "KILL" });
329005
+ process.kill(-pg, "SIGKILL");
329006
+ killed.push({ pid: -pg, ok: true, signal: "PGRP-KILL" });
328929
329007
  } catch {
328930
- killed.push({ pid, ok: false, signal: "KILL" });
329008
+ killed.push({ pid: -pg, ok: false, signal: "PGRP-KILL" });
328931
329009
  }
328932
329010
  } catch {
328933
329011
  }
@@ -328936,6 +329014,37 @@ function killScheduledProcesses(pids, pattern) {
328936
329014
  }
328937
329015
  return killed;
328938
329016
  }
329017
+ function disableAllOaTimers() {
329018
+ let disabled = 0;
329019
+ try {
329020
+ const timers = listOaUserTimers();
329021
+ for (const t2 of timers) {
329022
+ try {
329023
+ userServiceAction(`${t2.name}.timer`, "disable");
329024
+ disabled++;
329025
+ } catch {
329026
+ }
329027
+ try {
329028
+ userServiceAction(`${t2.name}.timer`, "stop");
329029
+ } catch {
329030
+ }
329031
+ }
329032
+ } catch {
329033
+ }
329034
+ return disabled;
329035
+ }
329036
+ function removeAllOaCrons() {
329037
+ try {
329038
+ const lines = getCurrentCrontabLines();
329039
+ const next = lines.filter((l2) => !l2.includes(CRON_MARKER2));
329040
+ if (next.length !== lines.length) {
329041
+ writeCrontabLines(next);
329042
+ return lines.length - next.length;
329043
+ }
329044
+ } catch {
329045
+ }
329046
+ return 0;
329047
+ }
328939
329048
  function listMatchingProcesses(pattern) {
328940
329049
  const list = [];
328941
329050
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.321",
3
+ "version": "0.187.323",
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",