dsh-plugin-toggle

August 25, 2026 · View on GitHub

DeepSeek Harness (DSH) 的设置 → 插件页面直接启用/停用插件:新增一个「启用/停用」标签页,位于只读的「插件列表」旁边。拨动开关即时停止/启动插件(无需重启),并持久化到配置文件,重启后依旧生效。

English: README.md · LLM 索引: llms.txt · Agent 指南: AGENTS.md

dsh-plugin DeepSeek Harness license install

关键词 / Keywords: dsh-plugin · deepseek-harness-plugin · plugins · settings · enable · disable · toggle · loader · 插件 · 启用 · 停用


📑 目录


✨ 特性

特性说明
🎚️ 启用/停用标签页设置 → 插件 中新增标签页(id toggle,顺序 20),位于自带的只读「插件列表」旁边——不覆盖自带页面
🔄 即时切换拨动开关即调用 Cordis Loader 的 Entry.update({disabled})——插件 fiber 立刻被销毁(停用)或启动(启用),无需重启 DSH
💾 重启常驻每次变更都会追加到 profile 自己的 cordis.patch.yml(官方用户补丁层),重启后状态依旧生效
📊 状态一目了然每行显示插件名、启用/停用标签、Cordis 阶段(active / pending / failed / not mounted)
🔒 安全防护loader 的 include 条目与本插件自身被锁定;未知 id 返回 404,锁定 id 返回 403
🛡️ 只读列表GET 返回与自带插件列表相同的 Loader 投影(entryIdmoduleNameenabledfiberPhase)——无需 Remote 通道
🌗 主题自适应全部颜色使用 --dsw-alias-* 设计令牌,亮/暗色自动跟随
♨️ 重启常驻真实 profile 打包插件:dsh plugin add 安装一次,每次 DSH 启动自动加载 —— 无需 cordis_define、无需每次重装

🏗️ 工作原理

设置 → 插件 → 「启用/停用」标签页(新增,id `toggle`)

Client 半区(浏览器)              ▼
  └─ fetch GET /plugin-toggle/api → loader 条目列表
  └─ 每行一个插件:名称 + 启用/停用标签 + Cordis 阶段 + 开关
  └─ 拨动开关 → fetch POST /plugin-toggle/api { entryId, disabled }

Host 半区(DSH 进程内)            ▼
  └─ webServer 路由 POST /plugin-toggle/api
  └─ loader.resolve(entryId).update({ disabled })
       └─ 销毁 fiber(停用)或启动(启用)——即时生效,无需重启
  └─ 向 profile 的 cordis.patch.yml 追加 `- id: <rawId>` / `disabled: <bool>`
       (用户补丁层,在所有 bundle 层之后应用 → 启动时生效)
  └─ 返回 { ok, entryId, disabled, fiberPhase, persisted }

Client 半区(浏览器)              ▼
  └─ toast:「已停用 <插件>」/「已启用 <插件>」(或错误信息)→ 刷新列表
  • 即时与持久化解耦Entry.update()(条目级)不会把 loader 树写回 cordis.yml——即时效果只存在于内存,持久化仅靠追加 cordis.patch.yml。不会打平补丁、不会产生重复行。
  • 补丁语义cordis.patch.yml 的行是按 id 定向的覆盖;后写者生效,因此重新启用时追加 disabled: false 覆盖之前的 true 即可。
  • 持久化:随包声明 dsh.bundlecordis.patch.yml)+ dsh.clientexports["./client"] 打包产物),作为真实 profile 插件安装,DSH client-modules 每次启动都会扫描加载。

🚀 快速开始

标准安装:dsh plugin add(重启常驻)

从本仓库安装:

# 本地目录(在本仓库父目录执行):
dsh plugin --profile web add ./dsh-plugin-toggle

# 或直接从 GitHub(任意 DSH 机器):
dsh plugin --profile web add github:Zenjibad/dsh-plugin-toggle
# 或:
dsh plugin --profile web add git+https://github.com/Zenjibad/dsh-plugin-toggle.git

dsh plugin add = 向 profile 做 pnpm add + dsh.profile.bundles 协调:识别到本包的 dsh.bundle 声明后,把 dsh-plugin-toggle 追加进 bundle 栈。重启 DSH,然后硬刷新浏览器标签页Ctrl+F5)。启动时 client-modules 扫描器解析 exports["./client"],新标签页出现在设置 → 插件。无需 cordis_define,重启后依旧。

⚠️ 注意:安装(或更新)客户端插件后必须硬刷新页面Ctrl+F5)——DSH 客户端 HMR 只会热替换已加载的 bundle,不会把新增的 bundle 注入已打开的标签页。

手动挂载(备选)

  1. git clone https://github.com/Zenjibad/dsh-plugin-toggle.git(任意位置)。
  2. ~/.dsh/profiles/web/package.jsondependencies"dsh-plugin-toggle": "link:<仓库路径>",然后在 profile 目录 pnpm install
  3. 重启 DSH。

使用前提

  • 运行中的 DSH web profile(dsh --profile web),loader 处于活动状态——标签页读取并切换其条目。
  • 停用被其他插件依赖的插件会让依赖方进入 pending;重新启用即可恢复(标准 Loader 行为)。

⚙️ 配置

无配置文件、无持久化设置。行为由源码中的常量固定:

可调项位置默认值
HTTP 路由src/index.ts`GET
锁定条目src/index.ts 中的 LOCKED / LOCKED_NAMESincludecordis:includedsh-plugin-toggle
标签页席位src/client/index.tsxsettings.plugins.tab id toggle,顺序 20
Toast 时长src/client/index.tsx6 秒
持久化目标由 loader 的 include 条目推导<profile>/cordis.patch.yml

❓ 常见问题

Q: 「启用/停用」标签页不见了? A: 先重启 DSH(如果 Host 半区尚未挂载),再硬刷新浏览器标签页Ctrl+F5)。新增的客户端 bundle 只有整页刷新才会加载——HMR 不会把新 bundle 加进已打开的标签页。

Q: 我停用了插件但它还在运行? A: 切换是即时的——Entry.update({disabled}) 会立刻销毁 fiber。若某个依赖插件继续提供同一服务,那是它自身的行为;请查看该行的阶段(应显示「Not mounted」)。

Q: 变更能跨重启保留吗? A: 可以。每次切换都会向 profile 的 cordis.patch.yml(官方用户补丁层,在所有 bundle 层之后应用)追加 - id: <条目> / disabled: <布尔值>。若追加失败,toast 会提示「未持久化,重启后失效」,仅影响当前会话。

Q: 为什么有些条目不能切换? A: loader 的 include 条目与本插件自身被锁定(403);未知 id 返回 404。其余条目(包括 @deepseek-ai/dsh-* host 插件)都可切换;停用某个服务提供方会让依赖方进入 pending,重新启用即可恢复。

Q: 停用插件会卸载它吗? A: 不会——只是停止 Loader 条目并追加一条 disabled 覆盖。包仍保持安装;重新启用即可再次启动。

Q: 如何移除本插件本身? A: dsh plugin --profile web rm dsh-plugin-toggle(或删除 profile 依赖与 bundle 条目)后重启 DSH。注意:如果你之前停用过其他插件,它们的 cordis.patch.yml 行会保留(那是独立的持久化层)。

⚠️ 安全须知

  • 无 Remote 通道、不写 loader 配置:客户端只调用同源 /plugin-toggle/api 路由;Host 从不写 cordis.yml 或任何 bundle 补丁——只向 profile 自己的用户补丁层追加行。
  • 输入校验entryId 必须在 loader 中可解析;锁定 id(include、自身)返回 403;未知 id 返回 404
  • 小载荷:POST 请求体上限 1 MB。
  • 即时停止是设计意图:停用插件会立刻销毁其 fiber——与 cordis_stop 相同;重新启用会重启它。

📦 项目结构

dsh-plugin-toggle/
├── src/
│   ├── index.ts            # host 半区:列表投影、loader.resolve().update()、cordis.patch.yml 追加、路由
│   └── client/index.tsx    # client 包:启用/停用标签页、开关、toast
├── cordis.patch.yml        # dsh.bundle patch(启动时插入插件行)
├── tsdown.config.ts        # 打包 host(node ESM)+ client(CJS ModuleLoader)
├── package.json            # name、exports["./client"]、dsh.client + dsh.bundle
├── lib/                    # 构建产物(index.js、client.js)
├── AGENTS.md               # AI agent 仓库指南
├── llms.txt / llms-full.txt
├── README.md / README.zh.md
└── LICENSE

🙏 致谢

  • DeepSeek Harness — DSH 插件/动态运行时、Cordis Loader、Slots、主题、webServer、client-modules。
  • headroom-stats-plugin — 打包式 client 插件构建模式参考(tsdown host/client 拆分、cordis.patch.ymldsh.client)。
  • dsh-drop-any-file — 兄弟插件;相同打包模式与文档套件。

Repo

GitHub

一个打包式 DSH profile 插件——需要 DeepSeek Harness(Node >= 18)、web profile 与 Cordis Loader。

📄 License

MIT