dsh-selfupdater 0.4.22 → 0.4.24
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/lib/updater.mjs +34 -5
- package/package.json +1 -1
package/lib/updater.mjs
CHANGED
|
@@ -376,19 +376,46 @@ function launchRunnerChain() {
|
|
|
376
376
|
env: { ...process.env, TRIM_APPDEST: appDir },
|
|
377
377
|
});
|
|
378
378
|
child.unref();
|
|
379
|
+
// 用新 runner 的 PID 覆盖飞牛守护的 PID 文件:守护探活恢复正常认知,
|
|
380
|
+
// 后续自愈/状态轮询不会因 PID 文件指向死进程而拉起竞争实例。
|
|
381
|
+
writeSupervisorPidFile(child.pid);
|
|
379
382
|
log(`已拉起 runner 链 (pid=${child.pid})`);
|
|
380
383
|
}
|
|
381
384
|
|
|
382
385
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
386
|
+
* 飞牛守护 PID 文件握手(0.4.23 新增,修复守护竞态):
|
|
387
|
+
* 宿主为升级退出后,守护的 PID 文件指向死进程,升级窗口(1~2 分钟)内
|
|
388
|
+
* 任何一次守护自愈/状态轮询/手动启停都会按"服务未运行"拉起竞争实例,
|
|
389
|
+
* 与本脚本的下载/换装/拉起互相踩踏(12:01~12:04 实测踩坑)。
|
|
390
|
+
* 对策:升级期间把本脚本 PID 写入 PID 文件 —— 守护 kill -0 探活认为
|
|
391
|
+
* "应用仍在运行",不会另起实例;结束后由 launchRunnerChain 用新 runner
|
|
392
|
+
* PID 覆盖。本脚本若中途死亡,PID 失效,守护自然兜底拉起,行为闭环。
|
|
393
|
+
*/
|
|
394
|
+
const supervisorPidFile = process.env.TRIM_PKGVAR
|
|
395
|
+
? join(process.env.TRIM_PKGVAR, `${process.env.TRIM_APPNAME || 'deepseek-harness'}.pid`)
|
|
396
|
+
: null;
|
|
397
|
+
|
|
398
|
+
function writeSupervisorPidFile(pid) {
|
|
399
|
+
if (!supervisorPidFile) return;
|
|
400
|
+
try {
|
|
401
|
+
writeFileSync(supervisorPidFile, String(pid));
|
|
402
|
+
log(`已写入守护 PID 文件: ${supervisorPidFile} <- ${pid}`);
|
|
403
|
+
} catch { /* 非飞牛环境或权限不足时静默跳过 */ }
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* 健康检查:轮询本地端口,判定服务是否真正就绪。
|
|
408
|
+
* 0.4.23:从"有任何响应即健康"收紧为要求 res.ok,防错误页中间层误判。
|
|
409
|
+
* 0.4.24:本机实测 alpha.4 起 Web 端点启用了 token 鉴权,未带 token 访问
|
|
410
|
+
* `/` 返回 401 —— 这是真实后端的应答(服务已就绪),必须放行;
|
|
411
|
+
* 代理错误页通常是 502/503,仍会被正确拒绝。
|
|
385
412
|
*/
|
|
386
413
|
async function waitHealthy(timeoutMs) {
|
|
387
414
|
const deadline = Date.now() + timeoutMs;
|
|
388
415
|
while (Date.now() < deadline) {
|
|
389
416
|
try {
|
|
390
|
-
await fetch(`http://127.0.0.1:${port}/`, { signal: AbortSignal.timeout(3000) });
|
|
391
|
-
return true;
|
|
417
|
+
const res = await fetch(`http://127.0.0.1:${port}/`, { signal: AbortSignal.timeout(3000) });
|
|
418
|
+
if (res.ok || res.status === 401 || res.status === 403) return true;
|
|
392
419
|
} catch { /* 未就绪继续等 */ }
|
|
393
420
|
await sleep(2000);
|
|
394
421
|
}
|
|
@@ -420,6 +447,8 @@ async function rollback() {
|
|
|
420
447
|
|
|
421
448
|
async function main() {
|
|
422
449
|
mkdirSync(dshStateDir, { recursive: true });
|
|
450
|
+
// 升级窗口内接管守护 PID 文件,防止飞牛守护拉起竞争实例(见上方握手注释)
|
|
451
|
+
writeSupervisorPidFile(process.pid);
|
|
423
452
|
const current = currentDshVersion();
|
|
424
453
|
|
|
425
454
|
// 锁文件握手:插件本体 POST /perform 会预写锁文件(by=plugin)作为并发
|
|
@@ -462,7 +491,7 @@ async function main() {
|
|
|
462
491
|
if (await waitHealthy(90000)) {
|
|
463
492
|
// 成功:清理 staging;bak 目录保留作为手动救砖的最后手段。
|
|
464
493
|
rmSync(stagingDir, { recursive: true, force: true });
|
|
465
|
-
setState('done', `升级完成:${current} -> ${target}
|
|
494
|
+
setState('done', `升级完成:${current} -> ${target}。请检查插件市场的插件是否已适配新版 DSH。`, { finishedAt: new Date().toISOString() });
|
|
466
495
|
} else {
|
|
467
496
|
await rollback();
|
|
468
497
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-selfupdater",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.24",
|
|
4
4
|
"description": "Self-update plugin for DeepSeek Harness: DSH core upgrades via detached swap script; plugin self-update installs in-place without killing the host and prompts for restart. DSH 主程序与已装插件的一站式在线更新插件。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|