让一个 DSH 插件在运行时改写其它已安装插件的编译产物,而不必维护 fork。
- 语言
- TypeScript
- License
- MIT
- 分支
- main
安装
$ dsh plugin --profile web add dsh-harmony在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
对话式安装
帮我安装 DeepSeek Harness 插件 CH4ACKO3/dsh-harmony:先查看仓库 https://github.com/memorax-ai/dsh-harmony 确认安全性,然后执行安装命令并验证插件加载成功。
把这段指令粘贴给 DSH Web GUI 里的助手,由它代你完成安装与验证。
一句话定位
dsh-harmony 是一个 DSH 插件市场中的"插件改写器",让一个插件可以在运行时改写、替换或装饰其它已安装插件的编译产物,而无需维护 fork 或修改 node_modules。
核心能力
- 在 DSH 启动前对目标插件的 TypeScript 源码做内存改写,Patch 串行执行,后一个读取前一个的结果
- 同时支持 Source(源码)、Semantic(语义)、Loader(加载器)和 Composite(组合)四类 Patch,可覆盖 React 组件、Loader 条目与共享函数定义
- 提供 Provider 与 Patch 两级粒度的
before/after顺序约束,用户可在 WebUI、TUI 或 CLI 中拖动和重排 - 失败隔离:独立 Patch 失败会被跳过并报告;Composite Patch 任意成员失败则整体不应用,不影响 Host 与其它 Patch
- 在 WebUI 的"设置 → Harmony"中加入 Patch 状态页与拖拽排序面板,支持原始/中间/最终三段源码查看与 Diff
- 通过 CLI 与 TUI 对运行中的 Host 进行事务式修改:
status、inspect、enable、disable、patch-order、provider-order、reload等
技术实现
- 语言: TypeScript(ESM,主仓库与
packages/react子包均为type: "module") - 关键依赖:
@phenomnomnominal/tsquery(TS AST 查询)、magic-string(源码区间改写)、semver(版本范围校验)、@deepseek-ai/dsh-atomic-write(配置原子写入)、@deepseek-ai/cordis(DSH 的依赖注入运行时) - 架构模式: 双形态部署 ——
bin.ts作为全局dsh-harmony启动器拦截 DSH 入口并在加载模块前安装 Hook;自身又作为 DSH 插件通过cordis的apply(ctx)暴露ctx.harmony服务并启动本地控制 HTTP,监听 Patch 重载、配置文件变更、插件更新事件 - 入口文件:
src/bin.ts(CLI 入口)、src/plugin.ts(DSH 插件 apply/inject)、src/runtime.ts(Provider/Patch 注册与变换)、src/builtins/settings.patch.cts(自带一个设置面板整合 Patch)
适用场景
当你需要修改其它 DSH 插件的内部 UI 组件、Loader 行为或编译后调用,但目标插件没有公开扩展点、不值得为它维护一份 fork 时,dsh-harmony 让你以"运行时改写 + Pin 版本 + expect 校验"的方式声明依赖。需要写一个能改动其它插件 UI 的 Hook 插件时,README 建议你直接对 AI 说"如果使用 dsh-harmony 呢"。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| @deepseek-ai/dsh | 0.1.0-rc.8 或 0.1.1-rc.1 | 通过 peerDependencies 声明;peerDependenciesMeta 标注为可选 |
| Node.js | ^22.22.3 或 >=24.11.1 | engines.node 字段硬性要求 |
| 运行平台 | 跨平台 | 已在 macOS、Windows、Linux 的 CI/打包脚本路径上出现(installer.ts:60-62 处理 Windows 下 cmd.exe 路径) |
| 其它运行依赖 | 内置 | @phenomnomnominal/tsquery、magic-string、semver、yaml、@deepseek-ai/dsh-atomic-write 均为 npm 依赖,不涉及原生模块 |
| 原生模块 | 无 | 不依赖 node-pty、node:sqlite、node-gyp 等 |
安装方式
dsh plugin --profile web add github:CH4ACKO3/dsh-harmony
配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
DSH_HARMONY_PERF | 环境变量 | 设为 1 后,每次启动、插件更新、配置更新和手动重载都会输出一条结构化耗时记录(含 prepare/transform/host-reload/client-rebuild/total) | 未设置 |
DSH_HARMONY_REACT_TRACE | 环境变量 | 设为 1 后,React 组件 Patch 会在中间结果中保留调试 trace,便于检查选择器是否命中 | 未设置 |
DSH_HARMONY_DSH_ENTRY | 环境变量 | 指定一个本地 @deepseek-ai/dsh 入口文件,覆盖默认从 node_modules 解析的路径 | 未设置 |
DSH_HARMONY_IGNORE_ONCE | 内部环境变量 | 当 dsh-harmony 作为插件安装但启动器未启用时,用户在终端/WebUI 选择"本次忽略"会自动写入 1,跳过本进程的 launcher 安装提示 | 未设置 |
DSH_HARMONY_ACTIVE | 内部环境变量 | 由 dsh-harmony 启动器在加载 @deepseek-ai/dsh-app-boot 之前写入 1,让插件 apply 函数识别这是被 Harmony 启动的 DSH 进程 | 由启动器写入 |
dsh.profile.bundles | package.json 字段 | harmony.patch.yml 通过 cordis.patch.yml 把 dsh-harmony 注入到 DSH 的 dsh-harmony bundle;非必要但建议保留 | 由 harmony.patch.yml 提供 |
常见问题
Q: 我只是一个普通用户,需要先学 TypeScript 才能用 dsh-harmony 吗?
A: 不需要。普通用户只需要在 WebUI 的"设置 → Harmony"页查看已注册的 Patch、用拖拽排序、用启用/停用按钮开关;终端用户也可以用 dsh harmony status 查看健康状态。理解 TypeScript AST 是 Patch 作者的工作,不是使用者的工作。
Q: 安装后 dsh web 还是原来的样子,Harmony 没生效怎么办?
A: dsh-harmony 作为插件被 DSH 加载时,apply 函数会调用 waitForRuntimeChoice(ctx),在 WebUI 内弹出对话框让你选择"安装 / 安装并重启 / 移除插件 / 本次忽略"。README 与 installer.ts:106-125 都明确,必须安装全局 dsh-harmony 启动器并重启 DSH,Patches 才会真正生效(plugin.ts:223)。
Q: 改写代码会不会让我装的目标插件升级后挂掉?
A: 不会直接挂,但可能失败。Patch 声明时使用 target.package + target.version(semver 范围)+ select(TSQuery)+ expect(期望匹配数)。当目标升级导致版本不再匹配或匹配数偏离 expect 时,Patch 会被标记为 failed,后续 Patch 与 Host 仍继续运行,但实际改写不会生效(README.md:58、src/runtime.ts:1041-1064 测试)。
Q: 我能同时装多个 Patch 改写同一个文件吗?
A: 可以。全局 patchOrder 决定它们的执行顺序,前一个 Patch 的输出是后一个的输入;Composite Patch 把多个 Patch 绑成一个排序位置和开关,它们要么全部生效要么全部不生效(README.md:40-46、src/runtime.ts:108-111)。
Q: 怎么知道某个 Patch 实际做了什么改写?
A: 用 dsh harmony inspect <package> [--file <file>] [--patch <key>] [--summary],可以打印原始源码、每一步 Patch 的中间结果和最终源码;WebUI 的 Patch 状态页也有同样的可折叠 diff 视图。--summary 模式只输出包/文件与命中数,适合做 CI 校验(src/bin.ts:212-279、browser/client.ts:9-175)。
Q: 我可以用它来改写 DeepSeek 客户端的核心包吗?
A: 可以,但请先在 README 的"Plugin compatibility"声明里填 requires / conflicts / integrates,并在 target.version 中严格钉住版本。Harmony 不会自动安装、启用或停用任何插件,这些声明只用于检测和展示;目标升级后声明的 Patch 会显示为 failed,需要重新审视(README.md:121-149)。
Q: 我装了它之后 DSH 启动变慢了,怎么排查?
A: 启动时设 DSH_HARMONY_PERF=1,每次启动/插件更新/手动重载都会向 stderr 输出一条 JSON 耗时记录,分阶段给出 prepareMs、transformMs、hostReloadMs、clientRebuildMs、totalMs;也可以订阅 Node.js diagnostics_channel 的 dsh-harmony:load 通道。默认情况下这些探针完全关闭,对正常加载路径没有计时开销(README.md:196-202)。
上手难度
进阶 — 普通用户只需在设置页拖拽/开关即可,但编写或审阅自己的 Patch 需要理解 TSQuery 选择器、MagicString 区间改写、patchOrder 与 before/after 约束。
已知问题与限制
- dsh-harmony 不能在自己进程内热重载:尝试
dsh harmony reload dsh-harmony或 Hook 命中 dsh-harmony 自身会抛reloading "dsh-harmony" inside its own runtime is unsafe; restart DSH ...,源码中三处显式拒绝(src/plugin.ts:360-362、580-586、785-787)。 - Composite Patch 内的成员不允许声明
before或after,违反时启动失败(src/runtime.ts:496-498);成员必须保持声明顺序,全部成功才会一起应用。 - Patch 改写的是"已编译后的产物",目标是内部细节而非稳定 API,目标包升级可能让 Patch 失效,需要重新审阅而不是依赖 Harmony 自动迁移(README.md:52-66)。
- 当目标文件不存在、版本不满足或匹配数偏离
expect时,Patch 状态会变成failed并在status输出中可见,不会阻断启动但也不会改写(src/runtime.ts:1145、1276、1503)。 - Desktop 包内置的 Host 不会被全局启动器接管,运行时检测到
DSH_DESKTOP=1时只允许"移除/忽略",不允许"安装"(src/installer.ts:132、184、browser/client.ts 中runtimeDesktopTitle/runtimeDesktopBody文案)。 - 提供者级启用与单个 Patch 启用是两套独立开关:停用整个 Provider 不会清除单个 Patch 的禁用标志,重新启用 Provider 时只恢复此前单独启用的那些 Patch(README.md:113-118)。
dsh-harmony
Runtime Patch coordination for DeepSeek Harness plugins.
A library for patching, replacing and decorating DeepSeek Harness plugins during runtime.
Usage
Just type "What about we use dsh-harmony" when vibe coding your DSH plugin.
Introduction
Use Harmony when one DeepSeek Harness plugin needs to change another without maintaining a fork. Harmony loads Patches before the target runs, changes its compiled code in memory, and starts Harness with the result.
Source Patches find TypeScript AST nodes with TSQuery and rewrite their source ranges with MagicString. They run one after another, each reading the source left by the previous Patch. This lets several plugins change the same target while leaving installed files untouched.
A provider can place its Patches before or after another provider. One Patch may override that rule, and users may interleave Patches from different providers. When several changes must succeed together, a composite Patch gives them one position and one switch; if a member fails, Harmony applies none of them.
For browser plugins, Harmony also keeps provider-owned <style data-plugin> tags in Patch order. A provider owns one style group, so its last enabled Patch decides where that group appears in the CSS cascade. Harmony repeats the ordering after a Patch reload.
Harmony adds modification to the ways DeepSeek Harness plugins can work together.
Why Harmony
Ordinary DSH extension points remain the first choice when the target exposes the behavior you need. Harmony is for the gap between those APIs and maintaining a fork: changing an internal component, loader entry, or compiled behavior that the target does not expose.
| Without Harmony | With Harmony |
|---|---|
| Hide or duplicate an internal UI and keep both implementations aligned | Replace the selected component or compiled call site in place |
Patch node_modules, carry a fork, or reapply edits after upgrades | Transform source in memory; installed package files remain byte-for-byte unchanged |
| Discover a selector drift only after the UI silently breaks | Pin package version and expect; mismatches fail visibly in status |
| Treat the final bundle as a black box | Inspect the original, every Patch step, and the final transformed source |
| Remove custom edits manually | Disable or remove the Provider to restore the original behavior |
Harmony does not turn compiled internals into a stable public API. It makes that dependency explicit, ordered, inspectable, and reversible.
Respect
Inspired by Harmony, the project of the same name created by Andreas Pardeike and other contributors for C#.
AI agents: use the repository skill
Load use-dsh-harmony for installation, Patch selection and authoring, runtime operations, and troubleshooting.
Install
Requires Node.js ^22.22.3 or >=24.11.1 and @deepseek-ai/[email protected].
npm install -g @deepseek-ai/[email protected]
npm install -g dsh-harmony
dsh web
Open Settings → Harmony after starting the WebUI. For profiles, Desktop integration, updates, and removal, see the installation guide.
Use the terminal UI or non-interactive commands against any profile. Commands contact a running Host transactionally and report live; stopped profiles are validated and updated atomically as offline.
Multiple Hosts may use the same profile. Harmony follows DSH Settings' write model: whole-profile writes are serialized by a file lock and committed atomically; a stale UI save is rejected and refreshed, while concurrent processes use last-complete-write-wins semantics.
dsh harmony --profile web
dsh harmony status --json --profile web
dsh harmony disable my-provider/optional-patch --profile web
dsh harmony enable-provider my-provider --profile web
dsh harmony patch-order show --profile web
dsh harmony patch-order move my-provider/optional-patch --before other-provider/base --profile web
dsh harmony patch-order auto --profile web
dsh harmony provider-order move my-provider --after base-provider --profile web
dsh harmony inspect target-package --patch my-provider/optional-patch --summary --profile web
dsh harmony reload my-provider --profile web
Press Tab in the TUI to switch between Provider and Patch views. The Patch view supports individual and Provider-wide enablement, Patch ordering, automatic sorting, runtime details, and concise inspection. Both views keep the selection visible when a profile is larger than the terminal.
status, patch-order show, and provider-order show exit with status 1 when their health or order constraints fail. patch-order auto and provider-order auto minimize violations while preserving the current order where possible. inspect --summary omits transformed source, while --patch <key> limits inspection to targets touched by one Patch. reload requires a running Host.
Patch model
Harmony runs every Patch from one global patchOrder. Provider-level before and after rules set the usual order. A Patch that declares either rule uses its own rules instead. In Settings → Harmony, users can move a whole provider or place one Patch between Patches from another provider. Plugin and Patch details provide their enable and disable actions, while the Patch status page is a read-only runtime monitor. Harmony checks that the saved list contains every registered Patch exactly once.
Plugin-wide disablement is an independent provider/* flag. It never clears or creates individual Patch flags. Re-enabling a plugin therefore restores only the Patches that were individually enabled before the plugin was disabled.
Every Patch may declare a human-readable description. Harmony exposes it through Patch status and JSON output, and displays it in Settings so users can understand the Patch before changing its order or enablement.
A composite Patch groups several Patches under one order position and switch. Members keep their declared order and apply only when every member succeeds. A failed standalone Patch is reported and skipped; later Patches and the Host continue to run.
Plugin compatibility
Any DSH plugin package can describe its relationships with other plugins under dsh.plugin.compatibility, whether or not it provides Harmony Patches:
{
"dsh": {
"plugin": {
"compatibility": {
"requires": {
"base-plugin": "^2.0.0"
},
"conflicts": {
"legacy-plugin": "*"
},
"integrates": {
"optional-renderer": "^1.0.0"
}
}
}
}
}
requires reports a missing, inactive, or incompatible dependency; conflicts warns when an incompatible pair is active; and integrates reports an available optional integration. These declarations never install, enable, disable, or block plugins. Targets are package names and values are semver ranges. Reciprocal conflict declarations produce one warning, and disabling a Harmony Patch does not disable its owning plugin.
Live reports use the plugins active in Loader. When the profile is stopped, Harmony can only inspect its installation and therefore treats installed profile packages as active.
React-aware patches
Install dsh-harmony-react in a Patch provider when the target is compiled React:
npm install dsh-harmony-react
Use element() to change selected compiled jsx / jsxs calls. Use component() to change the shared component definition. Harmony applies both in the same Patch order as every other Source Patch.
| API | Scope |
|---|---|
element() | One or more selected call sites: replace, wrap, insert, transform props, or remove |
component() | Every call through an initialized variable or named function declaration: decorate or replace |
To let later Component Patches modify the same definition, Harmony rewrites a function declaration as an initialized const. The new binding is not hoisted. If the file reads the component before its declaration, use a core Source Patch instead. React integration covers selectors, Inspect traces, and Studio.
Documentation
| Topic | Guide |
|---|---|
| Runtime architecture | What is Harmony? |
| Installation and profiles | Installation |
| Writing source, semantic, loader, and composite Patches | Patch authoring |
| Provider/Patch order, status, inspection, and reload | Operations |
React-aware patches with dsh-harmony-react | React integration |
| Studio previews | Studio integration |
| Commands, limitations, and failures | CLI · Limitations · Troubleshooting |
Powered by Harmony
If your plugin uses Harmony, you’re welcome to use this badge to show your support!
[](https://memorax-ai.github.io/dsh-harmony/)
Development
All maintained implementation code uses TypeScript. Build artifacts are generated for packaging and are not tracked by Git.
Documentation sources and local preview tooling live on the docs branch.
npm test
Set DSH_HARMONY_PERF=1 when starting DSH to log one structured timing record for each Harmony startup, plugin update, profile update, and manual reload:
DSH_HARMONY_PERF=1 dsh web --no-open
Each record separates Patch preparation, source transformation, Host reload, browser rebuild, and total time. The probe stays inactive by default. Node.js diagnostic tools can instead subscribe to the diagnostics_channel channel dsh-harmony:load without enabling log output.
License
查看使用指南 →
该插件的安装步骤、关键要点、FAQ 与兼容性说明(基于已收录字段派生)。
收录徽章
[](https://deepseek-plugin.org/plugins/CH4ACKO3/dsh-harmony)把这段 markdown 粘贴到你的 GitHub README,链接回本插件详情页。徽章只声明已被本站收录,不代表安全认证。