deltara 0.30.54 → 0.31.0
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/bin/integrity.json +3 -3
- package/bin/postinstall.js +147 -16
- package/package.json +1 -1
- package/vendor/darwin-arm64/deltara +0 -0
package/bin/integrity.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"deltara": "sha256:
|
|
3
|
-
"generated_at": "2026-05-
|
|
4
|
-
"version": "0.
|
|
2
|
+
"deltara": "sha256:b6abe5779edcfdc9dfea0d27eb4cb3250d7b21a2929e17d4f1d6e3af7f4bbb8c",
|
|
3
|
+
"generated_at": "2026-05-05T19:23:55Z",
|
|
4
|
+
"version": "0.31.0"
|
|
5
5
|
}
|
package/bin/postinstall.js
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// postinstall.js —
|
|
3
|
-
// the controlling terminal, bypassing npm's stdout pipe.
|
|
2
|
+
// postinstall.js — npm lifecycle hook (runs after `npm install -g deltara`).
|
|
4
3
|
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
4
|
+
// Three phases:
|
|
5
|
+
// 1. Stop any running deltara server (old binary in memory).
|
|
6
|
+
// 2. Run `deltara setup --auto` for auth/MCP config (idempotent).
|
|
7
|
+
// 3. Start a fresh deltara server detached (new binary in memory).
|
|
8
|
+
//
|
|
9
|
+
// Why all three matter:
|
|
10
|
+
// The deltara server is a long-running standalone daemon — NO MCP host
|
|
11
|
+
// respawns it on demand. After `npm install -g deltara@<new>`, the new
|
|
12
|
+
// binary is on disk but the old server keeps running with the old binary
|
|
13
|
+
// loaded in memory. The release also rotates _CLI_SECRET, so the old
|
|
14
|
+
// server hits 403 forever and pipelines silently fail. Killing without
|
|
15
|
+
// restart just leaves the user with a dead system. Both halves required.
|
|
16
|
+
//
|
|
17
|
+
// All steps are best-effort — never fail npm install over upgrade hygiene.
|
|
9
18
|
|
|
10
|
-
const { spawnSync } = require("child_process");
|
|
19
|
+
const { spawnSync, spawn } = require("child_process");
|
|
11
20
|
const path = require("path");
|
|
12
21
|
const fs = require("fs");
|
|
13
22
|
const os = require("os");
|
|
14
23
|
|
|
15
|
-
// Skip in CI or non-interactive environments
|
|
24
|
+
// Skip in CI or non-interactive environments.
|
|
16
25
|
if (process.env.CI || process.env.DELTARA_NO_SETUP) {
|
|
17
26
|
process.exit(0);
|
|
18
27
|
}
|
|
@@ -22,32 +31,97 @@ const arch = os.arch();
|
|
|
22
31
|
const platformKey = `${platform}-${arch}`;
|
|
23
32
|
const binName = platform === "win32" ? "deltara.exe" : "deltara";
|
|
24
33
|
const binPath = path.join(__dirname, "..", "vendor", platformKey, binName);
|
|
34
|
+
const homeDir = os.homedir();
|
|
35
|
+
const deltaraDir = path.join(homeDir, ".deltara");
|
|
36
|
+
const pidFile = path.join(deltaraDir, "server.pid");
|
|
37
|
+
const upgradePendingFile = path.join(deltaraDir, "mcp_upgrade_pending");
|
|
25
38
|
|
|
26
39
|
if (!fs.existsSync(binPath)) {
|
|
27
|
-
// Unsupported platform — not an error
|
|
40
|
+
// Unsupported platform — not an error.
|
|
28
41
|
process.exit(0);
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
// Ensure executable bit (may be missing on some npm extract paths).
|
|
32
45
|
try { fs.chmodSync(binPath, 0o755); } catch (_) {}
|
|
33
46
|
|
|
34
|
-
//
|
|
35
|
-
//
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
48
|
+
// Phase 1: Stop any running deltara server.
|
|
49
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
50
|
+
function killOldServer() {
|
|
51
|
+
let killed = false;
|
|
52
|
+
|
|
53
|
+
// 1a. Read PID file and try graceful then forceful kill.
|
|
54
|
+
if (fs.existsSync(pidFile)) {
|
|
55
|
+
try {
|
|
56
|
+
const pidStr = fs.readFileSync(pidFile, "utf8").trim();
|
|
57
|
+
const pid = parseInt(pidStr, 10);
|
|
58
|
+
if (pid > 0) {
|
|
59
|
+
try {
|
|
60
|
+
process.kill(pid, "SIGTERM");
|
|
61
|
+
// Give the server up to ~2.5s to exit gracefully.
|
|
62
|
+
const start = Date.now();
|
|
63
|
+
while (Date.now() - start < 2500) {
|
|
64
|
+
try {
|
|
65
|
+
process.kill(pid, 0); // signal 0 = check existence
|
|
66
|
+
// Still alive — sleep a beat
|
|
67
|
+
const wait = spawnSync(process.execPath, ["-e", "setTimeout(()=>{},250)"], { stdio: "ignore" });
|
|
68
|
+
if (wait.status === null) break;
|
|
69
|
+
} catch (_) {
|
|
70
|
+
// ESRCH — process is gone
|
|
71
|
+
killed = true;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Forceful if still alive.
|
|
76
|
+
if (!killed) {
|
|
77
|
+
try { process.kill(pid, "SIGKILL"); killed = true; } catch (_) {}
|
|
78
|
+
}
|
|
79
|
+
} catch (e) {
|
|
80
|
+
// EPERM (different user) or ESRCH (already gone) — both OK.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch (_) {}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 1b. Belt-and-suspenders: pkill by command-line match (Unix only).
|
|
87
|
+
// Catches PIDs from stale lock files where pidFile is missing.
|
|
88
|
+
if (platform !== "win32") {
|
|
89
|
+
try {
|
|
90
|
+
spawnSync("pkill", ["-9", "-f", "deltara server"], { stdio: "ignore" });
|
|
91
|
+
} catch (_) {}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 1c. Clean lock files.
|
|
95
|
+
for (const f of [pidFile, upgradePendingFile]) {
|
|
96
|
+
try { if (fs.existsSync(f)) fs.unlinkSync(f); } catch (_) {}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return killed;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const wasRunning = killOldServer();
|
|
103
|
+
if (wasRunning) {
|
|
104
|
+
// Print to stdout (postinstall) so user sees the action.
|
|
105
|
+
console.log(" Deltara: stopped previous server (upgrade).");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
109
|
+
// Phase 2: Run `deltara setup --auto` with TTY wired up.
|
|
110
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
36
111
|
let ttyFd;
|
|
37
112
|
if (platform !== "win32") {
|
|
38
113
|
try {
|
|
39
114
|
ttyFd = fs.openSync("/dev/tty", "w");
|
|
40
115
|
} catch (_) {
|
|
41
|
-
// No controlling terminal (
|
|
42
|
-
//
|
|
116
|
+
// No controlling terminal (SSH no-TTY, Docker, etc.).
|
|
117
|
+
// Skip both setup and server start — user can run `deltara setup` manually.
|
|
43
118
|
process.exit(0);
|
|
44
119
|
}
|
|
45
120
|
} else {
|
|
46
|
-
// Windows: stdout is already fine (npm behaviour differs).
|
|
47
121
|
ttyFd = process.stdout.fd;
|
|
48
122
|
}
|
|
49
123
|
|
|
50
|
-
const
|
|
124
|
+
const setupResult = spawnSync(binPath, ["setup", "--auto"], {
|
|
51
125
|
stdio: ["inherit", ttyFd, ttyFd],
|
|
52
126
|
env: process.env,
|
|
53
127
|
});
|
|
@@ -56,5 +130,62 @@ if (ttyFd !== process.stdout.fd) {
|
|
|
56
130
|
try { fs.closeSync(ttyFd); } catch (_) {}
|
|
57
131
|
}
|
|
58
132
|
|
|
59
|
-
//
|
|
133
|
+
// Setup non-zero exit is non-fatal — but don't try to start the server
|
|
134
|
+
// if setup failed; auth config may be incomplete.
|
|
135
|
+
if (setupResult.status !== 0) {
|
|
136
|
+
process.exit(0);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
140
|
+
// Phase 3: Start fresh deltara server detached.
|
|
141
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
142
|
+
function startNewServer() {
|
|
143
|
+
try {
|
|
144
|
+
const child = spawn(binPath, ["server", "start"], {
|
|
145
|
+
detached: true,
|
|
146
|
+
stdio: "ignore",
|
|
147
|
+
env: process.env,
|
|
148
|
+
});
|
|
149
|
+
child.unref();
|
|
150
|
+
// Brief poll for confirmation: server.pid should be rewritten with the
|
|
151
|
+
// new process's PID within a couple of seconds.
|
|
152
|
+
const start = Date.now();
|
|
153
|
+
let confirmed = false;
|
|
154
|
+
while (Date.now() - start < 4000) {
|
|
155
|
+
if (fs.existsSync(pidFile)) {
|
|
156
|
+
try {
|
|
157
|
+
const newPid = parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10);
|
|
158
|
+
if (newPid > 0) {
|
|
159
|
+
try {
|
|
160
|
+
process.kill(newPid, 0); // alive check
|
|
161
|
+
confirmed = true;
|
|
162
|
+
break;
|
|
163
|
+
} catch (_) {}
|
|
164
|
+
}
|
|
165
|
+
} catch (_) {}
|
|
166
|
+
}
|
|
167
|
+
// Short busy-wait — child_process.spawnSync(setTimeout) trick avoids
|
|
168
|
+
// requiring async/await in this script.
|
|
169
|
+
const _w = spawnSync(process.execPath, ["-e", "setTimeout(()=>{},250)"], { stdio: "ignore" });
|
|
170
|
+
if (_w.status === null) break;
|
|
171
|
+
}
|
|
172
|
+
if (confirmed) {
|
|
173
|
+
console.log(" Deltara: new server started.");
|
|
174
|
+
} else {
|
|
175
|
+
console.log(
|
|
176
|
+
" Deltara: server did not confirm within 4s. " +
|
|
177
|
+
"Run 'deltara server start' to see the error live."
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
} catch (e) {
|
|
181
|
+
console.log(
|
|
182
|
+
" Deltara: failed to spawn new server: " + e.message + "\n" +
|
|
183
|
+
" Run 'deltara server start' to start it manually."
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
startNewServer();
|
|
189
|
+
|
|
190
|
+
// Always exit 0 — npm install must never fail because of upgrade-restart.
|
|
60
191
|
process.exit(0);
|
package/package.json
CHANGED
|
Binary file
|