DSH 生态的"模组注入器":免重启把任意本地插件包加载到运行中的 web,含热重载/自重载/一键卸载/路由自愈/侧挂区与设置页插件管理 UI。
- 语言
- TypeScript
- 分支
- main
安装
$ dsh plugin --profile web add github:yjh051108/dsh-super-injector在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程
一句话定位
DSH(DeepSeek Harness)的运行时"模组注入器":装好它之后,对 agent 说一句话就能把任意本地插件包免重启加载到运行中的 web,并把整套开发闭环——热重载、自重载、一键卸载、路由自愈、侧挂测试区——一并交付,省掉反复重启和改配置。
核心能力
- 运行时注入任意本地插件包:把插件目录链接到 profile 的 node_modules,再用 loader.create 装配,不动 patch/package.json,免重启立刻生效(含 host 工具 + client UI)
- 整包热重载:改代码 → build → 1.5 秒内自动监听文件指纹变化触发重载,或显式调用
dev_reload_package;失败自动回滚保留旧版 - 一键卸载 + 路由自愈:卸 loader entry、清注入清单、删 junction、清 webserver 路由残留,全部免重启
- 双路径安装 + 启动自动恢复:既可运行时注入(开发态)也可走 profile bundles(重启后由官方接管);注入清单持久化,重启后自动归位
- 插件生产线脚手架:内置四种形态骨架(工具包 / 守护循环 / UI 面板 / 混合),含构建脚本、peerDependencies 范围声明、ctx.effect 资源注册规范
- 设置页插件管理 UI:客户端新增"插件"设置页,可视化浏览已注入插件、一键卸载、拖入文件夹走"内化"(新建 agent 会话让 AI 把内容变成插件)
技术实现
- 语言: TypeScript(ESM、NodeNext)
- 关键依赖:
@deepseek-ai/dsh-tools(peer,工具注册)、cordis(peer,DI/fiber)、schemastery(peer,Config Schema);运行时还用到node:fs / node:path / node:os / node:child_process - 架构模式: 自带一个 cordis 引导器 entry(通过
cordis.patch.yml的insert注入),注册 16 个dev_*工具(host 层) + 一个settings.section客户端 UI;host 与 client 各自走独立 build(tsc + tsdown) - 入口文件:
src/index.ts:570(apply(ctx, config)),客户端入口src/client/index.ts:54
适用场景
- 想在 DSH 上快速试用或迭代自己的插件包,但又不想每次重启 web(debug 时频繁重启尤其痛苦)
- 需要让 AI agent 自己决定"装/卸/换"插件的运行时管理面——官方装配机制只覆盖"装什么",而"装完之后怎么改"留白
- 多人/多环境的 DSH 部署里,需要在不碰官方 profile 配置的前提下注入第三方插件
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH(@deepseek-ai/dsh-tools) | >=0.0.1-rc <2 | peerDependencies 范围声明,DSH 0.1.0-rc.6 已实测通过,升级不需改插件 |
| cordis | >=4.0.0-rc <5 | peerDependencies 范围声明 |
| schemastery | ^3.18.0 | peerDependencies |
| Node | 未声明 | devDependencies 用 @types/node ^24.13.3;运行依赖与 DSH 宿主 Node 版本一致即可 |
| 平台 | macOS / Windows / Linux | Windows 用 NTFS junction,其他系统用软链;Windows 需要 Git Bash 或 WSL 运行 bash 构建脚本 |
| 原生模块 | 无 | 仅用 node:fs / node:path / node:os / node:child_process / node:url |
| 外置工具 | bash + node + npm | 仅在使用 dev_scaffold_plugin / dev_build_plugin 脚手架工具链时需要;纯注入/卸载不需要 bash |
安装方式
dsh plugin --profile web add github:yjh051108/dsh-super-injector
配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
registryFile | string | 注入清单持久化文件路径;记录已注入的插件包目录与时间,重启后按此自动恢复 | ~/.dsh/super-injector/registry.json(DSH_HOME 优先于 homedir()) |
profileNodeModules | string | profile 的 node_modules 路径;junction 链接目标,DSH loader 据此解析包 | ~/.dsh/profiles/web/node_modules |
autoRestore | boolean | 启动时是否自动恢复注入清单(重新链接并装配所有已注入的包) | true |
intervalMs | number | watch 自动轮询检测产物指纹的间隔毫秒;构建产物整批写入,间隔天然合并抖动 | 1500 |
watches | array | 自定义监听目录与匹配子串,每条形如 {dir, match};loadCache key 是 realpath URL,按目录名子串匹配 | [] |
常见问题
Q: 装好之后看不到 dev_ 工具怎么办?*
A: 先确认注入器已通过官方装配路径(dsh plugin --profile web add 或 cordis.patch.yml)生效、对应 web profile 已重启,再对 agent 说 dev_plugin_status——若列表里没有 dsh-super-injector,多半是装到了非运行 profile。
Q: 注入一个 UI 形态插件报 "client ✗" 怎么排查?
A: 若插件本来就没声明 dsh.client.platform,会显示"跳过",这是预期。若显示"注册失败",说明缺 lib/client.js 或 client bundle 不是 tsdown 产物;需要 npm run build:client 单独构建 client bundle,注入器会在注入前自动阻断。
Q: dev_reload_package 报"重载目标命中注入器自身"被拒绝?
A: 注入器拒绝普通路径下的自毁——必须用 dev_reload_package 匹配名中带 dsh-super-injector(走自重载分支),且两次自重载间隔必须 ≥10 秒,否则会被节流拦下。
Q: web 启动报 "duplicate loader entry id" 崩溃怎么修?
A: 在解压目录里跑 node scripts/fix-patch.mjs(或在已起的环境里用 dev_fix_patch),按 id 去重并自动备份原文件;dsh loader 严格要求同 id 仅一条。
Q: Windows 上构建报 "找不到 bash" 或 WSL 报错?
A: 注入器主动拒绝 WSL 的 System32\bash.exe(System32 抢先 PATH 时会启动失败),需要装 Git for Windows / PortableGit 并把 Git\bin 加到 PATH;Windows 链接用 NTFS junction 而非符号链接。
Q: 注入的插件重启后还在吗?
A: 在。注入清单持久化到 ~/.dsh/super-injector/registry.json,下次装配时 autoRestore 默认开启,自动按清单逐个重新注入;侧挂转正的工具也持久化在 staging.json。
Q: 怎么彻底卸载注入器?
A: dsh plugin --profile web remove @yjh051108/dsh-super-injector,再清理 cordis.patch.yml 里相关条目(保持单一顶层数组)、删 profile node_modules 链接、可选删 ~/.dsh/super-injector/ 目录;重启后 dev_* 工具消失即卸载完成。
Q: scaffold 出来的骨架能直接注入吗?
A: 可以,但需要先 dev_build_plugin 在 DSH_CHECKOUT 环境下构建出 lib/;骨架已强制 ctx.effect 注册规范与 peerDependencies 范围声明,client 形态还会校验 slots.register 的合法 slot 名。
上手难度
进阶 — 不只是装一个插件,而是把官方装配机制之外的一整套运行时管理面带进来;要理解 junction、loader.create、cordis fiber 与 schema 注入才能读懂源码;普通用户只需按 README/INSTALL 走完安装与自检即可用。
已知问题与限制
- 自重载必须显式调用
dev_reload_package且匹配串含dsh-super-injector;watch 自动重载不会触发自重载(防无人值守时注入器永久缺席) - 自重载最小间隔 10 秒(防连环自杀),节流时间戳落盘到
~/.dsh/super-injector/self-reload.json以跨实例持久 - client 形态插件必须声明
inject = ['slots']且slots.register的 name 落在已知白名单(conversation.view/settings.section/settings.plugin.item等 11 个),否则注入会被阻断 - 注入前会校验构建产物新鲜度:声明了
dsh.client.platform但缺lib/client.js或产物非 tsdown 输出(缺__ModuleLoader__标记)→ 阻断;src/比lib/新 → 警告不阻断 - Windows 上 PowerShell 编辑过的
cordis.patch.yml可能含 UTF-8 BOM,注入器主动检查 BOM 并拒绝 DSH_HOME环境变量与 web 进程的homedir()不一致(如服务账户)时,路径推导会全部错位——以DSH_HOME为权威- WSL 安装但未配分发版时,
System32\bash.exe抢先 PATH,注入器主动探测并拒绝,需用 Git for Windows / PortableGit - 测试插件(
dev_self_test)的临时目录固定在DSH_HOME下的super-injector/selftest-runner,目录名/路径变化会触发 tsx 旧缓存命中导致重载失败 - peerDependencies 范围声明是脚手架的强制约束(不硬编码版本),下游插件作者若改用
0.1.0这种精确版本,可能因 DSH 升级而装不上
🎉 v0.3.0 重大声明(2026-08-14)
从经验补丁到源码契约——注入器完成规范重构。
本版本按 docs/SPEC.md(基于 DSH 0.1.0-rc.6 源码语义推导的 设计契约)重构自重载为官方 REPLACE 结构:工具只排程、绝不亲自自杀; reboot 走
entry._dispose(官方_disposing豁免)+ 失败自动 rollback。 从此注入器的一切行为都有源码依据,不再依赖经验补丁。里程碑回顾:
- 三轮零上下文 subagent 评测:9/10 → 9.5/10 → 10/10
- 作死压力测试:连环自杀/坏语法/悬空 junction/循环注入卸载——零崩溃零残留
- 云源自举:下载 release 副本 → 装配 → 注入器从云端副本运行(自检 8/8)
- 免杀进程恢复:失败 → touch patch(include.refresh 进程内重装配)→ 6 秒复活
- DSH 正式版兼容:0.1.0-rc.6 一行不改直接运行(peerDeps 范围声明实证)
哲学不变:一切皆插件——注入器是 DSH 生态的运行时注入标准层, 让"插件想长成什么样就长成什么样"。
DSH 生态的 BepInEx 式模组注入入口:运行时把任意本地插件包注入运行中的 web, 不碰 patch / package.json / bundles 列表、不重启进程。注入即完整生效(host 工具 + client UI)。
灵感:官方装配机制(profile bundle / repository-plugin)是唯一的"官方入口",就像游戏 只有启动器能装模组。本插件打破这一点——引导器走官方入口装一次,之后万物皆可运行时注入。
安装(三选一)
方式 A:Release 包(推荐,免构建)
从 Releases 下载
dsh-external-dsh-super-injector-0.0.1.tgz,解压得到插件目录(含 lib/ 与 cordis.patch.yml),然后:
# 官方装配(重启后由 bundles 接管,生产态)
dsh plugin --profile web add <解压目录>
# 或运行时注入(免重启,开发态;需任一环境已常驻注入器)
# 对 AI 说:dev_inject_plugin <解压目录>
方式 B:git 装配
dsh plugin --profile web add github:yjh051108/dsh-super-injector
git 依赖拉取的是源码仓库(不含
lib/);包内prepare钩子会在安装时自动 用 tsdown 构建自包含lib/(首次需要网络拉取 tsdown,之后走本地缓存)。 若构建失败,请改用方式 A 的 Release tgz(预构建产物)。
方式 C:引导装配(源码方式,只需一次)
⚠️ 仅限未走 bundles 装配时使用:注入器自带 bundle 层会自注册
dsh-super-injector,与下方手动insert撞同一个 loader entry id,会报duplicate loader entry id。走方式 A/B 装配后请勿再加这一条。
在 ~/.dsh/profiles/web/cordis.patch.yml 添加:
- insert:
- id: dsh-super-injector
name: '@yjh051108/dsh-super-injector'
config: {}
引导器常驻后,任意超级模组随取随用,无需再碰官方配置。
兼容性
- 不硬编码 DSH 版本:peerDependencies 全部为范围声明
(
@deepseek-ai/dsh-tools: >=0.0.1-rc <2、cordis: >=4.0.0-rc <5)——DSH 升级不报废。 - 已适配服务改名:
webServer(原 httpServer)、compaction(原 compact)。
特性
- 🔥 热重载 + 自重载:
dev_reload_package整包重载(清缓存 → 重新 import → 重建 fiber,失败回滚保留旧代);注入器自身也支持自重载(自杀 → 全局定时器重建) - 🤖 自动 watch:注入即自动监听插件目录,改代码 build 后约 1.5 秒自动重载(无需手动触发)
- 🖥️ 注入插件 UI 完整生效:清除 loader 幽灵 entry 隔离(normalizeEntry),client 模块补扫/联动/卸载清理——注入的插件 host 工具 + 图谱/面板等 UI 全部可用
- 🧪 开发侧挂区(staging)+ 持久化:测试工具挂"后侧"不进 tools schema、缓存零污染;
dev_stage_promote一键转正;staging 落盘,自重载/重启后转正工具自动恢复 - 🧹 一键卸载:
dev_uninject_pluginfiber 全清理(工具/监听/路由/client 表)→ 清注入清单 → 删 junction,免重启 - 🛠️ 路由自愈:
dev_clear_routes直捣 webserver 内部路由表,热重载残留的孤儿路由免重启清除 - 🔁 重启自动恢复:注入清单持久化(
~/.dsh/super-injector/registry.json),web 重启后自动归位 - 📊 操作自检:每次注入/重载/安装返回
host ✓ / client ✓双验证;dev_plugin_status含操作成功率统计 - 🛡️ 失败可重试:
hasActiveEntry权威防重 + 失败残留缓存自动清理 + 残留 entry 自动清理
与 dsh-evolve 的定位差异(生态互补)
| dsh-evolve | dsh-super-injector | |
|---|---|---|
| 形态 | 创造模式:agent 现场写单文件插件源码(~/.dsh/evolve/<name>.mjs)热挂载 | 手术台:注入开发者预构建的完整插件包(package.json + lib/) |
| 适用 | agent 随对话长出小工具(记账/天气/周报) | 装/换成品模组、自主开发闭环(写 → build → 注入 → 热重载) |
| 联动 | evolve 长出的源码可升级为完整包,再走注入器上膛 | 注入后可被 dev_reload_package 热重载 |
生态定位:官方之下的运行时标准层
官方对插件体系的方向(2026-07 agent notes):
- 否决安装命令 + 安装数据库 + marketplace——持久化插件只有一种状态:配置(cordis.patch.yml / profile bundles / repositories),事务性 HMR 对账;
- agent 自己管理运行时——自指 cordis 工具集,运行时归 agent 管。
翻译:官方钦定"装什么"(bundle / repository + 配置),但"装完之后怎么改"——热重载、侧挂测试、一键转正、卸载、失败自愈——是官方留白。这一整块运行时管理面,由本插件吃下。
| 生态入口 | 层 | 一句话分工 |
|---|---|---|
| 官方 bundle / repository | 装配层 | 唯一官方入口,配置即状态 |
| plugin-registry | 官方薄控制台 | 官方格式插件管理与开发引导 |
| marisa | agent 面工具链 | 临时插件 → 持久化插件的固化桥 |
| mygo | 受管对象层 | 插件生命周期对象化(锁定/启停/依赖图) |
| dsh-evolve | 创造模式 | agent 现场长出单文件能力 |
| dsh-super-injector | 运行时手术台 | 开发闭环全家桶:注入 / 热重载 / 侧挂转正 / 卸载 / 路由自愈 / UI 联动 |
设计原则:
- 不发明协议:注入的是标准插件包(package.json + lib/),格式就是官方包格式,装上即官方语义;
- 双路径,尊重"配置唯一":运行时注入(免重启,开发态)↔
dev_install_package落 profile bundles(重启后由官方接管,生产态)——注入清单只是运行时恢复缓存,不是第二安装数据库; - 模型可驱动:dev_* 全是工具,agent 自己注入/卸载/转正——正踩在官方"agent 自己管理运行时"的方向上;
- 可逆且自愈:注入可回滚(失败保旧代)、卸载即净(fiber 全清理)、残留可自愈(路由/缓存/entry 自动清理)。
目标:成为官方装配机制之下、生态事实标准的运行时管理层——"启动器装模组"只是起点,注入器让 DSH 拥有"万物可注入、注入可回滚、改完即生效"的 Mod 级体验。
工具全家桶(全部免重启)
| 工具 | 说明 |
|---|---|
dev_inject_plugin | 运行时注入本地插件包(junction 链接 + loader.create,hasActiveEntry 防重) |
dev_uninject_plugin | 一键卸载注入模组(fiber dispose 全清理;bundle 插件自动写 disabled 阻断自装配) |
dev_injected_list | 列出注入清单 |
dev_install_package | 热装配本地 bundle 插件(profile package.json + junction + loader.create,重启后由 bundles 列表正常装配) |
dev_reload_package | 整包热重载(清缓存 → 重新 import → 重建 fiber,失败回滚保留旧代;含自重载) |
dev_plugin_status | 已装配插件清单、fiber 状态与操作成功率统计 |
dev_clear_routes | webserver 路由残留自愈(按 path 前缀删除孤儿路由) |
dev_stage_add | 开发侧挂:测试工具挂后侧(不进 tools schema,缓存零污染) |
dev_stage_call | 调用侧挂工具测试 |
dev_stage_list | 列出侧挂工具(含转正状态) |
dev_stage_promote | 一键转正:侧挂工具挂前侧正式注册(唯一一次缓存刷新) |
dev_stage_demote | 撤回/注销侧挂或已转正工具 |
插件开发指南(生产线)
哲学:插件想长成什么样就能长成什么样——工具包 / 守护循环(timer+LLM 自主 agent loop)/ UI 面板 / 混合形态,同一注入通道;注入即完整生效(host+UI)、可热重载与自重载、卸载即净;插件自身的提示词/工具/循环皆可自我优化(改 → build → 重载闭环)。建新插件优先克隆/借鉴/重构生态已有资源(dsh-external 仓库、已注入插件、官方 packages 模式),不重复造轮子。
一分钟起步(生产线三件套)
# 1. 生成骨架(toolkit / daemon-loop / ui-panel / hybrid)
# 对 AI 说:dev_scaffold_plugin {"dir": "D:/dev/my-plugin", "name": "my-plugin", "form": "daemon-loop", "description": "..."}
# 2. 构建打包(探测 DSH_CHECKOUT → tsc host → tsdown client(如声明)→ npm pack → tgz)
# 对 AI 说:dev_build_plugin {"dir": "D:/dev/my-plugin"}
# 3. 发布(gh release create v<version> + tgz)
# 对 AI 说:dev_release_plugin {"dir": "D:/dev/my-plugin", "version": "0.1.0"}
# 注入即活:dev_inject_plugin {"dir": "D:/dev/my-plugin"}
# 改代码 → build → 自动 watch ~1.5s 重载(或 dev_reload_package)
30 行写一个"会思考的插件"(守护循环最小示例)
import type { Context } from 'cordis'
import type LlmService from '@deepseek-ai/dsh-llm'
import { createUserMessage, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
type AppContext = Context & { llm: LlmService; setInterval(fn: () => void, ms: number): any }
export const name = 'my-daemon'
export const inject = ['timer', 'llm']
export function apply(ctx: AppContext): void {
let route: { provider: string; model: string } | null = null
ctx.on('llm/stream', (options, next) => { route = { provider: options.provider, model: options.model }; return next() })
ctx.setInterval(() => {
void (async () => {
if (!route) return
const stream = ctx.llm.stream({
provider: route.provider, model: route.model,
system: '判断是否需要人工介入,直接输出结论',
messages: [createUserMessage({ source: { kind: 'user' }, content: [{ type: 'text', text: '检查事项...' }] })],
reasoningEffort: ReasoningEffortId('off'), maxTokens: 200,
})
for await (const chunk of stream) { /* 决策 → 行动 */ }
})().catch(() => {})
}, 60_000)
}
规范铁律(注入器实测沉淀):
- 资源注册必须挂
ctx.effect(工具/路由/监听)——热重载/卸载才能自动清理,否则僵尸残留(注入器自己踩过) - peerDependencies 用范围声明(
>=0.0.1-rc <2、>=4.0.0-rc <5)——不硬编码版本,DSH 升级不报废 - client bundle 需单独构建(tsdown → lib/client.js)——UI 形态两步构建
- 提示词注入遵守缓存原则:静态文本 + order 靠前(静态到头);动态内容走消息尾(动态到尾);严禁动态拼接进 system——system 前缀任何动态变化 = 整个会话缓存全量 miss(命中便宜 10 倍)
- 自检:改完代码跑一次
dev_self_test,确保注入/重载/自重载/预检/卸载全链路不退化 - 首轮锚定(V4 Pro 实测,参考 dsh-anchored-standard,Project2 98/99):工具面大(≥5 个)时,首轮请求只暴露最核心的 1-2 个工具,首个
tool/call后恢复全部——首轮请求结构决定整条会话的策略轨迹,锚定训练对齐的窄工具面再放开,能力不损。实现:system-prompt/assembleWaterfall 过滤器(骨架已自带,见 dev_scaffold_plugin) - 工具 schema 精简:description 用短句点明用途,详解放 tool result / 静态引导文本,不要写进 schema——工具目录按字符计费进首轮 prefill,实测 6 插件可膨胀到 17.6 万字符,稀释首轮注意力且无缓存 prefill 最贵(缓存命中便宜 10 倍)
- 近距离信号原则(最强机制,P14/P16/P20 实测):所有行为引导(分类/深度思考/收敛)必须注入在用户消息之后(近距离),同一指令放 system(远距离)会衰减甚至反向(P13 协议加速衰减、P20 深度段进 persona 路由崩到 67%);固定文本保持缓存命中(92-94%)
- 弱域内路由(P8/P11):任务类型模糊时不要武断选模式——用弱 persona(模型自己分类),按模型选 persona(Pro=spec句+few-shot,Flash=neutral+classify,同一 persona 两模型行为可相反)
- 单任务长链路三锚(P22/P23):开放任务探索失控是主病(完成率 0%)——persona 静态锚「回顾已完成 + 信息足够就产出 + 禁止环境检查/穷举 grep」把完成率拉到 100%
高性能插件(首轮锚定 · 为什么 & 怎么做)
为什么:DeepSeek V4 Pro 的行为策略在首轮请求处被「完整 system prompt + 工具 schema 分布」强条件化。同题同环境:minimal(2 工具)99/96,standard(25 工具)91,两阶段锚定 98/99——先窄后宽,能力与完整工具面兼得。微探针证明起作用的是可调用的 schema 面(action space),不是看见工具名文本;工具目录只变化一次(首↔次请求之间有一次前缀缓存变化,首轮无缓存 prefill 最贵)。
怎么做(骨架自带,三步启用):
dev_scaffold_plugin生成的 toolkit 骨架 apply() 末尾有注释好的锚定块;inject数组加'systemPrompt',把MINE换成你的工具名集合、CORE换成首轮要保留的核心工具;- 首次工具调用后自动恢复全部工具,resume/reload 不丢状态(阶段从持久 session events 推导)。
验证:导出 session JSONL 看 request/header——第一份只含核心工具,首次工具调用后的下一份变更 header 含完整目录,此后保持。
高性能引导的完整认知(v0.3.3 更新,基于 dsh-router-standard P1-P23 实测)
| 机制 | 实测 | 落地 |
|---|---|---|
| 首轮锚定(窄工具面) | Project2 98/99 | tool-bootstrap 过滤器(骨架自带) |
| 近距离引导(用户消息后注入) | 零衰减(远距离同指令加速衰减) | 插件监听 session/event → inbox.append 固定引导 |
| 弱域内路由(模糊任务交模型自分类) | 区分度 +5~5.7,按模型选 persona | weak 模式(dev_router_mode weak) |
| deep-guide(分类+深度思考+commit) | 路由 96% + 收敛 100% + 反稀释 | 近距离固定引导文本 |
| 单任务三锚(回顾+收敛+反跑题) | 完成率 0%→100% | persona 静态锚 |
| plan-mode section 保留 | 失忆修复(v6) | applyPersona 只换 persona section |
完整实现与复现探针:dsh-router-standard(v0.1.0,含论文与 P1-P23 全数据)。
参考与致谢:本引导中的「首轮锚定」机制与统计证据,参考了 xiaobright 的开源工作——
dsh-anchored-standard(MIT,
两阶段锚定 preset 与 tool-bootstrap.mjs 实现,Project2 实测 98/99,首轮 2 工具 → 首次
工具调用后恢复 25 项完整 Standard 工具)与
modeltest(V4.1b 评测套件:同环境对照
minimal 99/96 vs standard 91 vs 两阶段 98/99、触发机制微探针、轨迹统计)。骨架中的锚定
实现即该 preset 过滤器的插件级移植(只裁剪本插件工具)。
典型工作流
装模组:拿到插件包(package.json + lib/ 产物)→ 对 AI 说 dev_inject_plugin(参数 = 插件包绝对路径)→ 当场生效(下一 step 工具可见)。
开发迭代:改代码 → build → 自动 watch 约 1.5 秒自动重载(或 dev_reload_package)→ 验证 → 稳定后 dev_stage_promote 一键转正。
卸载:dev_uninject_plugin(参数 = 包名子串)→ 工具/监听/路由/client 表全清,免重启。
机制
- junction 链接插件包到
~/.dsh/profiles/web/node_modules(loader 标准解析路径); ctx.loader.create({ name, config })运行时装配(完整 ctx);- 清单持久化(
~/.dsh/super-injector/registry.json),重启后自动恢复注入; - client 联动:注入/重载后清除 entry disabled 标记并补扫 client 模块表(
client-modules.processOne),浏览器端 bundle rev 联动更新。
踩坑记录
- 插件包必须自带依赖链接:
lib/里import '@deepseek-ai/dsh-tools'等从包自身node_modules解析——照 build.sh 建 junction 到 checkout 包(如node_modules/@deepseek-ai/dsh-tools → <checkout>/packages/core/tools); - client bundle 需单独构建:host 侧
bash scripts/build.sh(tsc),client 侧npm run build:client(tsdown,产物lib/client.js)——注入插件要出 UI 必须两步都构建; - 失败 import 会毒化重试:loadCache 残留残缺 job 导致同名重载复用失败态——注入前
purgeCache清理; - 资源注册必须挂
ctx.effect:reloadPackage重建失败若报duplicate / already registered,说明资源是裸注册——挂ctx.effect后热重载才能正确清理重建; - client 操作必须用完整包名:
client-modules.processOne对entry.options.name精确匹配,传短名会静默注册失败; - 注入的插件不进 loader 配置持久化——重启后由注入器自动恢复(引导器常驻)。
仓库:https://github.com/yjh051108/dsh-super-injector Release:https://github.com/yjh051108/dsh-super-injector/releases