dsh-selfupdater 0.4.7 → 0.4.8
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/plugin-update-task.mjs +56 -18
- package/package.json +1 -1
|
@@ -135,15 +135,26 @@ function readJson(file) {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
/** 读 profile
|
|
138
|
+
/** 读 profile 清单里记录的本插件依赖声明(可能是 ^0.4.6,也可能是 file:/…tgz);无记录返回 null。 */
|
|
139
139
|
function profileDeclaredVersion(profileDir) {
|
|
140
140
|
const dep = readJson(join(profileDir, 'package.json'))?.dependencies?.[SELF_NAME];
|
|
141
141
|
return typeof dep === 'string' && dep !== '' ? dep : null;
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
/**
|
|
145
|
-
|
|
146
|
-
|
|
144
|
+
/**
|
|
145
|
+
* 读 profile 下 node_modules 里实际安装的自身版本 —— 唯一权威来源。
|
|
146
|
+
* FPK 等安装方式会把清单声明写成 file:/…tgz 而非版本号(0.4.6 就因此
|
|
147
|
+
* 把"当前版本"显示成了整个 tgz 路径,连带 isNewer 误判"已是最新");
|
|
148
|
+
* 且更新装好但宿主未重启时,也只有这里的 package.json 是新版本。读不到返回 null。
|
|
149
|
+
*/
|
|
150
|
+
function installedVersionFromModules(profileDir) {
|
|
151
|
+
const version = readJson(join(profileDir, 'node_modules', SELF_NAME, 'package.json'))?.version;
|
|
152
|
+
return typeof version === 'string' && version !== '' ? version : null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** 字符串是否为合法 semver(file: URL、git URL 等非法声明返回 false)。 */
|
|
156
|
+
function isSemverString(v) {
|
|
157
|
+
return parseSemver(v) !== null;
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
/** 当前正在运行的自身版本(读本包 package.json;ESM 下用 createRequire 同步读)。 */
|
|
@@ -157,15 +168,29 @@ function runningVersion() {
|
|
|
157
168
|
}
|
|
158
169
|
|
|
159
170
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
171
|
+
* 解析"已安装的自身版本"(检查更新/状态展示/更新任务三方共用),三级兜底:
|
|
172
|
+
* 1. profile/node_modules 实际落盘的版本(权威;覆盖 file: 安装与未重启场景);
|
|
173
|
+
* 2. 清单 dependencies 声明(仅当是合法 semver;file: 等 URL 声明不可用);
|
|
174
|
+
* 3. 正在运行的版本(本地开发/异常兜底)。
|
|
175
|
+
*/
|
|
176
|
+
function resolveInstalledVersion(profileDir) {
|
|
177
|
+
const fromModules = installedVersionFromModules(profileDir);
|
|
178
|
+
if (fromModules !== null) return fromModules;
|
|
179
|
+
const declared = profileDeclaredVersion(profileDir);
|
|
180
|
+
if (declared !== null && isSemverString(declared.replace(/^[\^~>=<\s]+/, ''))) {
|
|
181
|
+
return declared.replace(/^[\^~>=<\s]+/, '');
|
|
182
|
+
}
|
|
183
|
+
return runningVersion();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 已安装的自身版本(供"检查更新/状态展示"路由使用)。
|
|
188
|
+
* 必须实时读盘而非模块加载时快照:更新装好但宿主未重启期间,
|
|
189
|
+
* UI 要立即显示新版号,"检查更新"也不能再误报"发现新版本"。
|
|
164
190
|
*/
|
|
165
191
|
export function installedSelfVersion(workspace) {
|
|
166
192
|
const profileDir = join(workspace, '.dsh', 'profiles', process.env.DSH_PLUGIN_PROFILE ?? 'web');
|
|
167
|
-
|
|
168
|
-
return declared !== null ? declared.replace(/^[\^~>=<\s]+/, '') : runningVersion();
|
|
193
|
+
return resolveInstalledVersion(profileDir);
|
|
169
194
|
}
|
|
170
195
|
|
|
171
196
|
/** 定位 dsh CLI 入口:打包布局优先,其次 node_modules 标准布局。 */
|
|
@@ -268,10 +293,9 @@ export async function runPluginUpdateTask({ appDir, workspace, logger }) {
|
|
|
268
293
|
rmSync(orphanBak, { recursive: true, force: true });
|
|
269
294
|
}
|
|
270
295
|
|
|
271
|
-
/* 1.
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
const installed = declared !== null ? declared.replace(/^[\^~>=<\s]+/, '') : runningVersion();
|
|
296
|
+
/* 1. 确定当前版本:读实际落盘的 node_modules(权威来源,见
|
|
297
|
+
resolveInstalledVersion 注释——清单声明可能是 file:/…tgz)。 */
|
|
298
|
+
const installed = resolveInstalledVersion(profileDir);
|
|
275
299
|
setState('running', '正在查询最新版本…', { startedAt: new Date().toISOString() });
|
|
276
300
|
|
|
277
301
|
/* 2. 查询最新版本与下载地址。 */
|
|
@@ -300,15 +324,29 @@ export async function runPluginUpdateTask({ appDir, workspace, logger }) {
|
|
|
300
324
|
INSTALL_TIMEOUT_MS,
|
|
301
325
|
);
|
|
302
326
|
|
|
303
|
-
/* 6.
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
327
|
+
/* 6. 校验:实际落盘版本一致 + 入口文件存在。
|
|
328
|
+
不读清单声明——本地 tgz 安装会把声明写成 file: 指向暂存文件,不可靠。 */
|
|
329
|
+
const installedNow = installedVersionFromModules(profileDir);
|
|
330
|
+
if (installedNow !== release.version) {
|
|
331
|
+
throw new Error(`安装后版本异常:期望 ${release.version},实际 ${installedNow ?? '未安装'}`);
|
|
307
332
|
}
|
|
308
333
|
if (!existsSync(join(profileDir, 'node_modules', SELF_NAME, 'lib', 'index.js'))) {
|
|
309
334
|
throw new Error('入口文件未落盘,安装可能不完整');
|
|
310
335
|
}
|
|
311
336
|
|
|
337
|
+
/* 6.5 修正清单声明:dsh plugin add 装本地 tgz 会把依赖写成 file: 指向
|
|
338
|
+
暂存文件,而暂存文件随后会被删除(引用悬空);改写为精确版本号,
|
|
339
|
+
保证下次重建依赖时能从 registry 正常解析。失败不影响本次安装。 */
|
|
340
|
+
try {
|
|
341
|
+
const manifest = readJson(manifestPath);
|
|
342
|
+
if (manifest.dependencies?.[SELF_NAME] !== release.version) {
|
|
343
|
+
manifest.dependencies = { ...manifest.dependencies, [SELF_NAME]: release.version };
|
|
344
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
345
|
+
}
|
|
346
|
+
} catch (err) {
|
|
347
|
+
warnLog(`清单声明修正失败(不影响已安装文件): ${err.message}`);
|
|
348
|
+
}
|
|
349
|
+
|
|
312
350
|
/* 7. 成功:不重启宿主,提示用户重启使新版本生效。 */
|
|
313
351
|
setState('done_pending_restart',
|
|
314
352
|
`插件已更新到 ${release.version},请重启 DeepSeek Harness 使新版本生效`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-selfupdater",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
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",
|