dsh-plugin-console

August 28, 2026 · View on GitHub

研讨立项(2026-08-27,工作台项目 pmtbcss1x2ggr,模式①+②完成,当前③最小设计)

核心痛点:Cordis 插件树重启后静默不加载,且没有任何机制发现和恢复

问题定义(一句话)

DSH/Cordis 插件加载依赖 5 道手工易碎的关卡(bundles 层栈 / patch insert / node_modules 落盘 / inject 声明 / 动态-静态同步),任一关卡在重启前悄悄失败(最常见:dsh plugin add 时 pnpm exit≠0 导致 reconcilePlugins 被跳过),重启后插件静默不加载——本项目做一个插件期望状态对账器,让插件加载从"手工装配、静默失败"变成"声明期望、自动对账、失败可诊断"。

5 道加载关卡(源码实证)

#关卡失败模式源码依据
dsh.profile.bundles 层栈dsh plugin add 时 pnpm exit≠0 → reconcilePlugins 被跳过(if (exitCode === 0) reconcilePlugins(...)),包装了但没写层栈dsh/lib/plugin-9h8shc4d.js
bundle 的 cordis.patch.yml - insert: 条目手清/错位/丢失;home 层 $DSH_HOME/cordis.patch.yml 与 profile 层冲突(home 层优先级更高)dsh-app-boot composeProfile
node_modules 落盘link: 残留、半安装、ESM 锁目录本机卸载残留经验
inject 声明ctx 严格代理:探测式访问未声明属性 → cannot get property without inject整棵树 boot 失败(非单个插件挂掉)cordis/lib/index.js ReflectService.get trap
动态/静态双轨同步dev 动态插件重启即失(vibecoding-workbench 教训:静态 bundle 滞后,重启回退)本机实战

架构设计(③最小设计)

plugins.intent.json(期望状态,~/.dsh/,profile 外)
   ├── dsh-plugin-console sync   → 生成/核对 dsh.profile.bundles 层栈(M1)
   ├── boot 对账器(host 插件)  → boot 后实测 loader 树 vs intent,缺失自动补写(M2)
   ├── 加载巡检                  → fiber.state 巡检 0挂起/3错误/5卸载(M3)
   └── heal 自愈                 → 确定性修复 / 不确定给命令(M4)

组件划分

组件形态职责
plugins.intent.json状态文件(~/.dsh/)声明期望插件集合:{name, version-line, source, dynamic?}
sync CLI独立 CLI(dsh-plugin-console bin)从 intent 生成/核对 dsh.profile.bundles--dump-config 交叉验证
boot 对账器host 插件(ctx.inject(['loader'])boot 后 loader.entries() 实测 vs intent;缺失 → 写回层栈(幂等);注入失败 → fail-loud 报告
巡检器host 插件服务周期/按需巡检 fiber.state;标记依赖缺失(fiber.inject vs fiber.store
healCLI 子命令确定性修复(补 bundles / 清 link 残留 / 重跑 pnpm add);不确定的(inject 缺服务、config 校验失败)只输出精确命令

关键设计决策

  1. 意图文件放 profile 外~/.dsh/plugins.intent.json):profile 目录本身是易碎区,不能把"修复清单"放在"被修对象"里。
  2. 对账发生在 boot 后、HMR 前:loader 树已 settle,用 ctx.get('loader') 实测而非猜配置。
  3. 自愈只做确定性修复(幂等操作:写 bundles、重跑 reconcile、清 link 残留);不确定的只报告 + 给命令,避免自动改坏。
  4. 兼容动态/静态双轨:intent 里 dynamic: true 的插件,sync 时提示同步静态 bundle(把 vibecoding-workbench 的坑变成流程护栏)。
  5. 纯函数决策层:intent 解析 / 层栈 diff / 修复计划生成 = 纯函数(可单测);文件写、pnpm 调用 = IO 边界。

技术约束(坑位预埋)

  • ctx 严格代理:只声明注入的 loader;取路径用 process.env.DSH_HOME,绝不探测式访问 ctx 属性。
  • harness 工具 render 必须返回数组 [{type:'text',text}]
  • dsh plugin add 在 pnpm exit≠0 时跳过 reconcile —— 对账器必须独立于 CLI reconcile 自证。
  • 插件文件被 ESM 锁目录:改 bundle 前先移除 patch 条目再重启。
  • 动态插件迭代后必须同步静态 bundle(update-bundle.ps1 流程)。

里程碑(已挂工作台③)

#里程碑状态验收
M1intent 声明 + sync CLI✅ 完成生成层栈与 --dump-config 合成树一致
M2boot 对账器(host 插件)✅ 完成模拟 reconcile 被跳过场景,重启后自动补写层栈
M3加载巡检 + 状态报告✅ 完成故意制造 inject 缺失/挂起,巡检正确标记并指出缺哪个服务
M4heal 自愈 + 五关诊断✅ 完成一键修复且幂等;修不了的输出可执行命令
M5真机验证(本机 web profile)✅ 完成(隔离环境)装/卸/改坏各场景重启实测通过
M6发布(publish=true)✅ 完成(2026-08-28)GitHub 仓库 + Release v0.1.0 + BWH issue #147 + 官方 Discussion #4825

实现状态(2026-08-28,47 单测全绿)

真机验证记录(M5,隔离环境 DSH_HOME 实测)

  1. 最小 profile 独立 bootdsh plugin add link:... → reconcile 正常写入层栈 → --dump-config 合成树含 plugin-console 层 → 启动 web 成功(3080 监听)。
  2. 自愈闭环(核心验收):装 dsh-mnemon → 从层栈手动移除(模拟 pnpm exit≠0 跳过 reconcile)→ 启动 web → boot 后对账器自动把 dsh-mnemon 补写回层栈末尾.bak 备份证明写回前后差异(写回前无 mnemon)。
  3. 幂等性:二次启动层栈不变、无新增写回。
  4. 真实环境还原:测试后已从真实 web profile 移除插件并清 link 残留,--dump-config 确认无残留。

真机踩坑(已入工作台教训栏)

  • cordis 插件 Config 必须是 standard-schema 对象:导出普通对象 {type:'array'}resolveConfigConfig["~standard"].validate 抛 TypeError → 该 entry 失败 → AggregateError 拖垮整棵 loader tree(plugin tree failed to load: loader entries failed to apply),且 fail-loud 只跟 cause 链、不打印 AggregateError.errors,排查极难。解法:不导出 Config,配置走 cordis.patch.yml 的 config 字段。
  • PATH 里的 dsh 可能是 Desktop launcherDSH Desktop\host-commands\desktop\bin\dsh.cmd),它忽略 DSH_HOME 且用打包版 cordis;真机隔离验证要用全局 npm 版:node <npm-global>/@deepseek-ai/dsh/lib/bin.js

已实现

  • plugins.intent.json~/.dsh/):v1 格式,{version, profiles: {web: {plugins: [{name, spec, dynamic}]}}}
  • dsh-plugin-sync CLI(bin/sync.js):
    • 默认 dry-run 对账(期望 vs 实际层栈)
    • --apply 幂等写回 dsh.profile.bundles(.bak 备份,保留核心 bundle,缺失追加末尾)
    • diagnose 子命令:五关诊断 + 修复命令
  • host 插件(plugin/host.js,boot 对账器):
    • boot 后自动对账:ctx.inject(['loader','tools']),实测 loader 树 vs intent,缺失自动补写
    • agent 工具:dsh_plugin_reconcile(对账+自愈)、dsh_plugin_inspect(fiber.state 巡检)、dsh_plugin_diagnose(五关诊断)
  • 纯函数决策层(lib/,全部可单测):intent.js / reconcile.js / reconciler.js / inspect.js / heal.js

五关诊断(M4)

检查修复
bundles 层栈 vs intentdsh-plugin-sync --apply 自动补写
bundle cordis.patch.yml 的 - insert:提示补回条目
node_modules 落盘 + link: 残留pnpm add 命令
inject 依赖缺失(fiber.state 0 挂起)巡检指出缺哪个服务
动态/静态双轨同步update-bundle.ps1 提示

目录规划(待④实现)

D:\HarnessSpace\dsh-plugin-console\
├── README.md              ← 本文档
├── intent/                ← plugins.intent.json 定义与样例
├── cli/                   ← sync / heal CLI(node:test 单测)
├── plugin/                ← boot 对账器 host 插件(bundle 结构,dsh 可装)
│   ├── host.js
│   ├── cordis.patch.yml
│   └── package.json
└── test/                  ← 单测 + 真机场景脚本