@gehennawu/dsh-service 2.0.4 → 2.0.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/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  import { AsyncLocalStorage } from 'node:async_hooks'
4
4
  import { createHash, createHmac, randomBytes, randomUUID } from 'node:crypto'
5
5
  import { Buffer } from 'node:buffer'
6
- import { constants as fsConstants, existsSync, readFileSync } from 'node:fs'
6
+ import { constants as fsConstants, existsSync, readFileSync, realpathSync } from 'node:fs'
7
7
  import { access, chmod, cp, link, lstat, mkdir, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from 'node:fs/promises'
8
8
  import { homedir } from 'node:os'
9
9
  import { basename, dirname, join, relative, resolve, sep } from 'node:path'
@@ -284,18 +284,60 @@ const FETCH_TIMEOUT_OVERRIDE = '--config.fetchTimeout=600000'
284
284
  // 当前正在运行的插件源码目录:定位「本插件由哪个 profile 挂载」时与磁盘副本做 realpath 匹配。
285
285
  const loadedPluginDir = dirname(fileURLToPath(import.meta.url))
286
286
 
287
- // 读取当前 dsh 版本。DSH 包由宿主安装,不作为插件依赖打包进来。
288
- let dshVersion = 'unknown'
289
- let pluginVersion = 'unknown'
290
- try { pluginVersion = require('./package.json').version } catch (_) {}
291
- try {
292
- dshVersion = require(`${DSH_PACKAGE}/package.json`).version
293
- } catch (_) {
287
+ // 运行中宿主版本的探测。DSH 包由宿主安装,不作为插件依赖打包进来,插件只能自己找。
288
+ // 候选按「离真正在跑的进程有多近」排序(2026-10-03 修复:旧实现只有后两条,
289
+ // 非全局前缀安装——npx / `npm i --prefix` / 隔离 profile——会静默读到机器上另一份安装):
290
+ // ① 当前进程入口 `process.argv[1]`(先 realpath 穿透 `.bin` 软链)逐级向上找
291
+ // `name === '@deepseek-ai/dsh'` 的 package.json —— 这是真正在跑的那份;
292
+ // ② 从插件自身路径 require(历史行为,profile 与宿主同树时命中);
293
+ // ③ 镜像/容器里的历史全局路径(兼容既有部署)。
294
+ // 任一候选的版本串都要过 BACKUP_VERSION_RE(含数字、长度封顶)才采纳,否则继续回落;
295
+ // 全部失败返回 'unknown',绝不让坏值进版本卡、更新判定与备份文件名。
296
+ const LEGACY_GLOBAL_DSH_MANIFEST = '/usr/local/lib/node_modules/@deepseek-ai/dsh/package.json'
297
+
298
+ function readDshVersion(options = {}) {
299
+ const readText = options.readFileSync ?? readFileSync
300
+ const resolveReal = options.realpathSync ?? realpathSync
301
+ const loadManifest = options.requireManifest ?? ((path) => require(path))
302
+ const argv1 = options.argv1 ?? process.argv[1]
303
+ const accepted = (value) => (typeof value === 'string' && BACKUP_VERSION_RE.test(value) ? value : null)
304
+ const entryManifestVersion = (path) => {
305
+ try {
306
+ const manifest = JSON.parse(readText(path, 'utf8'))
307
+ if (manifest === null || typeof manifest !== 'object' || manifest.name !== DSH_PACKAGE) return null
308
+ return accepted(manifest.version)
309
+ } catch (_) {
310
+ return null
311
+ }
312
+ }
313
+ if (typeof argv1 === 'string' && argv1 !== '') {
314
+ let entry = argv1
315
+ try { entry = resolveReal(argv1) } catch (_) {}
316
+ // 目录链深度设上限:拿不到 realpath 或入口在异常位置时不至于无限上溯。
317
+ let directory = dirname(entry)
318
+ for (let depth = 0; depth < 12; depth += 1) {
319
+ const version = entryManifestVersion(join(directory, 'package.json'))
320
+ if (version !== null) return version
321
+ const parent = dirname(directory)
322
+ if (parent === directory) break
323
+ directory = parent
324
+ }
325
+ }
326
+ try {
327
+ const version = accepted(loadManifest(`${DSH_PACKAGE}/package.json`)?.version)
328
+ if (version !== null) return version
329
+ } catch (_) {}
294
330
  try {
295
- dshVersion = require('/usr/local/lib/node_modules/@deepseek-ai/dsh/package.json').version
296
- } catch (__) {}
331
+ const version = accepted(loadManifest(LEGACY_GLOBAL_DSH_MANIFEST)?.version)
332
+ if (version !== null) return version
333
+ } catch (_) {}
334
+ return 'unknown'
297
335
  }
298
336
 
337
+ let dshVersion = readDshVersion()
338
+ let pluginVersion = 'unknown'
339
+ try { pluginVersion = require('./package.json').version } catch (_) {}
340
+
299
341
  // Node 最低要求只读 package.json engines 一处(与版本号同源),启动时解析一次。
300
342
  let requiredNodeMajor = 22
301
343
  try {
@@ -6168,6 +6210,7 @@ export {
6168
6210
  quotaEndpointFor,
6169
6211
  quotaErrorCode,
6170
6212
  quotaProviderUnusable,
6213
+ readDshVersion,
6171
6214
  readLlmProviders,
6172
6215
  readLlmProvidersFromDescribe,
6173
6216
  normalizeLlmProviderEntries,
@@ -6263,6 +6306,7 @@ export default {
6263
6306
  quotaEndpointFor,
6264
6307
  quotaErrorCode,
6265
6308
  quotaProviderUnusable,
6309
+ readDshVersion,
6266
6310
  readLlmProviders,
6267
6311
  readLlmProvidersFromDescribe,
6268
6312
  normalizeLlmProviderEntries,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gehennawu/dsh-service",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
4
4
  "description": "DSH Web 运维面板:安全重启、健康监控、备份和 Linux 权限维护。",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -52,7 +52,7 @@
52
52
  "homepage": "https://github.com/gehennawu/dsh-service#readme",
53
53
  "engines": {
54
54
  "node": ">=22",
55
- "dsh": ">=0.1.1-rc.2 <0.2.0-rc.3"
55
+ "dsh": ">=0.1.1-rc.2 <0.2.1-alpha.2"
56
56
  },
57
57
  "dependencies": {
58
58
  "@deepseek-ai/schemastery": "^3.18.3"