dsh-plugins/dsh-loader
A version‑aware adapter registry that decouples third‑party Cordis plugins from dsh’s internal service names, paths, and RPC internals. 基于版本感知适配器注册表,为 dsh Cordis 插件提供运行时兼容层,使第三方插件与内部服务名、模块路径及 RPC 细节解耦。
项目介绍Project Overview
dshloader 是面向 DSH 插件的运行时兼容垫片,通过版本感知适配器注册表隔离 dsh 内部服务名、模块路径、包名与 RPC 变化,提供 ctx.dshLoader、window.__dshLoader__ 和稳定子路径导入。适用于第三方插件需跨 dsh 升级保持源码不变、避免直接依赖 @deepseek-ai/* 的场景。注意:开启设置白名单绕过会移除浏览器设置访问的默认拒绝边界,仅应在信任所有插件的配置中使用。
dshloader is a runtime compatibility shim for DSH cordis plugins. It uses a version-aware adapter registry to hide changes in dsh service names, module paths, package names, and RPC details, exposing ctx.dshLoader, window.__dshLoader__, and stable import subpaths. Use it when third-party plugins must keep working across dsh upgrades without depending directly on @deepseek-ai/* packages. Caveat: enabling the settings whitelist bypass removes the default-deny boundary for browser settings access.
请帮我了解并安装插件:【dsh-loader】【https://github.com/dsh-plugins/dsh-loader】
把上面这条消息直接发给当前会话里的 DSH,让它帮你了解并安装。安装命令不一定准确,发给 DSH 更稳。Send this message to DSH in your current session. CLI install commands may not be accurate across systems — DSH will figure it out for you.
或使用命令行安装(适合开发者)Or use CLI install (for developers)
命令行安装CLI Install
dsh plugin --profile web add github:dsh-plugins/dsh-loader
把 dsh-plugins/dsh-loader 加入你的 DSH 配置(web profile)即可启用。
READMEREADME

dshloader
A version-aware runtime compatibility shim that keeps third-party plugins working unchanged across dsh (DeepSeek Harness) upgrades.
English
A runtime compatibility shim for dsh (DeepSeek Harness) cordis bundle plugins. dshloader decouples third-party plugins from dsh's internal service names, module paths, package names, and RPC details through a version-aware adapter registry, so that when dsh upgrades and breaks internal APIs, you only upgrade dshloader — plugins keep working unchanged.
Why
dsh is moving fast and its internal surface changes between releases:
httpServerwas renamed towebServer— old plugins that injecthttpServerhang forever.- Deep source imports like
@deepseek-ai/dsh-client-runtime/src/client/sessions/context-provenance.tsbreak when dsh ships nosrc/. - Client UI packages like
@deepseek-ai/dsh-client-ui-primitivescould be renamed in future dsh versions, breaking every plugin that imports them directly. - The official
dsh-host-apiproxyhardcodes a settings namespace whitelist, so third-party settings cards never appear in the Web UI.
dshloader absorbs these (and future) breaks behind a stable API:
ctx.dshLoader on the host, window.__dshLoader__ in the browser, and
@dsh-plugin/dsh-loader/* stable subpaths for package imports.
Quick start
1. Install dshloader into a profile
dsh plugin --profile <name> add /path/to/dshloader
# or
DSH_HOME=~/.dsh npx dshloader setup <name>
2. Plugin package.json — only depend on dshloader
{
"dependencies": {
"@dsh-plugin/dsh-loader": "link:..."
}
}
Plugins must NOT declare any
@deepseek-ai/*dependency. All dsh packages are accessed through dshloader's stable subpaths.
3. Host side — use ctx.dshLoader
export const inject = ['dshLoader'];
export async function apply(ctx) {
// Settings: register a namespace
const scope = ctx.dshLoader.settings.register('my-plugin', schema);
// Web: register routes and WebSocket upgrades
ctx.dshLoader.web.get('/api/my-plugin/status', (req, res) => res.json({ ok: true }));
ctx.dshLoader.web.registerUpgrade({ path: '/ws/my-plugin', handler: fn });
// Services: read cordis services
const sessions = ctx.dshLoader.services.get('sessions');
}
4. Import dsh packages via stable subpaths
// Host packages
const { defineTool } = require('@dsh-plugin/dsh-loader/tools');
// Client UI packages (in client bundle source)
import { IconCloseFill14 } from '@dsh-plugin/dsh-loader/ui-primitives';
Stable subpath → real dsh package mapping (dsh 1.x):
| Stable subpath | Real dsh package |
|---|---|
@dsh-plugin/dsh-loader/tools |
@deepseek-ai/dsh-tools |
@dsh-plugin/dsh-loader/llm |
@deepseek-ai/dsh-llm |
@dsh-plugin/dsh-loader/agent |
@deepseek-ai/dsh-agent |
@dsh-plugin/dsh-loader/settings |
@deepseek-ai/dsh-settings |
@dsh-plugin/dsh-loader/ui-primitives |
@deepseek-ai/dsh-client-ui-primitives |
@dsh-plugin/dsh-loader/ui-slots |
@deepseek-ai/dsh-client-ui-slots |
@dsh-plugin/dsh-loader/ui-settings |
@deepseek-ai/dsh-client-ui-settings/client |
@dsh-plugin/dsh-loader/web-react |
@deepseek-ai/dsh-client-web-react |
@dsh-plugin/dsh-loader/schema-form |
@deepseek-ai/dsh-client-schema-form |
@dsh-plugin/dsh-loader/runtime |
@deepseek-ai/dsh-client-runtime/client |
When dsh renames a package, only the dshloader adapter changes — plugin source and bundle stay the same.
5. Client side — use window.__dshLoader__
// Read cordis client services
const conv = window.__dshLoader__.services.get('conversation');
// Register a package alias at runtime (fallback)
window.__dshLoader__.registerPackageAlias('@old/pkg', '@new/pkg');
6. Build config — mark stable subpaths as external
const CLIENT_EXTERNALS = [
'react', 'react/jsx-runtime', 'react-dom', 'react-dom/client', 'cordis',
'@dsh-plugin/dsh-loader/ui-primitives',
'@dsh-plugin/dsh-loader/ui-slots',
'@dsh-plugin/dsh-loader/ui-settings',
'@dsh-plugin/dsh-loader/web-react',
'@dsh-plugin/dsh-loader/schema-form',
'@dsh-plugin/dsh-loader/runtime',
]
How it works
plugin ──▶ ctx.dshLoader.{settings,web,services} ──▶ dshloader adapter
│
▼
real dsh (current version)
plugin bundle ──▶ require('@dsh-plugin/dsh-loader/ui-primitives')
│
▼ (__ModuleLoader__ wrapper maps stable name)
require('@deepseek-ai/dsh-client-ui-primitives')
│
▼
dsh module table
- Version detection reads
node_modules/@deepseek-ai/dsh/package.json(orDSHLOADER_DSH_VERSIONfor tests/override). - AdapterRegistry selects the best adapter for the detected version (exact → range → nearest-low fallback → clear error).
- The selected adapter registers service aliases, installs package-name
mapping hooks (host:
Module._resolveFilename; client:__ModuleLoader__.loadwrapper), and (only when opted in) the settings whitelist bypass bridge. All registrations usectx.reflect.provide/ctx.effect, so cordis auto-recycles them on fiber unload.
Load order does not matter. cordis is reactive dependency injection: plugins declaring
inject: [...]stayPENDINGuntil the alias is provided, regardless of where dshloader sits incordis.patch.yml.
Settings whitelist bypass (exposeAllNamespaces)
By default dshloader does not bypass the official settings namespace whitelist. Opt in explicitly:
- env:
DSHLOADER_EXPOSE_ALL_SETTINGS=1 - profile
package.json:dsh.dshloader.exposeAllNamespaces: true
Security trade-off: enabling this removes the official default-deny boundary for browser settings access. Only enable it in profiles where you trust every installed plugin.
CLI
dshloader setup <profile> Inject dshloader into a profile (dep + patch).
dshloader dump-config <profile> Run `dsh --profile <name> --dump-config`.
dshloader info [profile] Print loader version, detected dsh version,
selected adapter.
Rollback / disable
- Disable per launch:
DSHLOADER_DISABLE=1 dsh web - Remove:
dsh plugin --profile <name> rm @dsh-plugin/dsh-loader
Project layout
src/
index.ts host bundle entry (name / inject / apply)
client.ts client bundle entry (immediately tier)
api.ts DshLoaderHostAPI construction
registry.ts AdapterRegistry + version detection
types.ts shared host/client TypeScript types
version.ts loader version + log prefix
stable/ stable subpath re-exports (ui-primitives, tools, ...)
services/
settings.ts settings stable API
web.ts web stable API
services.ts services stable API (get / alias)
adapters/
dsh-1-x.ts dsh 1.x adapter
index.ts adapter registration
setup.ts profile injection + dump-config + info
bin/dshloader.mjs CLI entry
dist/ compiled host build (tsc output, git-ignored)
lib/ compiled client bundle (tsdown output, git-ignored)
tsconfig.json typecheck config
tsconfig.build.json host build config (emits dist/)
tsdown.client.config.mjs client bundle build config
docs/
api.md full API reference (Chinese)
design.md design document (Chinese)
tests/ L1 (unit) / module (L2) / integration (L3)
examples/
sample-plugin/ minimal example plugin
dsh-aux-state/ example using ctx.dshLoader only
Develop
pnpm install
npm run typecheck # type-check src/**/*.ts
npm run build # compile host (dist/) + client bundle (lib/)
npm test # all tests
npm run test:l1 # unit
npm run test:l2 # module
npm run test:l3 # integration
Node.js >= 18, node --test, no extra test framework.
License
LGPL-3.0-only (GNU Lesser General Public License v3 only). See LICENSE.
nexu-io/open-design
freestylefly/awesome-gpt-image-2
anywhere-labs/dsh-desktop
walkinglabs/learn-harness-engineering
awesome-dsh-plugin/awesome-dsh-plugin
MemTensor/MemOS