dsh-selfupdater 0.4.25 → 0.4.26

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.
Files changed (2) hide show
  1. package/lib/updater.mjs +47 -4
  2. package/package.json +1 -1
package/lib/updater.mjs CHANGED
@@ -12,7 +12,8 @@
12
12
  */
13
13
  import { spawn } from 'node:child_process';
14
14
  import net from 'node:net';
15
- import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
15
+ import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync
16
+ , rmSync, writeFileSync } from 'node:fs';
16
17
  import { dirname, join, resolve } from 'node:path';
17
18
  import { fileURLToPath } from 'node:url';
18
19
  import { applyFnosPatches } from './fnos-patches.mjs';
@@ -317,10 +318,19 @@ async function downloadIntoStaging(target, registryBase) {
317
318
  // 版本,撞上"staged 必须严格等于 target"的校验而误报失败。
318
319
  writeFileSync(
319
320
  join(stagingDir, 'package.json'),
320
- JSON.stringify({ name: 'dsh-selfupdate-staging', private: true, dependencies: { [PKG]: target } }, null, 2),
321
+ // pnpm.onlyBuiltDependencies 白名单放行原生包的 install 脚本:pnpm 10 默认
322
+ // 拦截构建脚本,koffi(cnoke 解压 vendor 预编译)和 fs-ext(node-gyp 编译)
323
+ // 不跑脚本就没有 native 产物,dsh 0.1.3-alpha.2 起依赖它们,boot 直接崩。
324
+ JSON.stringify({
325
+ name: 'dsh-selfupdate-staging',
326
+ private: true,
327
+ dependencies: { [PKG]: target },
328
+ pnpm: { onlyBuiltDependencies: ['koffi', 'fs-ext'] },
329
+ }, null, 2),
321
330
  );
322
- // 实体文件布局 + 关闭交互确认,保证无人值守可执行。
323
- writeFileSync(join(stagingDir, '.npmrc'), 'node-linker=hoisted\n');
331
+ // 实体文件布局 + 关闭交互确认 + 关闭 side-effects 缓存(防 store 里旧版本的
332
+ // 构建产物跨版本污染),保证无人值守可执行。
333
+ writeFileSync(join(stagingDir, '.npmrc'), 'node-linker=hoisted\nside-effects-cache=false\n');
324
334
  const pnpm = pnpmCommand();
325
335
  setState('downloading', `正在下载 ${PKG}@${target} …`);
326
336
  // pnpm 不认 npm 风格的 --omit/--no-audit/--no-fund(0.4.18 实测踩坑):
@@ -341,6 +351,39 @@ async function downloadIntoStaging(target, registryBase) {
341
351
  // 校验装到的确实是目标版本,防止镜像滞后悄悄装了旧版。
342
352
  const staged = JSON.parse(readFileSync(join(stagingDir, 'node_modules', PKG, 'package.json'), 'utf8')).version;
343
353
  if (staged !== target) throw new Error(`staging 版本不符:期望 ${target},实际 ${staged}`);
354
+ // 原生模块自检:0.1.3-alpha.2 起 dsh 依赖 koffi/fs-ext,缺 native 产物会让
355
+ // 宿主 boot 崩溃(0.4.25 实测踩坑),换装前在此拦截。
356
+ verifyNativeModules();
357
+ }
358
+
359
+ /**
360
+ * 校验 staging 内原生模块的构建产物是否齐全。
361
+ * - koffi:cnoke --prebuild 从 vendor 解压,产物在 build/koffi/ 下的 .node;
362
+ * - fs-ext:node-gyp 编译,产物在 build/Release/fs-ext.node(NAS 需编译工具链)。
363
+ * 任一缺失即抛错,终止本次升级(尚未换装,旧版原样运行,天然安全)。
364
+ */
365
+ function verifyNativeModules() {
366
+ const problems = [];
367
+ if (!findFileByExt(join(stagingDir, 'node_modules', 'koffi', 'build'), '.node')) {
368
+ problems.push('koffi 缺少原生二进制(install 脚本未执行或 prebuild 解压失败)');
369
+ }
370
+ const fsExtDir = join(stagingDir, 'node_modules', 'fs-ext');
371
+ if (!existsSync(join(fsExtDir, 'fs-ext.js'))) {
372
+ problems.push('fs-ext 包文件不完整(缺少 fs-ext.js)');
373
+ } else if (!findFileByExt(join(fsExtDir, 'build'), '.node')) {
374
+ problems.push('fs-ext 缺少编译产物 build/Release/fs-ext.node(NAS 需要 python3/make/g++ 工具链)');
375
+ }
376
+ if (problems.length > 0) throw new Error(`原生模块校验失败:${problems.join(';')}`);
377
+ }
378
+
379
+ /** 递归查找目录下第一个指定扩展名的文件,目录不存在或未找到返回 null。 */
380
+ function findFileByExt(dir, ext) {
381
+ try {
382
+ for (const entry of readdirSync(dir, { recursive: true })) {
383
+ if (entry.endsWith(ext)) return join(dir, entry);
384
+ }
385
+ } catch { /* 目录不存在 */ }
386
+ return null;
344
387
  }
345
388
 
346
389
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-selfupdater",
3
- "version": "0.4.25",
3
+ "version": "0.4.26",
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",