@dsh-workbench/module-tools
v0.2.0
Published
模块包的构建与门禁工具:build(单文件 ESM 宿主侧 + 套 loader 壳的浏览器侧)、check(契约/产物边界/源码边界/卡片渲染)。模块包不再各带一份构建脚本。
Readme
@dsh-workbench/module-tools
工作台模块的工具箱:建骨架、构建、过门禁、管三张表、发货前核清单。 模块作者(以及替用户造模块的 agent)只跟这几条命令打交道。
命令
dsh-wb-module init <unit> [--dir <目录>] [--template minimal|diy] [--description "一句话"]
dsh-wb-module build # 出 dist/host.js 与套了 loader 壳的 client.js
dsh-wb-module check [--only <判据>] # 十一条判据;--only 可以单跑
dsh-wb-module design <init|check|render|accept>
dsh-wb-module publish # 发货前的清单:门禁 + 三张表 + npm pack 清单(只 dry run)--cwd <目录> 指定包目录(默认当前目录)。模块目录里更省事的是骨架自带的脚本:
pnpm build / pnpm typecheck / pnpm test / pnpm selfcheck / pnpm design。
十一条判据(check)
| 判据 | 盯什么 |
|---|---|
| contracts | 模块契约:单元 id 唯一、两个面、四个脚本、files、peer 下限;以及清单 ↔ 代码(真正注册的工具)与底稿 ↔ 清单(design.json 的能力名)两处对账(见下) |
| protocol | 模块声明协议:dsh.workbench 的 apiVersion 要在、静态半形状要对、不许有协议不认识的键(scope 现在就是不认识的键之一 —— 见下) |
| bundles | 产物边界:宿主面里不许出现浏览器侧的东西 |
| source | 源码边界:不直接引 dsh 的包、不引不是种子词的 @deepseek-ai/* |
| primitives | dsh 原语只从模块表(kit)拿 |
| kit | 这份外壳的 kit 成员到底有哪些(缺什么会当场点名) |
| cards | 卡片渲染:五态都要画得出来,空数据不许抛 |
| standalone | 独立构建:产物不依赖工坊里跑 |
| markers | 公开包无内部标识(内网域名、企业内部名) |
| style | 样式归属:模块不许定义外壳前缀(wb-*)的规则 |
| alias | 模块不指外壳:源码里没有指向外壳 @/ 的引用 |
三态输出:✔ 通过 / ○ 不适用 / ✖ 不过;有任何不过就退出 1。
三张表:design.json
三张表(面板 / 能力 / 联动)+ 状态矩阵 + 数据源记录 + 验收清单住在模块根目录的 design.json,
README 里那一段由它生成(夹在 <!-- dsh-wb:design:start/end --> 之间)。
design.json 是设计底稿:只装人话(oneLine / shape / approvalText / 面板那几张表的文字 /
datasource),不装机器字段。"这条能力在哪些工作区出现"不在底稿、也不在清单:
那是用户的事(他的面板板),模块作者声明不了(用户口径「模块开发者不能定义 scope,
scope 永远是用户来决定的」,见 ADR-0038
§2.4 / §6.16)。
contracts 会把底稿的能力名与清单的工具名做键集合对账(不重不漏,只对名字):
底稿多一条、清单多一把都点名判红;没有 design.json 的模块不查。
dsh-wb-module design check # 空着的格一格格点名叫出来 + README 有没有落后
dsh-wb-module design render # 用 design.json 重新生成 README 那一段
dsh-wb-module design accept # 用户逐条点头之后,把验收清单打勾协议:dsh 字段里的五段
一个模块包在 package.json 里声明五件事,缺哪一段在哪一层炸都不一样:
| 段 | 是什么 | 谁读 |
|---|---|---|
| dsh.bundle.patch | 把自己插进 profile 组合图的 cordis 补丁 | dsh 的组合器(装载) |
| dsh.client{platform,inject,external} | 浏览器侧接线 | dsh 的客户端组合器(dsh 自己不校验,错的声明要等浏览器 require 才炸 —— 所以 contracts 替你查) |
| dsh.workbench | 模块声明协议(下详) | 门禁 · 市场 · 外壳 |
| dsh.workbenchFaces{host,client} | 工具链元数据(不在协议里):两个 half 的源码入口 | 门禁:source 拿它算可达性、contracts 查它在位;运行期与装机预检都不读 |
| peerDependencies['@dsh-workbench/core'] | 服务面:外壳 provide 的服务在不在 | dsh 的 evaluatePluginCompatibility |
dsh.workbench(协议 v1)
"workbench": {
"apiVersion": 1, // 必填。形状契约,缺了外壳不认这个模块
"unit": "hello", // 单元 id(小写连字符),进持久化配置
"card": { "titleKey": "hello.cardTitle", "order": 90 }, // 没有卡片写 null
"tools": [{ "name": "hello_read", "writes": false }], // 没工具写 []
"host": { "inject": [] }, // 这个单元要外壳的哪几个服务(判"能不能挂")
"env": { "command": "opencli", "plugins": [], "libs": [] } // 可选:靠什么才跑得起来
},
"workbenchFaces": { "host": "src/host.ts", "client": "src/client.tsx" } // 工具链那一格(不在协议里):两半的源码入口五条口径:
- 声明了
apiVersion= 宣布静态半写全了 ——unit/card/tools/host四个键都必须有(card没有卡片写null),env没有外部供给时省略。 - 不许有协议不认识的键:生字段会被外壳静默忽略(拼错一个键就等于那句话没写),
所以
protocol判据先拦。scope不在协议里:它曾经是(card.scope/tools[].scope), 现已删除 —— 一个能力在哪些工作区出现只由用户的板决定,作者写它 = 写了一个生字段、当场红 (protocol会点名"scope")。见 ADR-0038 §2.4 / §6.16。 - 清单声明的工具 = 代码真正注册的工具(U1b 起):清单是工具面的唯一来源,
contracts拿mount()里registerTools()真正注册的名字对账,两边漂了就红。 - 底稿 ↔ 清单只对账键集合(U1c 起):
design.json的capabilities[].name与清单的tools[].name不重不漏,只对名字(内容各写一处,没有可比的东西);没有design.json的模块不查 —— 底稿是可选的设计材料。见 ADR-0038 §2.5 / §6.3。 dsh.workbenchFaces不是协议的一部分,但门禁必填(A-2 起):它是dsh.workbench的 兄弟键,写两半的源码入口;source判据靠它算"这段源码属于哪一半"。 写进dsh.workbench里会被判生字段(不留兼容),它也不能指向出货产物 —— 从dist/host.js反推不出是哪份源码把 dsh 的包拖进来的。见 ADR-0038 §7 第 7 条。
两个模板
| 模板 | 是什么 |
|---|---|
| minimal(默认) | 空壳:卡壳、文案、测试接好了,没有数据源 |
| diy | 一份真能跑的样板:宿主侧一条只读路由真读盘、卡片五态、?wbMock=1 三档夹具,三张表也是填好的 |
init 会连模板里的 *.tpl 一起拷过去、把 __UNIT__ / __NAME__ / __DESC__ 填上、剥掉 .tpl 后缀,
再用 design.json 生成 README 那一段。
自己的自检
node scripts/selfcheck.mjs工具箱的回归网:两个模板各 init 一遍、各跑全套(门禁 + 五个脚本);判据的正例与负例都要对;
打包清单不含 .tpl 残留;design 的空格、README 同步、accept;publish 的清单。
去哪看"为什么"
模块怎么写、DIY 那套流程怎么走,见外壳包里的指引:@dsh-workbench/core 的
skills/workbench-module-diy/**(SKILL.md / BUILD.md / WIRING.md / DESIGN.md / PANEL.md /
TOOLS.md / LINKAGE.md / DATASOURCE.md / REVIEW.md / TOOLING.md / STEPS.md)。
架构上的取舍写在工作台仓库的 docs/adr/**。
