- Home
- Plugins
- Dev & Plugin Tools
- dsh-fusion
dsh-fusion
mouyu6508-hue/dsh-fusion
Reports conflicting DeepSeek Harness plugin composition — duplicate loader names across bundles (install-shadow), one id given two names, enable/disable fights, and config keys silently overwritten by a later layer — then emits a patch with the final merged values. Ships a CLI that runs when DSH itself will not boot, plus a fusion_report tool that reads the live loader.
Install
dsh plugin --profile web add github:mouyu6508-hue/dsh-fusionREADME
dsh-fusion
English | 中文
Conflict detection and config fusion for DeepSeek Harness plugin composition — find the duplicate loader that keeps your profile from booting, and merge the config that a later layer silently overwrites.
DeepSeek Harness builds a profile in layers: the root cordis.yml → every bundle's cordis.patch.yml → the profile's own cordis.patch.yml. The more plugins you install, the more two things start happening — and neither is obvious:
- The same loader gets mounted twice across bundles. The plugin market reports it as
install-shadow, for example:@tt-a1i/archify-dsh introduced cross-layer duplicate loader names — @deepseek-ai/dsh-skill-filesystem (@deepseek-ai/dsh-base + @tt-a1i/archify-dsh) - The same config key gets silently overwritten by a later layer. No error, no log. You think your value took effect; it didn't.
dsh-fusion surfaces both: it reads the real layer stack, shows who overrode whom, and emits one patch containing only the final merged values.

Install
From GitHub (current distribution):
dsh plugin --profile web add github:mouyu6508-hue/dsh-fusion
On the desktop client, paste the repository URL into Settings → Plugins.
If this ever lands on npm, the command becomes
dsh plugin --profile web add dsh-fusion.
CLI (works even when DSH won't boot)
dsh-fusion scan # what's fighting in this profile?
dsh-fusion scan --profile web --json # machine-readable
dsh-fusion fuse # print the fused patch
dsh-fusion fuse --fix --write # keep one copy of a duplicate, write cordis.fusion.yml
Real output from the bundled demo profile:
profile: examples/conflict-profile
bundles: 3 | layers: 5 | entries: 3
conflicts: 1 | silent overrides: 2
[conflict] same loader mounted 2 times: @deepseek-ai/dsh-skill-filesystem
ids skill-filesystem, archify-skill-filesystem (from @deepseek-ai/dsh-base + @tt-a1i/archify-dsh).
the module runs twice; tools/services get registered twice or shadow each other
[override] dsh-dafeiyu config key scale overridden by profile:cordis.patch.yml
1 → 0.55
fuse --fix turns the first one into a patch you can apply directly:
- id: archify-skill-filesystem
disabled: true
--prefer <id> picks which copy to keep (default: the first one mounted, i.e. the base layer).
The fusion_report tool
Installing the plugin adds one tool:
| Parameter | Meaning |
|---|---|
profile | profile name to inspect (default desktop) |
dir | profile directory instead of a name |
write | also write cordis.fusion.yml (default: report only) |
It looks at two sources:
- Static — the layered patch files. Useful before the host is even running.
- Runtime — asks
ctx.loaderwhich entries are actually mounted. Some duplicates only appear at runtime: the plugin's patch file is clean, and it mounts a second copy of a module duringapply(). The case above is exactly that — file inspection alone never finds it.
If the host doesn't expose the loader, it degrades to static-only instead of failing.
What it reports
| Kind | Severity | Meaning |
|---|---|---|
duplicate-name | conflict | the same loader is mounted on 2+ rows; the module runs twice |
name-mismatch | conflict | one id given two different names by two layers |
disabled-conflict | conflict | one layer enables, another disables |
unknown-target | conflict | a patch targets an id nobody inserted (the row is silently dropped) |
config-override | override | a config key overwritten by a later layer |
repeat-row | notice | same id + same name written twice (normal way the market saves settings) |
dynamic-config | notice | config contains !!js expressions; can't be merged statically |
What it does not do
- It never changes running plugins. Read-only against the loader; no enable/disable. Auto-fixing a live graph breaks worse than it heals.
- It never removes rows. The fused patch only pins final values; you decide which duplicate to drop (
--fixwrites thedisabled: truefor you). - It never touches the system prompt. A fusion tool shouldn't add more noise to it.
- It never executes
!!js. Expressions are kept as text; rows that can't be merged are skipped and named in the output.
Requirements
- Node.js 18+
- A DSH host that loads bundle plugins (
dsh.bundle.patch) - Linux, macOS and Windows are all fine
Development
node --test # or run test files directly (the runner spawns children, which some sandboxes block)
node bin/fusion.js scan --dir examples/conflict-profile
lib/core.js— pure functions: parse, detect, deep-merge, emitlib/profile.js— filesystem only: read the profile layers in real orderlib/runtime.js— loader only: read what's actually mountedlib/index.js— plugin entry: registersfusion_report
Search terms
dsh plugin conflict · install-shadow · duplicate loader entry · profile patch merge · cordis patch layer · silent config override · DSH 插件冲突
MIT
Related plugins
deepseek-harness
deepseek-ai/deepseek-harness
dsh-market
dsh-market/dsh-market
dsh-web (dsh-plugin-manager)
zhu1090093659/dsh-web
dsh-web
zhu1090093659/dsh-web