@brainjar/cli 0.6.4 → 0.6.5
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/package.json +1 -1
- package/src/daemon.ts +21 -23
package/package.json
CHANGED
package/src/daemon.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn, execFileSync } from 'node:child_process'
|
|
2
2
|
import { createHash } from 'node:crypto'
|
|
3
|
-
import { readFile, writeFile, rm, access, open, chmod, mkdir, constants } from 'node:fs/promises'
|
|
3
|
+
import { readFile, writeFile, rm, access, open, chmod, mkdir, rename, copyFile, constants } from 'node:fs/promises'
|
|
4
4
|
import { dirname, join } from 'node:path'
|
|
5
5
|
import { tmpdir } from 'node:os'
|
|
6
6
|
import { Errors } from 'incur'
|
|
@@ -31,7 +31,7 @@ const { IncurError } = Errors
|
|
|
31
31
|
* Minimum server version this CLI is compatible with.
|
|
32
32
|
* Bump when the CLI depends on server features/API changes.
|
|
33
33
|
*/
|
|
34
|
-
export const MIN_SERVER_VERSION = '0.2.
|
|
34
|
+
export const MIN_SERVER_VERSION = '0.2.7'
|
|
35
35
|
|
|
36
36
|
export interface HealthStatus {
|
|
37
37
|
healthy: boolean
|
|
@@ -229,9 +229,17 @@ export async function downloadAndVerify(binPath: string, versionBase: string): P
|
|
|
229
229
|
})
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
await chmod(
|
|
232
|
+
// Avoid ETXTBSY: unlink the old binary first (running process
|
|
233
|
+
// keeps its inode), then move the new one into place.
|
|
234
|
+
await chmod(extractedBin, 0o755)
|
|
235
|
+
await rm(binPath, { force: true })
|
|
236
|
+
try {
|
|
237
|
+
await rename(extractedBin, binPath)
|
|
238
|
+
} catch {
|
|
239
|
+
// Cross-device rename (tmpdir on different fs) — fall back to copy
|
|
240
|
+
await copyFile(extractedBin, binPath)
|
|
241
|
+
await chmod(binPath, 0o755)
|
|
242
|
+
}
|
|
235
243
|
} finally {
|
|
236
244
|
await rm(tmpDir, { recursive: true, force: true })
|
|
237
245
|
}
|
|
@@ -275,27 +283,17 @@ export async function upgradeServer(): Promise<{ version: string; alreadyLatest:
|
|
|
275
283
|
return { version, alreadyLatest: true }
|
|
276
284
|
}
|
|
277
285
|
|
|
278
|
-
//
|
|
279
|
-
|
|
280
|
-
if (pid !== null && isAlive(pid)) {
|
|
281
|
-
await stop()
|
|
282
|
-
|
|
283
|
-
// Verify process is actually dead before replacing binary
|
|
284
|
-
const deadline = Date.now() + 3000
|
|
285
|
-
while (Date.now() < deadline && isAlive(pid)) {
|
|
286
|
-
await new Promise(r => setTimeout(r, 100))
|
|
287
|
-
}
|
|
288
|
-
if (isAlive(pid)) {
|
|
289
|
-
throw createError(ErrorCode.SERVER_START_FAILED, {
|
|
290
|
-
message: `Server process (PID ${pid}) is still running. Cannot replace binary.`,
|
|
291
|
-
hint: `Kill it manually: kill -9 ${pid}`,
|
|
292
|
-
})
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
286
|
+
// Binary replacement uses rm + rename/copy which avoids ETXTBSY.
|
|
287
|
+
// The running server keeps its old inode; next restart picks up the new binary.
|
|
296
288
|
const versionBase = `${DIST_BASE}/${version}`
|
|
297
289
|
await downloadAndVerify(binPath, versionBase)
|
|
298
290
|
await setInstalledServerVersion(version)
|
|
291
|
+
|
|
292
|
+
// Restart the server on the new binary
|
|
293
|
+
await stop()
|
|
294
|
+
await new Promise(r => setTimeout(r, 1000))
|
|
295
|
+
await start()
|
|
296
|
+
|
|
299
297
|
return { version, alreadyLatest: false }
|
|
300
298
|
}
|
|
301
299
|
|