🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

自动升级助手 guraul/self-dsh-plugins

DeepSeek Harness
guraul19 天前有提交已提供中文文档扫描:含敏感能力

检测新版本并预检兼容性,一键备份升级重启

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/17 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add guraul/self-dsh-plugins
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么[目录]—
dsh 原生插件 · ui
暂无时间戳·判据 →
装得上吗[实装验证]!
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
数据截至 2026/11/03·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 19 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

⚠︎ 实装验证未通过(unknown · 2026/11/3) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 140 处,展示前 117 条)
  • 发起网络请求
    dsh-auto-upgrade/lib/client.js:295
    const response = await fetch(url, {
  • 读取本地文件
    dsh-auto-upgrade/lib/index.js:49
    const ownPackage = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
  • 读取本地文件
    dsh-auto-upgrade/lib/index.js:67
    const raw = readFileSync(path, 'utf8')
  • 读取本地文件
    dsh-auto-upgrade/lib/index.js:728
    manifest = JSON.parse(await readFile(installation.manifestPath, 'utf8'))
  • 发起网络请求
    dsh-awake/lib/client.js:86
    const response = await fetch(url, {
  • 发起网络请求
    dsh-external-discuss/lib/client.js:224
    const response = await fetch(`${API_PAYLOAD}?${query.toString()}`, { headers: { accept: 'application/json' } })
  • 读取本地文件
    dsh-im-bridge-workspaces/lib/index.js:382
    size = statSync(real).size;
  • 读取本地文件
    dsh-im-bridge-workspaces/lib/index.js:393
    buffer = readFileSync(real);
  • 读取密钥环境变量
    dsh-im-bridge-workspaces/lib/index.js:6902
    if (node_process.env.LOG_TOKENS) console.log("|", cst.prettyToken(source));
  • 写入本地文件
    dsh-im-bridge-workspaces/lib/index.js:7915
    mkdirSync(dir, { recursive: true });
  • 写入本地文件
    dsh-im-bridge-workspaces/lib/index.js:8009
    mkdirSync(dest, { recursive: true });
  • 读取本地文件
    dsh-im-bridge-workspaces/lib/index.js:8013
    if (existsSync(skillDir)) rmSync(skillDir, {
  • 删除本地文件
    dsh-im-bridge-workspaces/lib/index.js:8013
    if (existsSync(skillDir)) rmSync(skillDir, {
  • 写入本地文件
    dsh-im-bridge-workspaces/lib/index.js:8022
    mkdirSync(dirname(target), { recursive: true });
  • 写入本地文件
    dsh-im-bridge-workspaces/lib/index.js:8023
    writeFileSync(target, entry.data);
  • 读取本地文件
    dsh-im-bridge-workspaces/lib/index.js:8163
    const raw = readFileSync(pkgJsonPath, "utf8");
  • 读取本地文件
    dsh-im-bridge-workspaces/lib/index.js:8168
    return existsSync(binJs) ? binJs : void 0;
  • 读取本地文件
    dsh-im-bridge-workspaces/lib/index.js:8186
    for (const name of names) if (existsSync(join(dir, name))) return true;
  • 写入本地文件
    dsh-im-bridge-workspaces/lib/index.js:8220
    mkdirSync(shimDir, { recursive: true });
  • 写入本地文件
    dsh-im-bridge-workspaces/lib/index.js:8222
    writeFileSync(join(shimDir, "wecom-cli.cmd"), `@echo off\r\necho ${WECOM_CLI_SHIM_DENY_MESSAGE}\r\nexit /b 1\r\n`, "utf8");
  • 读取本地文件
    dsh-im-bridge-workspaces/src/index.ts:651
    return readFileSync(config.personaFile, 'utf8')
  • 读取本地文件
    dsh-im-bridge-workspaces/src/index.ts:660
    return stripLeadingHashComments(readFileSync(file, 'utf8'))
  • 读取本地文件
    dsh-im-bridge-workspaces/src/index.ts:856
    raw = readFileSync(file, 'utf8')
  • 写入本地文件
    dsh-im-bridge-workspaces/src/index.ts:899
    mkdirSync(dirname(file), { recursive: true })
  • 写入本地文件
    dsh-im-bridge-workspaces/src/index.ts:901
    writeFileSync(tmp, `${JSON.stringify(payload, null, 2)}\n`, 'utf8')
  • 写入本地文件
    dsh-im-bridge-workspaces/src/index.ts:902
    renameSync(tmp, file)
  • 读取本地文件
    dsh-im-bridge-workspaces/src/index.ts:1821
    if (!existsSync(target) || !statSync(target).isDirectory()) {
  • 读取本地文件
    dsh-im-bridge-workspaces/src/index.ts:1821
    if (!existsSync(target) || !statSync(target).isDirectory()) {
  • 写入本地文件
    dsh-im-bridge-workspaces/src/index.ts:2109
    mkdirSync(dirname(file), { recursive: true })
  • 写入本地文件
    dsh-im-bridge-workspaces/src/index.ts:2110
    appendFileSync(file, `${line}\n`, 'utf8')
  • 读取本地文件
    dsh-im-bridge-workspaces/src/reply-images.ts:160
    size = statSync(real).size
  • 读取本地文件
    dsh-im-bridge-workspaces/src/reply-images.ts:171
    buffer = readFileSync(real)
  • 写入本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:323
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:426
    mkdirSync(dest, { recursive: true })
  • 读取本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:430
    if (existsSync(skillDir)) rmSync(skillDir, { recursive: true, force: true })
  • 删除本地文件递归
    dsh-im-bridge-workspaces/src/wecom-cli.ts:430
    if (existsSync(skillDir)) rmSync(skillDir, { recursive: true, force: true })
  • 写入本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:438
    mkdirSync(dirname(target), { recursive: true })
  • 写入本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:439
    writeFileSync(target, entry.data)
  • 读取本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:608
    const raw = readFileSync(pkgJsonPath, 'utf8')
  • 读取本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:613
    return existsSync(binJs) ? binJs : undefined
  • 读取本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:633
    if (existsSync(join(dir, name))) return true
  • 写入本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:674
    mkdirSync(shimDir, { recursive: true })
  • 写入本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:676
    writeFileSync(
  • 读取本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:998
    if (!existsSync(dir)) return []
  • 读取本地文件
    dsh-im-bridge-workspaces/src/wecom-cli.ts:1001
    entries = readdirSync(dir, { withFileTypes: true })
  • 读取本地文件
    dsh-plugin-memx/lib/index.js:38
    source: stripTypeScriptTypes(readFileSync(path, "utf8"), { mode: "transform" }),
  • 读取本地文件
    dsh-plugin-product-subagents/lib/availability.js:44
    const present = candidates.some((p) => existsSync(p))
  • 读取本地文件
    dsh-plugin-product-subagents/lib/availability.js:51
    return existsSync(path)
  • 读取本地文件
    dsh-plugin-product-subagents/lib/registry.js:29
    const raw = readFileSync(path, 'utf8')
  • 写入本地文件
    dsh-plugin-product-subagents/lib/registry.js:39
    mkdirSync(dirname(path), { recursive: true })
  • 写入本地文件
    dsh-plugin-product-subagents/lib/registry.js:41
    writeFileSync(tmp, JSON.stringify(cache, null, 2))
  • 写入本地文件
    dsh-plugin-product-subagents/lib/registry.js:42
    renameSync(tmp, path)
  • 读取本地文件
    dsh-plugin-product-subagents/lib/roles.js:30
    for (const file of readdirSync(rolesDir)) {
  • 读取本地文件
    dsh-plugin-product-subagents/lib/roles.js:34
    const raw = JSON.parse(readFileSync(join(rolesDir, file), 'utf8'))
  • 执行外部命令来自配置/变量
    dsh-plugin-product-subagents/lib/run.js:32
    if (!IS_WIN) return spawn(command, args, options)
  • 执行外部命令固定命令
    dsh-plugin-product-subagents/lib/run.js:33
    return spawn('cmd.exe', winArgs(command, args), { ...options, windowsVerbatimArguments: true })
  • 执行外部命令来自配置/变量
    dsh-plugin-product-subagents/lib/run.js:37
    if (!IS_WIN) return spawnSync(command, args, options)
  • 执行外部命令固定命令
    dsh-plugin-product-subagents/lib/run.js:38
    return spawnSync('cmd.exe', winArgs(command, args), { ...options, windowsVerbatimArguments: true })
  • 发起网络请求
    dsh-prompt-optimizer/lib/client.js:698
    const resp = await fetch(ROUTE, {
  • 发起网络请求
    dsh-prompt-optimizer/lib/client.js:1307
    const resp = await fetch("/dsh-prompt-optimizer/test-model", {
  • 发起网络请求
    dsh-prompt-optimizer/lib/controller.js:322
    const resp = await fetch(ROUTE, {
  • 执行外部命令来自配置/变量
    dsh-subagents/lib/bridge-cli.js:54
    const result = spawnSync(bin, args, {
  • 写入本地文件
    dsh-subagents/lib/cli.js:137
    writeFileSync(flags.out, `${JSON.stringify(payload, null, 2)}\n`, 'utf8')
  • 写入本地文件
    dsh-subagents/lib/cli.js:199
    writeFileSync(tmpFile, `${JSON.stringify(record, null, 2)}\n`, 'utf8')
  • 写入本地文件
    dsh-subagents/lib/cli.js:200
    renameSync(tmpFile, flags.record)
  • 读取本地文件
    dsh-subagents/lib/cli.js:218
    const request = JSON.parse(readFileSync(flags.request, 'utf8')).request
  • 写入本地文件
    dsh-subagents/lib/cli.js:232
    writeFileSync(flags.out, text, 'utf8')
  • 读取本地文件
    dsh-subagents/lib/cli.js:242
    const request = JSON.parse(readFileSync(flags.request, 'utf8')).request
  • 写入本地文件
    dsh-subagents/lib/cli.js:245
    writeFileSync(flags.out, text, 'utf8')
  • 读取本地文件
    dsh-subagents/lib/cli.js:274
    payload = JSON.parse(readFileSync(file, 'utf8'))
  • 读取本地文件
    dsh-subagents/lib/cli.js:318
    if (existsSync(canonical)) {
  • 执行外部命令固定命令
    dsh-subagents/lib/cli.js:399
    const out = spawnSync('gh', ['pr', 'view', String(flags.pr), '--json', 'headRefOid'], {
  • 读取本地文件
    dsh-subagents/lib/cli.js:416
    if (!existsSync(flags.record)) throw gate(`找不到审核记录 ${flags.record}(用 --no-review 显式跳过)`)
  • 写入本地文件
    dsh-subagents/lib/cli.js:530
    writeFileSync(requestFile, `${JSON.stringify({ request }, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 })
  • 删除本地文件递归
    dsh-subagents/lib/cli.js:547
    rmSync(tmpDir, { recursive: true, force: true })
  • 读取本地文件
    dsh-subagents/lib/cli.js:567
    const text = renderCard(JSON.parse(readFileSync(flags.input, 'utf8')))
  • 执行外部命令固定命令
    dsh-subagents/lib/cli.js:592
    const out = spawnSync('git', ['remote', 'get-url', 'origin'], { encoding: 'utf8', cwd })
  • 执行外部命令固定命令
    dsh-subagents/lib/cli.js:609
    const out = spawnSync('gh', ['repo', 'view', '--json', 'nameWithOwner', '-q', '.nameWithOwner'], {
  • 执行外部命令固定命令
    dsh-subagents/lib/cli.js:624
    const out = spawnSync('gh', command.args, {
  • 读取本地文件
    dsh-subagents/lib/provider.js:283
    if (existsSync(join(dir, bin))) return true
  • 读取本地文件
    dsh-subagents/lib/record-bridge.js:68
    const cli = tried.find((candidate) => existsSync(candidate))
  • 执行外部命令来自配置/变量
    dsh-subagents/lib/record-bridge.js:133
    const result = spawnSync(cli, args, { encoding: 'utf8' })
  • 执行外部命令固定命令
    dsh-subagents/lib/record.js:25
    const result = spawnSync('git', ['worktree', 'list', '--porcelain'], { cwd, encoding: 'utf8' })
  • 读取本地文件
    dsh-subagents/lib/record.js:54
    return JSON.parse(readFileSync(file, 'utf8'))
  • 读取本地文件
    dsh-subagents/lib/record.js:71
    if (!existsSync(file)) return empty
  • 读取本地文件
    dsh-subagents/lib/record.js:73
    const stored = JSON.parse(readFileSync(file, 'utf8'))
  • 写入本地文件
    dsh-subagents/lib/record.js:93
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    dsh-subagents/lib/record.js:94
    writeFileSync(circuitFile(dir), `${JSON.stringify(state, null, 2)}\n`, 'utf8')
  • 写入本地文件
    dsh-subagents/lib/record.js:100
    mkdirSync(skipDir, { recursive: true })
  • 写入本地文件
    dsh-subagents/lib/record.js:102
    writeFileSync(
  • 读取本地文件
    dsh-subagents/lib/record.js:112
    if (!existsSync(dir)) return []
  • 读取本地文件
    dsh-subagents/lib/record.js:114
    for (const entry of readdirSync(dir)) {
  • 读取本地文件
    dsh-subagents/lib/record.js:117
    const record = JSON.parse(readFileSync(join(dir, entry), 'utf8'))
  • 执行外部命令来自配置/变量
    dsh-subagents/lib/request.js:31
    const result = spawnSync(bin, args, { cwd, encoding: 'utf8', timeout, env, maxBuffer: 64 * 1024 * 1024 })
  • 读取本地文件
    dsh-subagents/lib/request.js:85
    if (!existsSync(path)) {
  • 读取本地文件
    dsh-subagents/lib/request.js:89
    return readFileSync(path)
  • 读取本地文件
    dsh-subagents/lib/roles.js:38
    if (!existsSync(dir)) return { roles, skipped }
  • 读取本地文件
    dsh-subagents/lib/roles.js:39
    for (const entry of readdirSync(dir).sort()) {
  • 读取本地文件
    dsh-subagents/lib/roles.js:43
    const raw = JSON.parse(readFileSync(file, 'utf8'))
  • 读取本地文件
    dsh-subagents/lib/shard.js:279
    if (!existsSync(dir)) {
  • 读取本地文件
    dsh-subagents/lib/shard.js:286
    for (const name of readdirSync(dir).sort()) {
  • 读取本地文件
    dsh-subagents/lib/shard.js:307
    record = JSON.parse(readFileSync(file, 'utf8'))
  • 写入本地文件
    dsh-subagents/lib/shard.js:458
    writeFileSync(tmp, `${JSON.stringify(record, null, 2)}\n`, 'utf8')
  • 写入本地文件
    dsh-subagents/lib/shard.js:459
    renameSync(tmp, target)
  • 读取本地文件
    dsh-subagents/lib/shard.js:479
    record = JSON.parse(readFileSync(target, 'utf8'))
  • 写入本地文件
    dsh-subagents/lib/shard.js:498
    writeFileSync(tmp, `${JSON.stringify(sharded, null, 2)}\n`, 'utf8')
  • 写入本地文件
    dsh-subagents/lib/shard.js:499
    renameSync(tmp, target)
  • 删除本地文件
    dsh-subagents/lib/shard.js:501
    rmSync(tmp, { force: true })
  • 读取本地文件
    dsh-usage-panel/lib/index.js:600
    await access(filePath);
  • 读取本地文件
    dsh-usage-panel/lib/index.js:616
    const stream = createReadStream(filePath, { encoding: "utf8" });
  • 发起网络请求
    dsh-usage-panel/lib/index.js:770
    const req = lib.request(
  • 读取本地文件
    dsh-usage-panel/lib/index.js:1034
    const entries = await readdir(backupsDir, { withFileTypes: true });
  • 读取本地文件
    dsh-usage-panel/lib/index.js:1150
    raw = await readFile(filePath, "utf8");
  • 读取本地文件
    dsh-usage-panel/lib/index.js:1230
    raw = await readFile2(filePath, "utf8");
  • 读取本地文件
    dsh-usage-panel/lib/index.js:1296
    const info = await stat(filePath);
  • 发起网络请求
    dsh-zhihu-sidebar/extension/content.js:13
    const response = await fetch(url, {
  • 发起网络请求
    dsh-zhihu-sidebar/lib/client.js:843
    return fetch(url, init)
扫描于 2026/11/4(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

自研 DeepSeek Harness (dsh) 插件集合 — 目前收录 dsh-auto-upgrade:Web UI 自动检测升级 + 兼容性预检 + 一键备份/安装/校验/重启

README

由 DeepSeek 最新模型翻译生成
self-dsh-plugins 为 DeepSeek Harness(dsh)自研的插件集合。 目前收录 1 个插件。 | 插件 | 说明 | 状态 | | dsh-auto-upgrade | dsh Web UI 自升级:检测 → 兼容性预检 → 非阻塞浮层 → 一键备份 / 安装 / 校验 / 重启 | 可用(真机升级链路待验证) | dsh-auto-upgrade 给 dsh 的 Web UI 加一个自升级入口:当天首次打开页面时自动检测 dsh 新版本与已装插件的兼容性,用一个不打断当前工作的浮层提示;用户点「升级」后才走完整链路。 设置页 浮层 它做什么 1. 当天首次打开自动检测:宿主按本地日期幂等,同一天多标签页/刷新只真正检测一次。 2. 检测两件事:npm 上的 dsh 新版本;已装插件对目标版本的兼容性(用官方 evaluatePluginCompatibility,不是自己写范围匹配)。 3. 不打断工作的浮层:右下角卡片,只占自己的位置;可「稍后」「不再提示」。 4. 点升级才动手:会话门禁 → 插件门禁 → 备份 ~/.dsh → 停服 → npm install -g → 对版 + 组合冒烟 → 重启交接。 5. 回滚与重启:重装指定旧版本;或只重启服务。设置页还有本机体检、插件兼容表、升级/重启日志。
展开完整文档(README 剩余 1 节)
self-dsh-plugins

为 DeepSeek Harness(dsh)自研的插件集合。

目前收录 1 个插件。

| 插件 | 说明 | 状态 |
| dsh-auto-upgrade | dsh Web UI 自升级:检测 → 兼容性预检 → 非阻塞浮层 → 一键备份 / 安装 / 校验 / 重启 | 可用(真机升级链路待验证) |

dsh-auto-upgrade

给 dsh 的 Web UI 加一个自升级入口:当天首次打开页面时自动检测 dsh 新版本与已装插件的兼容性,用一个不打断当前工作的浮层提示;用户点「升级」后才走完整链路。

设置页

浮层

它做什么

1. 当天首次打开自动检测:宿主按本地日期幂等,同一天多标签页/刷新只真正检测一次。
2. 检测两件事:npm 上的 dsh 新版本;已装插件对目标版本的兼容性(用官方 evaluatePluginCompatibility,不是自己写范围匹配)。
3. 不打断工作的浮层:右下角卡片,只占自己的位置;可「稍后」「不再提示」。
4. 点升级才动手:会话门禁 → 插件门禁 → 备份 ~/.dsh → 停服 → npm install -g → 对版 + 组合冒烟 → 重启交接。
5. 回滚与重启:重装指定旧版本;或只重启服务。设置页还有本机体检、插件兼容表、升级/重启日志。

安装

dsh plugin --profile web add <本仓库路径>/dsh-auto-upgrade

本机 profile 是 patchReload: live,装完不用重启 dsh web;刷新页面即可看到浮层与设置页。
卸载:dsh plugin --profile web remove dsh-plugin-auto-upgrade。

两条门禁(默认策略)

| 情况 | 行为 |
| 有会话正在执行 | 409,前端弹警告;用户确认后可带 force 继续(仅警告) |
| 目标版本与已装插件不兼容 | 409,拒绝升级且不可绕过——先升级/移除那个插件,或为它写精确版本豁免 |

豁免是按「插件@版本 → dsh 版本」精确匹配的:compatibility.json 里为 0.2.0-rc.2 写的豁免,在升级到别的版本时自动失效,于是那个插件会立刻出现在「不兼容」里。这正是本插件要提前告诉你的信息。

关键设计

- 双面插件,无构建步骤:宿主半边 lib/index.js 用 cordis 注册 /api/dsh-auto-upgrade/ 路由族;浏览器半边 lib/client.js 手写并包在 window.__ModuleLoader__.load({id, factory}) 里,注册 shell.overlay 浮层与 settings.section 设置页。
- 变更必须脱离进程:npm install -g 覆盖的正是宿主此刻在运行的那棵树,而「停服」就是杀掉宿主自己。
所以宿主只做「门禁 → 备份 → 落 payload → fork detached helper → exit 0」,停服/安装/对版/冒烟/拉起都在生成的 POSIX sh helper 里。exit 0 是刻意的:LaunchAgent 是 KeepAlive{SuccessfulExit:false},非零退出会被 launchd 再拉一次;helper 拉起时若发现 XPC_SERVICE_NAME 对应的 job 仍在,就用 launchctl kickstart -k,让服务继续留在 launchd 名下。
- 用「运行时那份」官方 API:@deepseek-ai/dsh-app-boot 不在 profile 的解析范围里,pnpm 只会再装一份副本。插件用 ctx.profileContext.installAnchor 推出宿主此刻真正执行的模块绝对路径再动态 import。
- 故意不声明 @deepseek-ai/dsh peerDependencies:否则升级之后,平台闸门会把「负责升级 dsh 的插件」自己判成不兼容(自锁)。本包只声明 react(浏览器半边需要)。
- 安全边界:路由族能读 npm、重写全局安装树、覆盖 ~/.dsh、结束本进程,所以一律 loopback-only (socket 地址为准,不信任 X-Forwarded-For),并且有副作用的一律 POST。
- UI 吃 dsh 的设计 token:字体 --dsw-font-、圆角 --dsw-radius-、语义色 --dsw-alias-state-、开关逐字照 primitives Switch.module.css,按钮尺寸照官方设置页规则(36px / 0 14px / bg-module-platform)。
详见包内 README 的「UI 风格契约」。

状态目录

$HOME/.dsh-auto-upgrade/(可用 DSH_AUTO_UPGRADE_DIR 改写):

- state.json — 当天检查记录、上次检测结果
- policy.json — {channel, exactVersion, mode, dailyCheck}
- settings.json — {overlay, dismissed, locale}
- restart.log / result.json / helper-payload.json — 升级交接的日志、结果与完整输入

开发

包由 pnpm 管理(.npmrc 指向共享 store):

cd dsh-auto-upgrade
pnpm install # 只有 react 一个 peer,会复用共享 store
node --check lib/index.js lib/client.jsbash
node --test "test/.test.mjs" # 35 用例

测试里没有 mock 掉关键路径:路由跑真 node:http + 假 npm registry;兼容性判定跑真官方 API;升级 helper 用假 npm/dsh/launchctl + 真 /bin/sh 跑生成的脚本;浏览器半边用假 ModuleLoader + 假 react 装载。

文档

- 设计:接口清单 + 数据流图 + 拍板结论
- 验收报告:逐条证据 + 明确没验证什么
- 包内 README

已知限制(诚实清单)

- 真机的安装/升级/重启链路尚未执行(属于需要用户点头的闸门);只读半边与门禁已在真机验证。
- 只支持 macOS / Linux:helper 是 POSIX sh 脚本。
- GET /notes(release notes)与 POST /plugins/action(写豁免/禁用插件)尚未接线,如实返回 501。
- 暂不做「静默自动升级」:policy.mode 只接受 notify。

License

MIT
预览分享卡片长什么样 ↓guraul/self-dsh-plugins
分享 · DeepSeek Harness Hub
guraul/self-dsh-plugins

检测新版本并预检兼容性,一键备份升级重启

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部