open-agents-ai 0.187.539 → 0.187.541

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.
package/dist/index.js CHANGED
@@ -585913,17 +585913,17 @@ async function runGraphicalSudo(opts) {
585913
585913
  }
585914
585914
  }, 2e3);
585915
585915
  }, timeoutMs);
585916
- child.stdout.on("data", (d2) => {
585916
+ child.stdout?.on("data", (d2) => {
585917
585917
  stdout += d2.toString("utf-8");
585918
585918
  });
585919
- child.stderr.on("data", (d2) => {
585919
+ child.stderr?.on("data", (d2) => {
585920
585920
  stderr += d2.toString("utf-8");
585921
585921
  });
585922
- child.on("error", (e2) => {
585922
+ child.once("error", (e2) => {
585923
585923
  clearTimeout(timer);
585924
585924
  reject(e2);
585925
585925
  });
585926
- child.on("close", (code8) => {
585926
+ child.once("close", (code8) => {
585927
585927
  clearTimeout(timer);
585928
585928
  if (timedOut) return reject(new Error(`graphical sudo timed out after ${timeoutMs}ms`));
585929
585929
  resolve43({ code: code8 ?? -1, stdout, stderr, helper });
@@ -85,18 +85,28 @@ function tryHealth(port, cb) {
85
85
  req.end();
86
86
  }
87
87
 
88
- // Resolve the `oa` launcher script. On npm global install:
89
- // Linux/macOS: $(npm prefix -g)/bin/oa
90
- // Windows: %APPDATA%/npm/oa.cmd
88
+ // Resolve the `oa` launcher script.
89
+ //
90
+ // PRIORITY ORDER (most stable first):
91
+ // 1. Sibling launcher.cjs — guaranteed to live next to this postinstall,
92
+ // survives across upgrades because it's part of the package itself.
93
+ // Avoids the npx cache trap and the fnm shim trap.
94
+ // 2. npm-global bin (if npm_config_prefix is set) — stable across reboots.
95
+ // 3. PATH-resolved oa — works in dev installs but can resolve to ephemeral
96
+ // shims (npx cache, fnm multishell symlinks).
91
97
  function resolveOaBinary() {
92
- // 1. If npm set npm_config_prefix, use it.
93
- var prefix = process.env.npm_config_prefix || "";
94
- if (!prefix) {
95
- // 2. Ask npm.
96
- prefix = runCapture("npm prefix -g");
97
- }
98
-
99
98
  var candidates = [];
99
+
100
+ // 1. Self-relative — IDEAL: the launcher ships in the same directory as
101
+ // this postinstall script, so as long as the package is installed, it
102
+ // exists. This path is what should land in the systemd ExecStart.
103
+ try {
104
+ candidates.push(path.resolve(__dirname, "launcher.cjs"));
105
+ } catch (e) {}
106
+
107
+ // 2. npm prefix bin
108
+ var prefix = process.env.npm_config_prefix || "";
109
+ if (!prefix) prefix = runCapture("npm prefix -g");
100
110
  if (prefix) {
101
111
  if (IS_WIN) {
102
112
  candidates.push(path.join(prefix, "oa.cmd"));
@@ -106,14 +116,9 @@ function resolveOaBinary() {
106
116
  candidates.push(path.join(prefix, "bin", "open-agents"));
107
117
  }
108
118
  }
109
- // 3. PATH fallback via which/where.
119
+ // 3. PATH fallback (last resort — can resolve to npx cache or fnm shim).
110
120
  var found = runCapture(IS_WIN ? "where oa" : "which oa").split(/\r?\n/)[0];
111
- if (found) candidates.push(found);
112
-
113
- // 4. Relative to this script: <pkg>/dist/launcher.cjs
114
- try {
115
- candidates.push(path.resolve(__dirname, "launcher.cjs"));
116
- } catch (e) {}
121
+ if (found && !/_npx|fnm_multishells/.test(found)) candidates.push(found);
117
122
 
118
123
  for (var i = 0; i < candidates.length; i++) {
119
124
  try {
@@ -315,8 +320,14 @@ function installSystemd(nodeBin, oaScript, user) {
315
320
  "Environment=OA_PORT=" + PORT,
316
321
  "Environment=NODE_ENV=production",
317
322
  "ExecStart=" + nodeBin + " " + oaScript + " serve --daemon --quiet",
318
- "Restart=on-failure",
323
+ // Restart=always (was on-failure) — also relaunch on clean exit.
324
+ // Some upgrade flows trigger process.exit(0) (e.g. /update reload,
325
+ // SIGTERM during npm install), which Restart=on-failure ignores.
326
+ // Pair with StartLimitIntervalSec to prevent thrash loops.
327
+ "Restart=always",
319
328
  "RestartSec=3",
329
+ "StartLimitIntervalSec=30",
330
+ "StartLimitBurst=10",
320
331
  "StandardOutput=append:" + path.join(logDir, "daemon.log"),
321
332
  "StandardError=append:" + path.join(logDir, "daemon.err.log"),
322
333
  "",
@@ -1,4 +1,92 @@
1
1
  #!/usr/bin/env node
2
- // Preinstall hook shim — no-op by default
3
- process.exit(0);
2
+ /* eslint-disable */
3
+ /**
4
+ * preinstall — runs BEFORE npm replaces files on disk. Gracefully stops
5
+ * the running OA daemon so the install window doesn't strand it with
6
+ * a half-replaced binary that crashes on next relaunch.
7
+ *
8
+ * The postinstall hook restarts the daemon after install completes with
9
+ * the new code in place.
10
+ *
11
+ * Opt-out: OA_SKIP_DAEMON_INSTALL=1 (matches postinstall semantics).
12
+ */
13
+
14
+ "use strict";
15
+
16
+ if (process.env.OA_SKIP_DAEMON_INSTALL === "1") {
17
+ process.exit(0);
18
+ }
19
+
20
+ var os = require("os");
21
+ var path = require("path");
22
+ var fs = require("fs");
23
+ var cp = require("child_process");
24
+
25
+ var IS_WIN = os.platform() === "win32";
26
+ var IS_LINUX = os.platform() === "linux";
27
+ var IS_MAC = os.platform() === "darwin";
28
+ var HOME = os.homedir();
29
+ var SERVICE_LABEL = "open-agents-daemon";
30
+ var LAUNCHD_LABEL = "ai.open-agents.daemon";
31
+ var WIN_TASK_NAME = "OpenAgentsDaemon";
32
+
33
+ function runQuiet(cmd) {
34
+ try { cp.execSync(cmd, { stdio: "pipe", timeout: 8000 }); return true; } catch (e) { return false; }
35
+ }
36
+
37
+ function log(msg) { process.stdout.write(" [preinstall] " + msg + "\n"); }
38
+
39
+ function stopServiceManager() {
40
+ // Stop via the registered service manager if one exists. This is
41
+ // graceful (sends SIGTERM, waits for exit) AND prevents the manager
42
+ // from auto-restarting the daemon mid-install.
43
+ try {
44
+ if (IS_LINUX) {
45
+ // Pause + stop. Don't disable — we want it to come back after
46
+ // postinstall re-enables/restarts it.
47
+ runQuiet("systemctl --user stop " + SERVICE_LABEL + ".service");
48
+ } else if (IS_MAC) {
49
+ var plist = path.join(HOME, "Library", "LaunchAgents", LAUNCHD_LABEL + ".plist");
50
+ if (fs.existsSync(plist)) runQuiet("launchctl unload " + plist);
51
+ } else if (IS_WIN) {
52
+ runQuiet('schtasks /End /TN "' + WIN_TASK_NAME + '"');
53
+ }
54
+ } catch (e) { /* best-effort */ }
55
+ }
56
+
57
+ function killPidFile(pidFile) {
58
+ try {
59
+ if (!fs.existsSync(pidFile)) return false;
60
+ var n = parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10);
61
+ if (!n || n <= 0) return false;
62
+ try { process.kill(n, "SIGTERM"); log("SIGTERM " + pidFile + " (pid " + n + ")"); return true; }
63
+ catch (e) { /* dead */ }
64
+ } catch (e) {}
65
+ return false;
66
+ }
67
+
68
+ stopServiceManager();
69
+ killPidFile(path.join(HOME, ".open-agents", "daemon.pid"));
70
+
71
+ // Final: lsof-based sweep for any process still holding 11435.
72
+ try {
73
+ var port = parseInt(process.env.OA_PORT || "11435", 10);
74
+ var out = "";
75
+ try {
76
+ out = cp.execSync("lsof -ti :" + port + " 2>/dev/null || true", {
77
+ encoding: "utf8", timeout: 3000,
78
+ }).trim();
79
+ } catch (e) {}
80
+ if (out) {
81
+ out.split(/\s+/).forEach(function (s) {
82
+ var n = parseInt(s, 10);
83
+ if (Number.isFinite(n) && n > 0 && n !== process.pid) {
84
+ try { process.kill(n, "SIGTERM"); log("SIGTERM port-holder pid " + n); } catch (e) {}
85
+ }
86
+ });
87
+ }
88
+ } catch (e) {}
89
+
90
+ // 1.5s grace so SIGTERM handlers can flush state.
91
+ setTimeout(function () { process.exit(0); }, 1500);
4
92
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.539",
3
+ "version": "0.187.541",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.539",
9
+ "version": "0.187.541",
10
10
  "hasInstallScript": true,
11
11
  "license": "CC-BY-NC-4.0",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.539",
3
+ "version": "0.187.541",
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",