open-agents-ai 0.187.538 → 0.187.540

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
@@ -285,9 +285,14 @@ function saveCache(cache8) {
285
285
  }
286
286
  async function fetchLatestVersion() {
287
287
  try {
288
- const resp = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
288
+ const url = `https://registry.npmjs.org/${PACKAGE_NAME}/latest?_=${Date.now()}`;
289
+ const resp = await fetch(url, {
289
290
  signal: AbortSignal.timeout(5e3),
290
- headers: { Accept: "application/json" }
291
+ headers: {
292
+ Accept: "application/json",
293
+ "Cache-Control": "no-cache, no-store, max-age=0",
294
+ Pragma: "no-cache"
295
+ }
291
296
  });
292
297
  if (!resp.ok) return null;
293
298
  const data = await resp.json();
@@ -315,7 +320,7 @@ async function checkForUpdate(currentVersion, forceCheck = false) {
315
320
  function formatUpdateBanner(info) {
316
321
  return `
317
322
  Update available: v${info.currentVersion} → v${info.latestVersion}
318
- Run: npm i -g ${PACKAGE_NAME} or use /update in the REPL
323
+ Run: npm i -g ${PACKAGE_NAME}@${info.latestVersion} or use /update in the REPL
319
324
  `;
320
325
  }
321
326
  var PACKAGE_NAME, CHECK_INTERVAL_MS, CACHE_DIR, CACHE_FILE;
@@ -569329,12 +569334,13 @@ async function handleUpdate(subcommand, ctx3) {
569329
569334
  if (doPackage && info) {
569330
569335
  installOverlay.setPhase("Package");
569331
569336
  installOverlay.setStatus("Installing package...");
569332
- const installCmd = `${sudoPrefix}npm install -g open-agents-ai@latest --prefer-online`;
569337
+ const versionSpec = info.latestVersion ? `@${info.latestVersion}` : "@latest";
569338
+ const installCmd = `${sudoPrefix}npm install -g open-agents-ai${versionSpec} --prefer-online --cache-min=0`;
569333
569339
  let installOk = await runInstall2(installCmd);
569334
569340
  if (!installOk && process.platform === "win32" && /EPERM|EACCES|access|denied|permission/i.test(installError)) {
569335
569341
  installOverlay.setStatus("Elevating permissions...");
569336
569342
  installError = "";
569337
- installOk = await runInstall2(`powershell -NoProfile -Command "Start-Process -FilePath 'npm' -ArgumentList 'install -g open-agents-ai@latest --prefer-online' -Verb RunAs -Wait"`);
569343
+ installOk = await runInstall2(`powershell -NoProfile -Command "Start-Process -FilePath 'npm' -ArgumentList 'install -g open-agents-ai${versionSpec} --prefer-online --cache-min=0' -Verb RunAs -Wait"`);
569338
569344
  }
569339
569345
  if (!installOk && /ENOTEMPTY|errno -39/i.test(installError)) {
569340
569346
  installOverlay.setStatus("Cleaning stale artifacts...");
@@ -569353,13 +569359,13 @@ async function handleUpdate(subcommand, ctx3) {
569353
569359
  }
569354
569360
  installOverlay.setStatus("Installing...");
569355
569361
  installError = "";
569356
- installOk = await runInstall2(`${process.platform === "win32" ? "" : sudoPrefix}npm install -g open-agents-ai@latest --force --prefer-online`);
569362
+ installOk = await runInstall2(`${process.platform === "win32" ? "" : sudoPrefix}npm install -g open-agents-ai${versionSpec} --force --prefer-online --cache-min=0`);
569357
569363
  }
569358
569364
  if (!installOk) {
569359
569365
  installOverlay.stop("Install failed");
569360
569366
  await new Promise((r2) => setTimeout(r2, 2e3));
569361
569367
  installOverlay.dismiss();
569362
- const hint = process.platform === "win32" ? `npm i -g open-agents-ai (run terminal as Administrator)` : `${sudoPrefix}npm i -g open-agents-ai`;
569368
+ const hint = process.platform === "win32" ? `npm i -g open-agents-ai${versionSpec} (run terminal as Administrator)` : `${sudoPrefix}npm cache clean --force && ${sudoPrefix}npm i -g open-agents-ai${versionSpec}`;
569363
569369
  renderWarning2(`Update failed: ${installError.slice(0, 150) || "unknown error"}`);
569364
569370
  renderWarning2(`Try manually: ${hint}`);
569365
569371
  return;
@@ -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.538",
3
+ "version": "0.187.540",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "open-agents-ai",
9
- "version": "0.187.538",
9
+ "version": "0.187.540",
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.538",
3
+ "version": "0.187.540",
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",