open-agents-ai 0.187.239 → 0.187.240

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.
@@ -422,10 +422,21 @@ function main() {
422
422
  }
423
423
 
424
424
  if (alreadyUp) {
425
- log("OA daemon already responding on port " + PORT + " reinstalling service definition so it picks up the new build.");
426
- // Fall through to (re)install service files; the serve command's
427
- // daemon-mode /health pre-check will no-op if the existing daemon
428
- // is still healthy.
425
+ log("OA daemon on port " + PORT + " is running the old version — killing it so the new build starts cleanly.");
426
+ // Kill the old daemon explicitly. The preinstall hook already tried
427
+ // pkill, but by this point the install has completed and the old
428
+ // binary was replaced. A stale daemon holding the port would prevent
429
+ // the new one from binding. Kill by port to be precise.
430
+ if (!IS_WIN) {
431
+ runQuiet("fuser -k " + PORT + "/tcp 2>/dev/null || true");
432
+ // Also try systemctl restart which handles service-managed daemons.
433
+ runQuiet("systemctl --user restart " + SERVICE_LABEL + ".service 2>/dev/null || true");
434
+ } else {
435
+ runQuiet("netstat -aon | findstr :" + PORT + " | for /f \"tokens=5\" %a in ('findstr LISTENING') do taskkill /PID %a /F 2>nul");
436
+ }
437
+ // Give it a moment to release the port
438
+ try { cp.execSync("sleep 1 || timeout /t 1 /nobreak >nul 2>&1", { stdio: "pipe", timeout: 3000 }); } catch (e) {}
439
+ // Fall through to (re)install service files and start the new daemon.
429
440
  }
430
441
 
431
442
  log("Installing OA API daemon service for port " + PORT + " ...");
@@ -3,6 +3,63 @@
3
3
  // Pure CJS (no ESM, no backticks) so it works on any Node version.
4
4
  // Cross-platform: Linux, macOS, Windows (cmd, PowerShell, Git Bash).
5
5
  // If Node is too old, guides the user through installing Node 22.
6
+
7
+ // ── ENOTEMPTY fix: clean stale staging dirs before npm tries to rename ──
8
+ // npm's atomic-rename strategy fails with ENOTEMPTY when a previous install
9
+ // was interrupted or the daemon held file handles open. Clean any leftover
10
+ // .open-agents-ai-* temp dirs in the global node_modules BEFORE npm starts
11
+ // the install. Also kill any running daemon so its file handles release.
12
+ (function cleanStaleStaging() {
13
+ try {
14
+ var cp = require("child_process");
15
+ var path = require("path");
16
+ var fs = require("fs");
17
+
18
+ // 1. Kill running OA daemon so it releases file handles on the old install.
19
+ // Without this, npm can't rename the directory because node has dist/index.js open.
20
+ try {
21
+ if (process.platform === "win32") {
22
+ cp.execSync('taskkill /F /IM node.exe /FI "WINDOWTITLE eq open-agents*" 2>nul', { stdio: "pipe", timeout: 5000 });
23
+ } else {
24
+ // Kill any `oa serve` or `open-agents serve` processes. SIGTERM so they shut down cleanly.
25
+ cp.execSync("pkill -f 'open-agents.*serve' 2>/dev/null || true", { stdio: "pipe", timeout: 5000 });
26
+ // Also kill by port if pkill missed it
27
+ cp.execSync("fuser -k 11435/tcp 2>/dev/null || true", { stdio: "pipe", timeout: 5000 });
28
+ }
29
+ } catch (e) { /* daemon not running or pkill unavailable — fine */ }
30
+
31
+ // 2. Find and remove stale .open-agents-ai-* staging directories.
32
+ // These are npm's temp rename targets that got left behind.
33
+ var globalDir;
34
+ try {
35
+ globalDir = cp.execSync("npm root -g", { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"], timeout: 10000 }).trim();
36
+ } catch (e) {
37
+ globalDir = "";
38
+ }
39
+ if (globalDir && fs.existsSync(globalDir)) {
40
+ try {
41
+ var entries = fs.readdirSync(globalDir);
42
+ var cleaned = 0;
43
+ for (var i = 0; i < entries.length; i++) {
44
+ if (entries[i].indexOf(".open-agents-ai-") === 0) {
45
+ var stale = path.join(globalDir, entries[i]);
46
+ try {
47
+ fs.rmSync(stale, { recursive: true, force: true });
48
+ cleaned++;
49
+ } catch (e2) {
50
+ // rmSync not available on old Node — try rm -rf
51
+ try { cp.execSync("rm -rf " + JSON.stringify(stale), { stdio: "pipe", timeout: 10000 }); cleaned++; } catch (e3) {}
52
+ }
53
+ }
54
+ }
55
+ if (cleaned > 0) {
56
+ process.stdout.write(" [preinstall] Cleaned " + cleaned + " stale staging dir(s)\n");
57
+ }
58
+ } catch (e) { /* readdir failed — non-fatal */ }
59
+ }
60
+ } catch (e) { /* entire cleanup failed — non-fatal, let npm try anyway */ }
61
+ })();
62
+
6
63
  var nodeVersion = parseInt(process.versions.node, 10);
7
64
 
8
65
  if (nodeVersion >= 22) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.187.239",
3
+ "version": "0.187.240",
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",