@gehennawu/dsh-service 2.0.4 → 2.0.6
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/README.en.md +3 -3
- package/README.md +3 -3
- package/client.js +1 -1
- package/index.js +59 -11
- package/package.json +2 -2
- package/screenshots/backup-management.png +0 -0
- package/screenshots/backup-management_en.png +0 -0
- package/screenshots/configuration.png +0 -0
- package/screenshots/configuration_en.png +0 -0
- package/screenshots/health-diagnostics.png +0 -0
- package/screenshots/health-diagnostics_en.png +0 -0
- package/screenshots/mobile-adaptation.png +0 -0
- package/screenshots/mobile-adaptation_en.png +0 -0
- package/screenshots/model-usage.png +0 -0
- package/screenshots/model-usage_en.png +0 -0
- package/screenshots/overview.png +0 -0
- package/screenshots/overview_en.png +0 -0
- package/screenshots/plugin-config.png +0 -0
- package/screenshots/plugin-config_en.png +0 -0
- package/screenshots/quota-lookup.png +0 -0
- package/screenshots/quota-lookup_en.png +0 -0
- package/screenshots/session-manager.png +0 -0
- package/screenshots/session-manager_en.png +0 -0
- package/screenshots/subagent-model.png +0 -0
- package/screenshots/subagent-model_en.png +0 -0
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
|
-
//
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
-
|
|
296
|
-
|
|
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 {
|
|
@@ -1216,7 +1258,11 @@ async function exportBackup(dshHome, downloadTokens, id) {
|
|
|
1216
1258
|
// 版本事实以归档内的 meta/backup.json 为准,不改名、不重写。
|
|
1217
1259
|
async function importBackup(dshHome, name, encoded, validatePath) {
|
|
1218
1260
|
if (typeof name !== 'string' || !BACKUP_NAME.test(name) || typeof encoded !== 'string' || encoded.length === 0) return undefined
|
|
1219
|
-
|
|
1261
|
+
// 只线性扫描字符;对大文件使用重复分组正则会耗尽 V8 正则调用栈。
|
|
1262
|
+
// 长度、填充位置和解码后重新编码的逐字节一致性仍共同约束规范 Base64。
|
|
1263
|
+
if (encoded.length > Math.ceil(MAX_BACKUP_TRANSFER_BYTES / 3) * 4 + 8 || encoded.length % 4 !== 0 || /[^A-Za-z0-9+/=]/.test(encoded)) return undefined
|
|
1264
|
+
const padding = encoded.indexOf('=')
|
|
1265
|
+
if (padding !== -1 && (padding < encoded.length - 2 || !/^[A-Za-z0-9+/]{2,3}={1,2}$/.test(encoded.slice(-4)))) return undefined
|
|
1220
1266
|
const data = Buffer.from(encoded, 'base64')
|
|
1221
1267
|
if (data.length === 0 || data.length > MAX_BACKUP_TRANSFER_BYTES || data.toString('base64') !== encoded) return undefined
|
|
1222
1268
|
const backupDir = join(dshHome, 'backups')
|
|
@@ -6168,6 +6214,7 @@ export {
|
|
|
6168
6214
|
quotaEndpointFor,
|
|
6169
6215
|
quotaErrorCode,
|
|
6170
6216
|
quotaProviderUnusable,
|
|
6217
|
+
readDshVersion,
|
|
6171
6218
|
readLlmProviders,
|
|
6172
6219
|
readLlmProvidersFromDescribe,
|
|
6173
6220
|
normalizeLlmProviderEntries,
|
|
@@ -6263,6 +6310,7 @@ export default {
|
|
|
6263
6310
|
quotaEndpointFor,
|
|
6264
6311
|
quotaErrorCode,
|
|
6265
6312
|
quotaProviderUnusable,
|
|
6313
|
+
readDshVersion,
|
|
6266
6314
|
readLlmProviders,
|
|
6267
6315
|
readLlmProvidersFromDescribe,
|
|
6268
6316
|
normalizeLlmProviderEntries,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gehennawu/dsh-service",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
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.
|
|
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"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/screenshots/overview.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|