@dsh-workbench/core 0.2.16 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +6 -2
  2. package/bin/dsh-workbench +17 -15
  3. package/client.js +359 -64
  4. package/dist/client/client.body.js +359 -64
  5. package/dist/client/index.js +658 -2978
  6. package/dist/host/index.js +443 -385
  7. package/dist/types/app/client.d.ts +3 -0
  8. package/dist/types/app/layouts/rightbar/BoardGrid.d.ts +23 -0
  9. package/dist/types/app/layouts/rightbar/board-columns.d.ts +17 -4
  10. package/dist/types/app/layouts/rightbar/rightbar-width.d.ts +16 -0
  11. package/dist/types/app/layouts/rightbar/use-board-split.d.ts +8 -0
  12. package/dist/types/modules/panels/model/diy-report.d.ts +13 -2
  13. package/dist/types/shared/api/host/diy-workshop.d.ts +13 -0
  14. package/dist/types/shared/api/host/runtime-seed.d.ts +0 -2
  15. package/docs/HANDOFF.md +43 -10
  16. package/docs/OPERATIONS.md +52 -0
  17. package/package.json +4 -3
  18. package/preset/diy.patch.yml +3 -0
  19. package/scripts/seed-workshop.sh +461 -13
  20. package/skills/workbench-module-diy/BUILD.md +11 -7
  21. package/skills/workbench-module-diy/DATASOURCE.md +3 -4
  22. package/skills/workbench-module-diy/DESIGN.md +3 -4
  23. package/skills/workbench-module-diy/KIT.md +11 -12
  24. package/skills/workbench-module-diy/LINKAGE.md +6 -7
  25. package/skills/workbench-module-diy/PANEL.md +9 -10
  26. package/skills/workbench-module-diy/REVIEW.md +2 -3
  27. package/skills/workbench-module-diy/SKILL.md +2 -3
  28. package/skills/workbench-module-diy/TOOLING.md +3 -8
  29. package/skills/workbench-module-diy/TOOLS.md +4 -9
  30. package/skills/workbench-module-diy/WIRING.md +3 -3
  31. package/dist/types/app/layouts/__tests__/async-feedback.test.d.ts +0 -1
  32. package/dist/types/app/layouts/__tests__/kit-preview-nav.test.d.ts +0 -1
  33. package/dist/types/app/layouts/__tests__/panel-hint.test.d.ts +0 -1
  34. package/dist/types/app/layouts/__tests__/project-selection.test.d.ts +0 -1
  35. package/dist/types/app/layouts/env-gate/__tests__/force-plan.test.d.ts +0 -1
  36. package/dist/types/app/layouts/env-gate/__tests__/gate-deadline.test.d.ts +0 -1
  37. package/dist/types/app/layouts/env-gate/__tests__/gate-hidden.test.d.ts +0 -1
  38. package/dist/types/app/layouts/env-gate/__tests__/gate-mocks.test.d.ts +0 -1
  39. package/dist/types/app/layouts/env-gate/gate-mock.d.ts +0 -18
  40. package/dist/types/app/layouts/market/__tests__/add-module-mock.test.d.ts +0 -1
  41. package/dist/types/app/layouts/market/__tests__/add-module-stages.test.d.ts +0 -1
  42. package/dist/types/app/layouts/market/__tests__/add-module-text.test.d.ts +0 -1
  43. package/dist/types/app/layouts/market/add-module-mock.d.ts +0 -14
  44. package/dist/types/app/layouts/rightbar/BoardMockStrip.d.ts +0 -5
  45. package/dist/types/app/layouts/rightbar/__tests__/board-fact.test.d.ts +0 -1
  46. package/dist/types/app/layouts/rightbar/__tests__/board-mock.test.d.ts +0 -1
  47. package/dist/types/app/layouts/rightbar/__tests__/board-plan.test.d.ts +0 -1
  48. package/dist/types/app/layouts/rightbar/__tests__/board-selection.test.d.ts +0 -1
  49. package/dist/types/app/layouts/rightbar/__tests__/breadcrumbs.test.d.ts +0 -1
  50. package/dist/types/app/layouts/rightbar/__tests__/market-catalog.test.d.ts +0 -1
  51. package/dist/types/app/layouts/rightbar/__tests__/market-change.test.d.ts +0 -1
  52. package/dist/types/app/layouts/rightbar/__tests__/market-dots.test.d.ts +0 -1
  53. package/dist/types/app/layouts/rightbar/__tests__/market-freshness.test.d.ts +0 -1
  54. package/dist/types/app/layouts/rightbar/__tests__/market-hint-visible.test.d.ts +0 -1
  55. package/dist/types/app/layouts/rightbar/__tests__/market-installed.test.d.ts +0 -1
  56. package/dist/types/app/layouts/rightbar/__tests__/market-live.test.d.ts +0 -1
  57. package/dist/types/app/layouts/rightbar/__tests__/market-mock.test.d.ts +0 -1
  58. package/dist/types/app/layouts/rightbar/__tests__/market-order.test.d.ts +0 -1
  59. package/dist/types/app/layouts/rightbar/__tests__/market-row-icon.test.d.ts +0 -1
  60. package/dist/types/app/layouts/rightbar/__tests__/market-rows-libs.test.d.ts +0 -1
  61. package/dist/types/app/layouts/rightbar/__tests__/market-rows-plugins.test.d.ts +0 -1
  62. package/dist/types/app/layouts/rightbar/__tests__/market-rows.test.d.ts +0 -1
  63. package/dist/types/app/layouts/rightbar/__tests__/market-running-display.test.d.ts +0 -1
  64. package/dist/types/app/layouts/rightbar/__tests__/market-section-icon.test.d.ts +0 -1
  65. package/dist/types/app/layouts/rightbar/__tests__/market-settle.test.d.ts +0 -1
  66. package/dist/types/app/layouts/rightbar/__tests__/market-shared.test.d.ts +0 -1
  67. package/dist/types/app/layouts/rightbar/__tests__/market-state-rules.test.d.ts +0 -1
  68. package/dist/types/app/layouts/rightbar/__tests__/market-workbench-act.test.d.ts +0 -1
  69. package/dist/types/app/layouts/rightbar/__tests__/market-workbench.test.d.ts +0 -1
  70. package/dist/types/app/layouts/rightbar/__tests__/panel-dismiss.test.d.ts +0 -1
  71. package/dist/types/app/layouts/rightbar/__tests__/panel-drag-target.test.d.ts +0 -1
  72. package/dist/types/app/layouts/rightbar/__tests__/panel-mock.test.d.ts +0 -1
  73. package/dist/types/app/layouts/rightbar/__tests__/panel-plugin-rows.test.d.ts +0 -1
  74. package/dist/types/app/layouts/rightbar/__tests__/panel-scope-ui.test.d.ts +0 -1
  75. package/dist/types/app/layouts/rightbar/__tests__/panel-write.test.d.ts +0 -1
  76. package/dist/types/app/layouts/rightbar/__tests__/suite-world.test.d.ts +0 -1
  77. package/dist/types/app/layouts/rightbar/__tests__/use-panels.test.d.ts +0 -1
  78. package/dist/types/app/layouts/rightbar/board-mock.d.ts +0 -22
  79. package/dist/types/app/layouts/rightbar/kit-preview-controls.d.ts +0 -11
  80. package/dist/types/app/layouts/rightbar/kit-preview-frame.d.ts +0 -18
  81. package/dist/types/app/layouts/rightbar/kit-preview-hash.d.ts +0 -1
  82. package/dist/types/app/layouts/rightbar/kit-preview-rows.d.ts +0 -6
  83. package/dist/types/app/layouts/rightbar/kit-preview.d.ts +0 -3
  84. package/dist/types/app/layouts/rightbar/market-installed-mock.d.ts +0 -9
  85. package/dist/types/app/layouts/rightbar/market-mock-types.d.ts +0 -58
  86. package/dist/types/app/layouts/rightbar/market-mock.d.ts +0 -4
  87. package/dist/types/app/layouts/rightbar/panel-mock.d.ts +0 -27
  88. package/dist/types/app/layouts/sidebar/__tests__/current-workspace.test.d.ts +0 -1
  89. package/dist/types/app/layouts/sidebar/__tests__/debug-ui.test.d.ts +0 -1
  90. package/dist/types/app/layouts/sidebar/__tests__/session-pick.test.d.ts +0 -1
  91. package/dist/types/app/layouts/sidebar/__tests__/session-row-ui.test.d.ts +0 -1
  92. package/dist/types/app/layouts/sidebar/__tests__/workspace-groups.test.d.ts +0 -1
  93. package/dist/types/app/layouts/sidebar/__tests__/workspace-name.test.d.ts +0 -1
  94. package/dist/types/app/units/__tests__/fixture-unit-mock.test.d.ts +0 -1
  95. package/dist/types/app/units/__tests__/manifests.test.d.ts +0 -1
  96. package/dist/types/app/units/__tests__/registry.test.d.ts +0 -1
  97. package/dist/types/app/units/fixture-unit-mock.d.ts +0 -7
  98. package/dist/types/dev/MockStrip.d.ts +0 -15
  99. package/dist/types/dev/surface-types.d.ts +0 -53
  100. package/dist/types/dev/surface.d.ts +0 -2
  101. package/dist/types/dev/surface.stub.d.ts +0 -2
  102. package/dist/types/modules/panels/__tests__/approval.test.d.ts +0 -1
  103. package/dist/types/modules/panels/__tests__/config.test.d.ts +0 -1
  104. package/dist/types/modules/panels/__tests__/diy-harness.d.ts +0 -105
  105. package/dist/types/modules/panels/__tests__/diy-report.test.d.ts +0 -1
  106. package/dist/types/modules/panels/__tests__/diy-tools-health.test.d.ts +0 -1
  107. package/dist/types/modules/panels/__tests__/diy-tools-panel.test.d.ts +0 -1
  108. package/dist/types/modules/panels/__tests__/diy-tools-status.test.d.ts +0 -1
  109. package/dist/types/modules/panels/__tests__/diy-tools.test.d.ts +0 -1
  110. package/dist/types/modules/panels/__tests__/face.test.d.ts +0 -1
  111. package/dist/types/modules/panels/__tests__/market-bundle.test.d.ts +0 -1
  112. package/dist/types/modules/panels/__tests__/market-dependency.test.d.ts +0 -1
  113. package/dist/types/modules/panels/__tests__/market-dispatch.test.d.ts +0 -1
  114. package/dist/types/modules/panels/__tests__/market-env.test.d.ts +0 -1
  115. package/dist/types/modules/panels/__tests__/market-plugin.test.d.ts +0 -1
  116. package/dist/types/modules/panels/__tests__/market-registries.test.d.ts +0 -1
  117. package/dist/types/modules/panels/__tests__/market-route.test.d.ts +0 -1
  118. package/dist/types/modules/panels/__tests__/market-tools-harness.d.ts +0 -45
  119. package/dist/types/modules/panels/__tests__/market-tools.test.d.ts +0 -1
  120. package/dist/types/modules/panels/__tests__/market-update.test.d.ts +0 -1
  121. package/dist/types/modules/panels/__tests__/market-workbench-update.test.d.ts +0 -1
  122. package/dist/types/modules/panels/__tests__/market.test.d.ts +0 -1
  123. package/dist/types/modules/panels/__tests__/plugin-actions.test.d.ts +0 -1
  124. package/dist/types/modules/panels/__tests__/plugin-ledger.test.d.ts +0 -1
  125. package/dist/types/modules/panels/__tests__/plugin-panel-market-parity.test.d.ts +0 -1
  126. package/dist/types/modules/panels/__tests__/plugin-panel.test.d.ts +0 -1
  127. package/dist/types/modules/panels/__tests__/plugin-section.test.d.ts +0 -1
  128. package/dist/types/modules/panels/__tests__/plugin-tool-units-harness.d.ts +0 -69
  129. package/dist/types/modules/panels/__tests__/plugin-tool-units.test.d.ts +0 -1
  130. package/dist/types/modules/panels/__tests__/prefs.test.d.ts +0 -1
  131. package/dist/types/modules/panels/__tests__/routes.test.d.ts +0 -1
  132. package/dist/types/modules/panels/__tests__/scope-machine.test.d.ts +0 -1
  133. package/dist/types/modules/panels/__tests__/scope-support.d.ts +0 -51
  134. package/dist/types/modules/panels/__tests__/scope.test.d.ts +0 -1
  135. package/dist/types/modules/panels/__tests__/service-release.test.d.ts +0 -1
  136. package/dist/types/modules/panels/__tests__/service.test.d.ts +0 -1
  137. package/dist/types/modules/panels/__tests__/tools.test.d.ts +0 -1
  138. package/dist/types/shared/__tests__/host-import-barrel.test.d.ts +0 -1
  139. package/dist/types/shared/__tests__/i18n-keys.test.d.ts +0 -1
  140. package/dist/types/shared/api/__tests__/context-ref.test.d.ts +0 -1
  141. package/dist/types/shared/api/host/__tests__/approval-note-injection.test.d.ts +0 -1
  142. package/dist/types/shared/api/host/__tests__/capability-force.test.d.ts +0 -1
  143. package/dist/types/shared/api/host/__tests__/cli-error.test.d.ts +0 -1
  144. package/dist/types/shared/api/host/__tests__/config-sync.test.d.ts +0 -1
  145. package/dist/types/shared/api/host/__tests__/context-inject.test.d.ts +0 -1
  146. package/dist/types/shared/api/host/__tests__/data-root.test.d.ts +0 -1
  147. package/dist/types/shared/api/host/__tests__/diy-debug-act.test.d.ts +0 -1
  148. package/dist/types/shared/api/host/__tests__/events.test.d.ts +0 -1
  149. package/dist/types/shared/api/host/__tests__/fact-writes.test.d.ts +0 -1
  150. package/dist/types/shared/api/host/__tests__/facts.test.d.ts +0 -1
  151. package/dist/types/shared/api/host/__tests__/host-args.test.d.ts +0 -1
  152. package/dist/types/shared/api/host/__tests__/long-task.test.d.ts +0 -1
  153. package/dist/types/shared/api/host/__tests__/panel-state-route.test.d.ts +0 -1
  154. package/dist/types/shared/api/host/__tests__/plugin-catalog.test.d.ts +0 -1
  155. package/dist/types/shared/api/host/__tests__/plugin-login-hint.test.d.ts +0 -1
  156. package/dist/types/shared/api/host/__tests__/plugin-source.test.d.ts +0 -1
  157. package/dist/types/shared/api/host/__tests__/plugin-tools.test.d.ts +0 -1
  158. package/dist/types/shared/api/host/__tests__/png-fixtures.d.ts +0 -17
  159. package/dist/types/shared/api/host/__tests__/post-channels.test.d.ts +0 -1
  160. package/dist/types/shared/api/host/__tests__/preflight-fixtures.d.ts +0 -19
  161. package/dist/types/shared/api/host/__tests__/preflight-warm.test.d.ts +0 -1
  162. package/dist/types/shared/api/host/__tests__/preflight.test.d.ts +0 -1
  163. package/dist/types/shared/api/host/__tests__/probe-cache.test.d.ts +0 -1
  164. package/dist/types/shared/api/host/__tests__/probe-libs.test.d.ts +0 -1
  165. package/dist/types/shared/api/host/__tests__/probe-units-cache.test.d.ts +0 -1
  166. package/dist/types/shared/api/host/__tests__/probe-units-npm-source.test.d.ts +0 -1
  167. package/dist/types/shared/api/host/__tests__/probe-units-release.test.d.ts +0 -1
  168. package/dist/types/shared/api/host/__tests__/probe-units.test.d.ts +0 -1
  169. package/dist/types/shared/api/host/__tests__/probe-verdict.test.d.ts +0 -1
  170. package/dist/types/shared/api/host/__tests__/profile-registries.test.d.ts +0 -1
  171. package/dist/types/shared/api/host/__tests__/provision-dependency.test.d.ts +0 -1
  172. package/dist/types/shared/api/host/__tests__/registry-declaration.test.d.ts +0 -1
  173. package/dist/types/shared/api/host/__tests__/release.test.d.ts +0 -1
  174. package/dist/types/shared/api/host/__tests__/self-update.test.d.ts +0 -1
  175. package/dist/types/shared/api/host/__tests__/tool-approval.test.d.ts +0 -1
  176. package/dist/types/shared/api/host/__tests__/tool-kit.test.d.ts +0 -1
  177. package/dist/types/shared/api/host/__tests__/tool-scope.test.d.ts +0 -1
  178. package/dist/types/shared/api/host/__tests__/tool-surface.test.d.ts +0 -1
  179. package/dist/types/shared/api/host/__tests__/unit-face.test.d.ts +0 -1
  180. package/dist/types/shared/api/host/__tests__/unit-readiness.test.d.ts +0 -1
  181. package/dist/types/shared/api/host/__tests__/unit-registry.test.d.ts +0 -1
  182. package/dist/types/shared/api/host/__tests__/unit-roster-facts.test.d.ts +0 -1
  183. package/dist/types/shared/api/host/__tests__/value-handoff.test.d.ts +0 -1
  184. package/dist/types/shared/api/host/__tests__/version-range.test.d.ts +0 -1
  185. package/dist/types/shared/api/host/__tests__/workspace-store.test.d.ts +0 -1
  186. package/dist/types/shared/api/host/__tests__/write-result.test.d.ts +0 -1
  187. package/dist/types/shared/hooks/__tests__/mock-mode.test.d.ts +0 -1
  188. package/dist/types/shared/hooks/__tests__/use-api-resource.test.d.ts +0 -1
  189. package/dist/types/shared/hooks/__tests__/use-capabilities.test.d.ts +0 -1
  190. package/dist/types/shared/hooks/__tests__/use-visible-busy.test.d.ts +0 -1
  191. package/dist/types/shared/hooks/mock-mode.d.ts +0 -2
  192. package/dist/types/shared/hooks/use-fixture-pick.d.ts +0 -20
  193. /package/dist/types/app/{__tests__/workbench-styles.test.d.ts → layouts/rightbar/rightbar-width.test.d.ts} +0 -0
@@ -89,7 +89,7 @@ h(Field, { label: t('myunit.mode'), hint: t('myunit.modeHint') },
89
89
  **`FormActions`** —— **操作区**(一组按钮):`actions: { key, label, kind?: 'default' | 'danger' | 'primary', onClick, disabled?, busy? }[]`。
90
90
  **顺序 / 间距 / 换行都归它** —— `primary` 永远在右、`danger` 紧挨它左侧、一个区只许一颗 `primary`、
91
91
  窄了自动折行且 `primary` 落在右下角;`busy` 自带 `Spinner`。调用点只给"有哪些动作、哪个是主要、点了做什么":
92
- **别自己写 `gap` / `margin` / 顺序,也别借 `.wb-formActions` 槽类手摆**(`check:style` 的 F3 会红,没有豁免)。
92
+ **别自己写 `gap` / `margin` / 顺序,也别借 `.wb-formActions` 槽类手摆**(`check --only style` 的 F3 会红)。
93
93
 
94
94
  ```tsx
95
95
  h(FormActions, { actions: [
@@ -99,10 +99,10 @@ h(FormActions, { actions: [
99
99
  ```
100
100
 
101
101
  `danger` 只标"这是破坏性的"(渲成描边 + 危险色,**永远不当填充的 `primary`**);**二次确认那半归调用点**
102
- (先问一句或弹窗都行),口径见 [ADR-0054](../../../../docs/adr/0054-the-action-area-is-one-component.md) §2 规则三。
102
+ (先问一句或弹窗都行)。
103
103
 
104
104
  **别手写 `<button>` / `<input>` / `<select>`**:dsh 有 `Button`(`variant` / `size`),
105
- kit 有上面这几件;手写的会拿到浏览器默认样式,而且**判据会红**(`check:style`)。
105
+ kit 有上面这几件;手写的会拿到浏览器默认样式,而且**判据会红**(`check --only style`)。
106
106
  `<textarea>` 例外(dsh 与 kit 都没有多行输入)——真要用就直接写,其余形态别开这个口子。
107
107
 
108
108
  控件怎么排成一行(标签位置、错误态、尺寸)见 §5。
@@ -120,7 +120,7 @@ h(FormRows, null,
120
120
  h(ChoiceGroup, { label: t('myunit.env'), name: 'env', options, value: env, onChange: setEnv })))
121
121
  ```
122
122
 
123
- - **标签归 `FormRow`**(`label`):默认标签在左,`layout: 'stacked'` 才是上下堆叠(等于原来的 `Field`)。
123
+ - **标签归 `FormRow`**(`label`):默认标签在左,`layout: 'stacked'` 才是上下堆叠(`Field` 那种排布)。
124
124
  **控件只给数据与语义 prop**,不写外观类名(§7 第 1 条)。进了 `FormRow` 就别再给控件自己的
125
125
  `label` / `hint`(`SelectField` 那两件是没 `FormRow` 时的兜底,重复给会多一个标签、还退回上下堆叠)。
126
126
  - **`hint` 与 `problem` 二选一**:给了 `problem` 就不画 `hint` —— 同一格不叠两段话,有错先显示错。
@@ -145,18 +145,15 @@ h(FormRows, null,
145
145
  **反例(别这么写)**:
146
146
 
147
147
  ```tsx
148
- h('span', { className: styles.label }, t('myunit.mode')) // ← 紧邻控件的手写标签行:check:style 红
148
+ h('span', { className: styles.label }, t('myunit.mode')) // ← 紧邻控件的手写标签行:`check --only style` 红
149
149
  h('div', { className: styles.form }, …) // ← .form { gap: 8px }:自己管行距也红
150
150
  ```
151
151
 
152
- `<span className={styles.label}>` 紧邻控件、或给表单容器自己写 `gap` —— 这正是 `check:style` 那条
153
- 棘轮(F1 手写行 / F2 自己管行距)盯的东西;`FORM_ROW_EXEMPT` 是这张表的历史账,**2026-10-17 已经清空**
154
- (外壳 0.2.13 之后按"迁一处删一行"迁完,ADR-0052 §10)—— 表空了仍然**不是"可以继续这么写"的许可**:
155
- 现在再这么写直接红,没有豁免那一层。
152
+ `<span className={styles.label}>` 紧邻控件、或给表单容器自己写 `gap` —— 这正是 `check --only style` 那条
153
+ 棘轮(F1 手写行 / F2 自己管行距)盯的东西:这么写直接红。
156
154
 
157
155
  **时点**:这一层随外壳**发版**后模块才能用 —— 模块的 `peerDependencies` 下限得先有它
158
- (`check:kit` 拿 peer 下限那份外壳比,不抬必红);迁移步骤见
159
- [ADR-0052](../../../../docs/adr/0052-the-form-row-is-one-component.md) §10。已迁完的包下限在 `^0.2.14`。
156
+ (`check --only kit` 拿 peer 下限那份外壳比,不抬必红)。包下限是 `^0.2.14`。
160
157
 
161
158
  ## 6 别的
162
159
 
@@ -166,7 +163,9 @@ h('div', { className: styles.form }, …) // ← .form { gap:
166
163
  - **`Stack`** —— 竖排 + 统一间距(懒得分组时的默认容器)。
167
164
  - **`BlockerState`** —— 阻断屏:要登录 / 没权限 / 能力没装好那一类(`blocker` / `t` / `onRetry` / `onOpenMarket`)。
168
165
  - **`Tip`** —— Tooltip:图标钮与只有图的地方**必须**有它(或 `aria-label`)。
169
- - **别给模块带夹具**:2026-10-16 起模板 / `init` 文案 / 这份指引都不带评审夹具了(`?wbMock=1` 那套、`useFixturePick` / `MockStrip` / `mockNote` 都从模板里删了)。夹具是模块作者负担里最不值的那一份 —— 而**你自己那份 `plugin.test.ts` 就能把五态各喂一遍**,而 `check:cards` 会拿七种外壳侧输入各喂一遍(它只问"退化得干不干净",不断言"画的是哪一态那一屏")。外壳自己那套 `?wbMock=1` 夹具是给**外壳的卡片**用的,模块不必跟(机制仍在,谁想要仍然可以用,但**不是你要做的事**)。
166
+ - **真机上造不出来的那几态**:**拿你自己那份 `plugin.test.ts` 把五态各喂一遍**就够;
167
+ `check --only cards` 还会拿**七种外壳侧输入**各喂一遍(它只问"退化得干不干净",
168
+ 不断言"画的是哪一态那一屏")。
170
169
  - **图标** —— `IconPanelScreen`(面板/卡片那类)、`IconModuleMark`(我们的模块类型标)、
171
170
  `IconNpm` / `IconOpencli`(包类型);其余图形一律从 dsh 的 `Icon*Regular` 拿,**别自己画图标**。
172
171
 
@@ -94,8 +94,7 @@
94
94
 
95
95
  三句都写进能力清单(用户看的是"哪一格会跟着动")。
96
96
 
97
- → 实现与逐工具那张表:本文 §1 · 工作台仓库里的 `docs/adr/0023-read-tools-claim-facts.md` §2.3
98
- (工程域的实现落点见 `.agents/skills/module-design/IMPLEMENTATION.md` §5)。
97
+ → 实现:本文 §1 与 §7。
99
98
 
100
99
  ## 8 宿主侧的四个口子(实现形状)
101
100
 
@@ -119,7 +118,7 @@ const resource = useApiResource(ROUTE, query, rev, {});
119
118
 
120
119
  卡片的 `useApiResource` **默认就订阅** `factOfRoute(route)`(`use-api-resource.ts` 里那句
121
120
  `options.fact ?? factOfRoute(route)`),所以多数情况你什么都不用接;用户自己按的那个动作做完,
122
- 用 `useFactInvalidate()()` 把这条事实标脏(cmdb 的发布就是这么做的)。
121
+ 用 `useFactInvalidate()()` 把这条事实标脏。
123
122
 
124
123
  ```ts
125
124
  context: { kinds: ['module'], render: async (ref) => `模块 ${ref.parts[0]}:…` },
@@ -131,13 +130,13 @@ warmReads: () => [['<unit>', '<target>']],
131
130
  判据只查形状(`kinds` 非空、`render` 是函数),**不会拿假参数调它** —— 那些参数只有真引用才有。
132
131
  * `warmReads`:**只给"走 opencli 适配器"的读用**。条目就是那条 opencli 命令的 argv,外壳在启动的
133
132
  preflight 里拼成 `opencli <argv…> --site-session persistent -f json` 先跑一遍(把站点登录态与首屏焐热)。
134
- 例:成熟模块 cmdb 的 `[['cmdb', 'enterprises']]`(`module-cmdb/src/model/warm.ts`,还带测试)。
133
+ 例:`[['cmdb', 'enterprises']]`(一条 opencli 命令的 argv,还带测试)。
135
134
  **本机读盘、browser bridge、直接打接口的读一律不要写这里** —— 写了外壳会去跑一条不存在的命令,
136
- preflight 只会给个 warn;这些读没有"冷启动"可省,焐不热任何东西。工坊里四个模块就是刻意不写的。
135
+ preflight 只会给个 warn;这些读没有"冷启动"可省,焐不热任何东西。
137
136
  * `values`(`deps.values`,`ValueHandoff`):把一次写的结果交给别的单元 —— `values.hand({fact, key}, 值)`,
138
137
  另一边 `values.take({fact, key})` 取;`key` 自己起(例:一次发布的结果给联动那一格用)。
139
138
 
140
139
  ## 9 范例
141
140
 
142
- 范例与来龙去脉都在**工作台仓库里**:`.agents/skills/module-design/EXAMPLES.md` §3
143
- (逐工具那张表、值交接、刷新下限、收起模块的来龙去脉)—— 工坊会话里够不到那儿。
141
+ 要一个"同形状、能跑"的样子:[SKILL.md](SKILL.md) 的「找不到一件事的时候」—— 模板
142
+ (`template-diy/` / `template/`)与装机模块的源码都可以直接读。
@@ -74,7 +74,7 @@
74
74
  | `view` | 卡片底部一次性的选择(看哪种口径、看几天) | 回默认 | 当 **route 参数**传给模块自己的只读口;非法的退路写进 `wrongChoice` |
75
75
  | `prefs` | 他配一次、以后一直算数(钉哪个环境、忽略哪些、超时多久) | **还在** | `mount` 返回 `prefs: { resource, handle }`,`handle` 里用 `deps.store` 落盘 |
76
76
 
77
- **宿主半侧**(最小可抄;工坊里 `module-diy-doctor/src/prefs.ts` 是完整例子):
77
+ **宿主半侧**(最小可抄):
78
78
 
79
79
  ```ts
80
80
  // mount(deps) 里。按项目分开记:这个项目一份,换项目不串
@@ -99,7 +99,7 @@ const write = useHostWrite({ channel: 'prefs', resource: 'your-module' });
99
99
  write.send({ ignored, timeoutSeconds, workspace });
100
100
  ```
101
101
 
102
- `handle` 里那几件事(成熟模块都这么做,`argocd` 的 `prefs.test.ts` 把每一条都钉住了):
102
+ `handle` 里那几件事(成熟模块都这么做):
103
103
 
104
104
  - **未设置 ≠ 空**:没写过就出"第一次选"那一屏;显式选空是"空态",两者不能混;
105
105
  - **清空 = 回到默认,并把文件收掉**(不留一个空对象);
@@ -128,7 +128,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
128
128
  它内部已经把 dsh 的图标原语包好了,所以模块**不用**为它声明 `client.external`。
129
129
  - **"去看某处"用哪个**:跳**整张卡对应的系统** → 卡头的图标按钮(`CardHead.platformHref`:只有图标 + Tooltip。
130
130
  **给这一个就够了**,那颗 ↗ 立刻就画;`platform` / `platformTitle` 是可选的,只决定 Tooltip 与
131
- `aria-label` 上的字 —— 以前的实现要两个都给才画,少给一个就静默少一颗按钮);
131
+ `aria-label` 上的字 —— 少给一个**不会**少画那颗 ↗);
132
132
  跳**一个具体页面 / 一条具体记录** → `Link`(正文里的文字链接);**触发一个动作**(刷新、重建、去登录)→
133
133
  dsh 的 `Button`,或阻断屏里的 `action`。区别在"跳去哪"和"它是不是一个动作",不在好看不好看。
134
134
  - **标签 + 输入框的排布用 `Field`**,输入框用 `TextField` —— 内边距与排版是外壳给的默认,
@@ -164,7 +164,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
164
164
  - **平台没给的那一格就不占位**(不留孤零零的字段名、不留空的一行)。
165
165
  - **读不到就说读不到**,并说清为什么(例:手上这份能力太旧);**绝不显示 0**。
166
166
  - 有确定答案就不打扰他(能按默认读出来就别弹设置面)。
167
- - 真机上造不出来的状态也要**在设计上**画出来(照这一格写清)—— 但**不必为它写夹具**:2026-10-16 起模板与指引都不带评审夹具,模块自己的 `plugin.test.ts` 把五态各喂一遍就够(`check:cards` 会拿**七种外壳侧输入**各喂一遍 —— 它只问"退化得干不干净",**不断言**"画的是哪一态那一屏")。
167
+ - 真机上造不出来的状态也要**在设计上**画出来(照这一格写清)—— 模块自己的 `plugin.test.ts` 把五态各喂一遍就够(`check --only cards` 会拿**七种外壳侧输入**各喂一遍 —— 它只问"退化得干不干净",**不断言**"画的是哪一态那一屏")。
168
168
 
169
169
  ### 7.1 图例就是把屏幕画成 ASCII
170
170
 
@@ -179,7 +179,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
179
179
  - **一行里那些记号挨着的样子**(状态点 + 编号 + 元信息 + 行尾两颗)
180
180
  - **状态点的几档**(只有颜色不同;**撞色的那两档要在图下点明靠什么分开**)
181
181
  - **可点的筛选**(几颗、选中的那颗什么样)
182
- - **只在某种模式出现的东西**(例:夹具条)
182
+ - **只在某种模式出现的东西**
183
183
  - **审批弹窗**(哪一行是套件给的、哪一行是系统给的、按钮在哪)
184
184
 
185
185
  三条写法:
@@ -187,12 +187,12 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
187
187
  - **用真字**:图里的文案用界面上真实那句(例「没有指派给你的缺陷。」),别写"一句空态文案"。
188
188
  - **别拿图标代替画面**:给状态起个名字、配个 `⛔` 这类符号,用户还是分不清;一眼能认的是**形状**(整卡换掉 vs 多一行)与**位置**(行首的点、行尾的两颗)。
189
189
  - **画不成的才写词**:动作、agent 的下一步、时间性的"不变 / 自己变",写成词并说清意思。
190
- - **真机上造不出来的状态**:沟通时照样画(画的是设计意图);实现时**要让它能用真实输入走到**(换个空目录、换个坏路径、先不选),而不是给它写夹具 —— 2026-10-16 起模板与指引都不带评审夹具,模块自己的 `plugin.test.ts` 把五态各喂一遍就够。
190
+ - **真机上造不出来的状态**:沟通时照样画(画的是设计意图);实现时**要让它能用真实输入走到**(换个空目录、换个坏路径、先不选),模块自己的 `plugin.test.ts` 把五态各喂一遍就够。
191
191
 
192
192
  ## 8 范例(真实产出的形状)
193
193
 
194
- 范例都在**工作台仓库里**:`.agents/skills/module-design/EXAMPLES.md` §1 —— 工坊会话里够不到那儿,
195
- 就照 [SKILL.md](SKILL.md) 的「找不到一件事的时候」读模板与装机模块的源码。
194
+ 要一个"同形状、能跑"的样子:[SKILL.md](SKILL.md) 的「找不到一件事的时候」—— 模板
195
+ (`template-diy/` / `template/`)与装机模块的源码都可以直接读。
196
196
 
197
197
  ## 9 界面边界:kit 不够用时怎么办
198
198
 
@@ -203,6 +203,5 @@ kit 里确实没有、而你要的又是标准控件(确认条、选择器、
203
203
  * 在 `package.json` 的 `dsh.client.external` 里**声明** `@deepseek-ai/dsh-client-ui-primitives`;
204
204
  * 宿主侧(`src/host.ts`)**一个字都不许碰** —— `check` 的源码边界判据会红。
205
205
 
206
- 理由不是"能省事":装机成熟模块里有一半的界面是这么搭的(argocd / cmdb / coding-issues / coding-analysis
207
- 四个包下 23 个文件引了这个包)。但**能拿 kit 的时候别自己画** —— kit 那套跟着外壳一起换主题、跟着语言走,
206
+ 理由不是"能省事":装机成熟模块里有一半的界面是这么搭的。但**能拿 kit 的时候别自己画** —— kit 那套跟着外壳一起换主题、跟着语言走,
208
207
  自己画的不会。
@@ -5,8 +5,8 @@
5
5
 
6
6
  | 判据 | 它防的事故 | 红了的典型说法 | 怎么修 |
7
7
  |---|---|---|---|
8
- | `contracts` | dsh 组合阶段**不校验**你 `package.json` 里的声明 —— 错的 `external` 要到浏览器 `require` 那一刻才炸;清单与代码、底稿与清单之间漂了也没人拦 | `单元 id "x" 与 … 撞了` / `dsh.workbenchFaces.client 指的文件不存在` / `dsh.workbenchFaces.host 没声明` / `没有对 @dsh-workbench/core 的 peer 依赖` / `没有 typecheck 脚本` / `它不是 private,却既没声明 publishConfig.access=public…` / `src/declared-tools.ts 与清单对不上(生成物过期…)` / `工具名的字面量又写回了源码` / `…没有 key` / `dsh.workbench 声明的能力与代码真正注册的对不上` / `design.json 的能力行里有「x」,清单的 tools[] 里却没有它` | 按报的那一条改 `package.json`(生成物对不上就跑 `dsh-wb-module sync`;工具名的字面量只许留在清单里);`unit` 换个不撞的名字;`dsh.workbenchFaces` 补上两个**源码**入口;四个脚本补全;私有不发就保持 `private: true`。**工具只声明在清单里**(`dsh.workbench.tools`)且必须与 `mount()` 里 `registerTools()` 真正注册的**不重不漏**;写了 `design.json` 的话,它的 `capabilities[].name` 与清单的 `tools[].name` 也要不重不漏(U1c 的**键集合对账**,只对名字 —— 内容各写一处);`gate.deniedTools` 是可选的运行期收窄,门禁不再对它做声明对账(协议里的 `scope` 已删 —— 哪些工作区出现由用户的板决定) |
9
- | `protocol` | `dsh.workbench` 是外壳读你得懂的那份声明:缺版本、形状不对、**多一个键**、枚举值不认都要在装机前拦下来。多出来的键最阴 —— 外壳会**静默忽略**它(拼错一个键 = 那句话白写) | `没有 apiVersion` / `apiVersion 是 99,这份只认 1` / `声明了 apiVersion 就要把静态半写全 —— 缺 dsh.workbench.tools` / `dsh.workbench 里有协议 v1 不认识的键 "faces"` / `card 里有不认的键 "enabledByDefault"`(这个键连外壳里都没有了 —— A-3 删的,见 [ADR-0038](../../../../docs/adr/0038-module-declaration-protocol.md) §6.7) / `tools[0] 里有协议不认的键 "scopes"` / `tools[0] 里有不认的键 "scope"`(`scope` 自本轮更正起**不在协议里**:能力在哪些工作区出现由用户的板决定,见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md)) | 补 `"apiVersion": 1`;把 `unit` / `card` / `tools` / `host` 四个键写全(没卡片写 `"card": null`、没工具写 `"tools": []`、一个服务都不要写 `"host": { "inject": [] }`);删掉协议外的键(`faces` 自 A-2 起搬到 `dsh.workbenchFaces`,写回 `dsh.workbench` 里就是生字段);`scope` **不要写**(协议不认它,写了就是生字段)。字段清单见 `dsh-wb-module` 的 README「协议」那一节 |
8
+ | `contracts` | dsh 组合阶段**不校验**你 `package.json` 里的声明 —— 错的 `external` 要到浏览器 `require` 那一刻才炸;清单与代码、底稿与清单之间漂了也没人拦 | `单元 id "x" 与 … 撞了` / `dsh.workbenchFaces.client 指的文件不存在` / `dsh.workbenchFaces.host 没声明` / `没有对 @dsh-workbench/core 的 peer 依赖` / `没有 typecheck 脚本` / `它不是 private,却既没声明 publishConfig.access=public…` / `src/declared-tools.ts 与清单对不上(生成物过期…)` / `工具名的字面量又写回了源码` / `…没有 key` / `dsh.workbench 声明的能力与代码真正注册的对不上` / `design.json 的能力行里有「x」,清单的 tools[] 里却没有它` | 按报的那一条改 `package.json`(生成物对不上就跑 `dsh-wb-module sync`;工具名的字面量只许留在清单里);`unit` 换个不撞的名字;`dsh.workbenchFaces` 补上两个**源码**入口;四个脚本补全;私有不发就保持 `private: true`。**工具只声明在清单里**(`dsh.workbench.tools`)且必须与 `mount()` 里 `registerTools()` 真正注册的**不重不漏**;写了 `design.json` 的话,它的 `capabilities[].name` 与清单的 `tools[].name` 也要不重不漏(**键集合对账**,只对名字 —— 内容各写一处);`gate.deniedTools` 是可选的运行期收窄 |
9
+ | `protocol` | `dsh.workbench` 是外壳读你得懂的那份声明:缺版本、形状不对、**多一个键**、枚举值不认都要在装机前拦下来。多出来的键最阴 —— 外壳会**静默忽略**它(拼错一个键 = 那句话白写) | `没有 apiVersion` / `apiVersion 是 99,这份只认 1` / `声明了 apiVersion 就要把静态半写全 —— 缺 dsh.workbench.tools` / `dsh.workbench 里有协议 v1 不认识的键 "faces"` / `card 里有不认的键 "enabledByDefault"` / `tools[0] 里有协议不认的键 "scopes"` / `tools[0] 里有不认的键 "scope"` | 补 `"apiVersion": 1`;把 `unit` / `card` / `tools` / `host` 四个键写全(没卡片写 `"card": null`、没工具写 `"tools": []`、一个服务都不要写 `"host": { "inject": [] }`);删掉协议外的键(`faces` 住在 `dsh.workbenchFaces`,写回 `dsh.workbench` 里就是生字段);`scope` **不要写**。字段清单见 `dsh-wb-module` 的 README「协议」那一节 |
10
10
  | `bundles` | 两个运行时互串:浏览器产物里带 node 内置、宿主产物里带 DOM / react | `浏览器产物里出现了 node 内置 …` / `宿主产物里出现了 react` | 宿主面别 import 浏览器侧的东西;浏览器面别 import `node:*`。两侧只通过服务名相接 |
11
11
  | `source` | 非种子词的 `@deepseek-ai/*`、宿主侧碰 dsh 的浏览器包、`@/` 指到工作台源码 | `…在宿主侧可达` / `不是平台种子词` | 宿主侧只用 Node 侧的东西;dsh 原语一律走 `kit`;`@/` 只指自己的 `src/` |
12
12
  | `primitives` | 声明了 `external` 却没有产物物证 ⇒ dsh 原语被**内联**成第二份实例 | `…用了却没声明 external` / `宿主产物里出现了` | 在 `dsh.client.external` 里显式声明它;确认产物里是 `require(...)` 而不是被打包进来 |
@@ -22,7 +22,6 @@
22
22
  判据自己也有正例与负例,正常不会误报。但有一种红是**模板/工具坏了**而不是你写错了:
23
23
 
24
24
  - 骨架是刚 `init` 出来的、**一行都没改**,却红了 —— 那是模板的问题,不是你的。
25
- 工作台仓库里有一条判据盯着这件事(生成一个骨架跑全套,红就是门禁坏了)。
26
25
 
27
26
  ## 三条"不是判据、但更常踩"的
28
27
 
@@ -68,9 +68,8 @@ description: 在工作台里凭需求造一个模块(面板上的一块内容
68
68
  `node_modules/@dsh-workbench/core/skills/workbench-module-diy/**` 就是这份指引。
69
69
  它的 README 与 `docs/HANDOFF.md` / `docs/OPERATIONS.md` 也在包里。
70
70
 
71
- ⚠️ **别去工坊外面找**:这几份指引里出现的 `docs/adr/**`、`.scratch/**`、`packages/**`
72
- 是**工作台仓库里**的路径(只有你恰好在那份仓库里时才有)。工坊里的会话够不到它们 ——
73
- `node_modules/@dsh-workbench/…` 才是你在工坊里够得到的那一份。
71
+ ⚠️ **你手上就是这两份**:工坊会话里够得到的是 `node_modules/@dsh-workbench/…` ——
72
+ 外壳与 `dsh-wb-module` 都在那儿;别处没有。
74
73
 
75
74
  ## 三条不许松的
76
75
 
@@ -14,10 +14,10 @@
14
14
  |---|---|
15
15
  | 十一条判据([REVIEW.md](REVIEW.md)) | `dsh-wb-module check`(`--only <判据>` 单跑;`--only kit` 列这份外壳的 kit 成员) |
16
16
  | 落点、文件形状、四个脚本([BUILD.md](BUILD.md) §1–§2) | `dsh-wb-module init --template diy`(骨架带一条真读盘的数据源)+ `scripts/smoke.mjs` |
17
- | 装、上板、不重装([WIRING.md](WIRING.md) §3) | `workbench_diy_install` / `workbench_diy_show` / `workbench_diy_status`(工坊那一跳自己上板,不再指向 `workbench_panels_show`) |
17
+ | 装、上板、不重装([WIRING.md](WIRING.md) §3) | `workbench_diy_install` / `workbench_diy_show` / `workbench_diy_status`(工坊那一跳自己上板) |
18
18
  | 它到底起得来没(装配抛的错 / 声明被拒的原文) | `workbench_diy_status`("起得来"那一行,见 [REVIEW.md](REVIEW.md) 四步取证的第二步) |
19
19
  | 这一页的控制台 / 网络怎么取证([REVIEW.md](REVIEW.md) 四步取证) | `workbench_diy_logs_watch` / `_read` / `_stop`(钩子有上限:每页 200 条、单条 400 字);`workbench_diy_net_watch` / `_read` / `_stop`(最多 2000 行 / 15 分钟后自己收工;`_read key=…` 取 body)。**别用 `opencli browser <会话> console`**:那条命令拿到的是 stub,恒回空数组。网络那一头工作台走的是**隔离 opencli**(自己的 `HOME`),它的缓存与你自己 shell 里 `~/.opencli` 那份不是同一个 —— 核验要用工具,别看错文件 |
20
- | 面板上现在是什么样(每张卡读到没 / 崩没崩) | `workbench_diy_panel`(浏览器半侧上报,宿主按 unit 留最新一条;见 [ADR-0042](../../../../docs/adr/0042-panel-runtime-state-is-reported-to-the-host.md)) |
20
+ | 面板上现在是什么样(每张卡读到没 / 崩没崩) | `workbench_diy_panel`(浏览器半侧上报,宿主按 unit 留最新一条) |
21
21
  | 空着的格就是还没定的事([DESIGN.md](DESIGN.md) §5) | `design.json` + `design check`(点名叫出空格)/ `render` / `accept` |
22
22
  | 发货前的清单([WIRING.md](WIRING.md) §5) | `dsh-wb-module publish`(门禁 + 打包清单 `files` 漏项,只 dry run) |
23
23
  | 干净机器上的第一脚([SKILL.md](SKILL.md) 第 4 步) | 启动器自愈骨架 + PATH 上的 `dsh-wb-module` |
@@ -30,7 +30,7 @@
30
30
  | DOM 读怎么读([DATASOURCE.md](DATASOURCE.md) 第 2 步) | `probe`(探)+ `browserFind`(固化)—— 切格 / 按列取值是两个纯函数 |
31
31
  | 链接只有一副样子([PANEL.md](PANEL.md) §6) | kit 的 `Link` 是唯一一份(**没有 `icon` 口子**),`check --only style` 拦裸 `<a>` |
32
32
  | 输入框不用自己配样式([PANEL.md](PANEL.md) §5.1) | `TextField` 的默认内边距 + kit 的 `Field`(标签 + 提示的排布) |
33
- | 这个单元在哪些工作区出现([TOOLS.md](TOOLS.md) §12) | **不是模块能声明的事** —— 用户用 `workbench_panels_*` 的板决定(卡片与全部工具同判);协议里的 `scope` 已删。`gate.deniedTools` 是可选的运行期收窄,门禁不再对它做声明对账 |
33
+ | 这个单元在哪些工作区出现([TOOLS.md](TOOLS.md) §12) | **不是模块能声明的事** —— 用户用 `workbench_panels_*` 的板决定(卡片与全部工具同判)。`gate.deniedTools` 是可选的运行期收窄 |
34
34
 
35
35
  ## 留给 agent 的(判断,不该固化)
36
36
 
@@ -43,8 +43,3 @@
43
43
  (工具只能保证"形状对","该多窄"是判断)
44
44
 
45
45
  工具只负责把**事实**摆出来(状态、报错原文、预览结果),判断仍然是人 / agent 的事。
46
-
47
- ---
48
-
49
- 为什么这样挑、哪一轮落地的(连同实测与反例):工作台仓库的
50
- `.agents/skills/module-design/EXAMPLES.md` §4 —— 工坊会话里够不到那儿。
@@ -223,8 +223,8 @@ const feed = kit.hooks.useLongTask({ unit: 'demo', workspace });
223
223
 
224
224
  ## 11 范例
225
225
 
226
- 范例都在**工作台仓库里**:`.agents/skills/module-design/EXAMPLES.md` §2 —— 工坊会话里够不到那儿,
227
- 就照 [SKILL.md](SKILL.md) 的「找不到一件事的时候」读模板与装机模块的源码。
226
+ 要一个"同形状、能跑"的样子:[SKILL.md](SKILL.md) 的「找不到一件事的时候」—— 模板
227
+ (`template-diy/` / `template/`)与装机模块的源码都可以直接读。
228
228
 
229
229
  ## 12 同一把工具,在有些项目里不该出现
230
230
 
@@ -249,16 +249,11 @@ return {
249
249
  用户关掉开关要等下次重启才生效。
250
250
  - 外壳两道都做:清单里不出现(agent 看不到)+ 真调到时当场拒(防手滑)。你只要把 `deniedTools` 写对。
251
251
 
252
- 外壳自己就是这么用的(工坊里看 `node_modules/@dsh-workbench/core/…`,仓库里是
253
- `packages/workbench/src/modules/panels/index.ts`):某张卡在这个项目上没开 → 那张卡的工具全不出现;
252
+ 外壳自己就是这么用的:某张卡在这个项目上没开 → 那张卡的工具全不出现;
254
253
  工坊那七把(`workbench_diy_*`)**只在工坊会话里**出现,别处一律不出现。
255
254
 
256
255
  **"这条能力在哪些工作区出现"不用你声明 —— 那是用户的事。** 用户口径:「模块开发者不能定义 scope,
257
256
  scope 永远是用户来决定的」。他在 `workbench_panels_show` / `workbench_panels_hide`(agent 工具)里把它们放上/收起;一个单元在不在,
258
257
  它的卡片与**全部**工具同判(外壳的 `resolveScope` 只看两份板:本工作区那份,否则机器级那份)。
259
- 协议里那个 `scope`(`dsh.workbench.tools[].scope` / `card.scope`)**已经删掉**,写它就是写了一个
260
- 不认识的键、`check --only protocol` 当场红(见 [ADR-0038 §2.4 / §6.16](../../../../docs/adr/0038-module-declaration-protocol.md))。
261
- `design.json` 的能力行也没有这一格。
262
258
 
263
- `gate.deniedTools` 仍然可以接,但它是**可选**的运行期收窄("这个能力还没配好,先按我自己的开关藏起来"),
264
- **不是**一条声明出来的承诺:门禁不再拿任何声明去对账它(那条判据已删 —— 没有作者侧声明就没有可比的东西)。
259
+ `gate.deniedTools` 可以接,它是**可选**的运行期收窄("这个能力还没配好,先按我自己的开关藏起来")。
@@ -37,7 +37,7 @@ import 运行值会被**打进你的包**(第二份实例),而且浏览器
37
37
  | 在公开包里写内网地址 / 内网域名 / 企业内部名 | 门禁会扫出来并指到行 |
38
38
 
39
39
  另外两条不是"被拦",是纪律:**样式走 `*.module.css`,类名别带 `wb-` 前缀**(`wb-*` 是外壳的**全局**
40
- 类名:模块定义它、或借契约里没有的那一个,`check:style` 都判红;模块自己的类名由构建**按文件路径
40
+ 类名:模块定义它、或借契约里没有的那一个,`check --only style` 都判红;模块自己的类名由构建**按文件路径
41
41
  哈希**,天然不会跟谁撞。要借外壳契约里的类,写 `:global(.wb-…)`,且那个类必须在契约里);
42
42
  **`src/**` 里零注释** —— 要说的写进 `README.md` 或 spec。
43
43
 
@@ -72,8 +72,8 @@ import 运行值会被**打进你的包**(第二份实例),而且浏览器
72
72
  装完之后**不要再装一遍**。改源码 → `dsh-wb-module build` → 用户面板上那张卡自己变。
73
73
 
74
74
  - **宿主侧**(`src/host.ts` / `balance.ts` … → `dist/host.js`):**秒级热换**,不重启、不刷新
75
- (实测 2026-10-11:加一行探针 → build → 3 秒内接口返回新内容)。这条曾经是坏的,
76
- 坏因是 `dsh-hmr` 跟着软链把文件描述符用光(`cordis.patch.yml` 的 `followSymlinks: false` 为它而加)。
75
+ (加一行探针 → build → 3 秒内接口就返回新内容)。`cordis.patch.yml` 里的 `followSymlinks: false`
76
+ 不能去掉:`dsh-hmr` 跟着软链会把文件描述符用光。
77
77
  - **客户端侧**(`src/client.tsx` / CSS → `client.js`):浏览器**不会自己**换,**刷新一下页面**即可
78
78
  (实测:重建后 60 秒页面没有任何反应)。`*.module.css` 的改动是就地改写那一份 `<style>`,刷新即生效。
79
79
  - **改 `cordis.patch.yml`、改 `package.json` 里的 `dsh.client` / `exports["./client"]` 需要重启。**
@@ -1 +0,0 @@
1
- export {};
@@ -1,18 +0,0 @@
1
- import type { PreflightBridgeIssue, PreflightGuidance, PreflightSnapshot } from '../../../shared/api/host/preflight';
2
- export interface GateMockExpect {
3
- readonly hint: 'checking' | 'installing' | 'failed';
4
- readonly guidance?: PreflightGuidance;
5
- readonly command: boolean;
6
- readonly bridgeIssues?: readonly PreflightBridgeIssue[];
7
- }
8
- export interface GateMock {
9
- readonly id: string;
10
- readonly label: string;
11
- readonly note: string;
12
- readonly snapshot: PreflightSnapshot;
13
- readonly expect: GateMockExpect;
14
- }
15
- export declare const GATE_MOCKS: readonly GateMock[];
16
- export declare function mountGateMockStrip(options: {
17
- onPick: (snapshot: PreflightSnapshot | null) => void;
18
- }): HTMLElement;
@@ -1,14 +0,0 @@
1
- import type { AddModuleOutcome, AddModulePhase, AddModulePreview, AddModuleProblem, AddModuleState } from './use-add-module';
2
- export interface AddModuleMock {
3
- readonly id: string;
4
- readonly label: string;
5
- readonly phase: AddModulePhase;
6
- readonly spec: string;
7
- readonly guideOpen?: boolean;
8
- readonly problem?: AddModuleProblem;
9
- readonly preview?: AddModulePreview;
10
- readonly outcome?: AddModuleOutcome;
11
- readonly failure?: string;
12
- }
13
- export declare const ADD_MODULE_MOCKS: readonly AddModuleMock[];
14
- export declare function stateOfMock(base: AddModuleState, mock: AddModuleMock): AddModuleState;
@@ -1,5 +0,0 @@
1
- import type { BoardFixtures } from './board-mock';
2
- export declare function BoardMockStrip({ fixtures, show }: {
3
- fixtures: BoardFixtures;
4
- show: boolean;
5
- }): JSX.Element | null;
@@ -1,22 +0,0 @@
1
- import type { UnitManifest } from '@dsh-workbench/shared';
2
- import type { BoardShape } from './board-shape';
3
- export interface BoardMockExpect {
4
- readonly cards: number;
5
- readonly empty: boolean;
6
- }
7
- export interface BoardMock {
8
- readonly id: string;
9
- readonly label: string;
10
- readonly note: string;
11
- readonly shape: BoardShape;
12
- readonly expect?: BoardMockExpect;
13
- }
14
- export declare function buildBoardMocks(roster: readonly UnitManifest[]): readonly BoardMock[];
15
- export interface BoardFixtures {
16
- readonly mock: BoardMock | undefined;
17
- readonly mocks: readonly BoardMock[];
18
- readonly index: number;
19
- readonly pick: (next: number) => void;
20
- readonly shape: BoardShape;
21
- }
22
- export declare function useBoardMock(roster: readonly UnitManifest[]): BoardFixtures;
@@ -1,11 +0,0 @@
1
- export declare function TextFieldDemo(): JSX.Element;
2
- export declare function SelectDemo({ variant }: {
3
- readonly variant?: 'boxed' | 'ghost';
4
- }): JSX.Element;
5
- export declare function SelectRichDemo(): JSX.Element;
6
- export declare function SelectStateDemo(): JSX.Element;
7
- export declare function AppearanceDemo(): JSX.Element;
8
- export declare function ChoiceDemo(): JSX.Element;
9
- export declare function FormActionsDemo(): JSX.Element;
10
- export declare function SaveBarDemo(): JSX.Element;
11
- export declare function LinkDemo(): JSX.Element;
@@ -1,18 +0,0 @@
1
- import type { ReactNode } from '@dsh-workbench/shared';
2
- export declare function KitNavProvider({ children }: {
3
- readonly children?: ReactNode;
4
- }): JSX.Element;
5
- export declare function KitNav(): JSX.Element | null;
6
- export declare function Section({ title, note, children, }: {
7
- readonly title: string;
8
- readonly note?: string;
9
- readonly children?: ReactNode;
10
- }): JSX.Element;
11
- export declare function Grid({ children }: {
12
- readonly children?: ReactNode;
13
- }): JSX.Element;
14
- export declare function Cell({ label, wide, children, }: {
15
- readonly label: string;
16
- readonly wide?: boolean;
17
- readonly children?: ReactNode;
18
- }): JSX.Element;
@@ -1 +0,0 @@
1
- export declare function hashTargetsSection(anchor: string, hash: string): boolean;
@@ -1,6 +0,0 @@
1
- export declare function RowsSection(): JSX.Element;
2
- export declare function FormSection(): JSX.Element;
3
- export declare function ActivitySection(): JSX.Element;
4
- export declare function LongTaskSection(): JSX.Element;
5
- export declare function IconSection(): JSX.Element;
6
- export declare function StripSection(): JSX.Element;
@@ -1,3 +0,0 @@
1
- import type { BoardModule, BoardModuleProps } from '@dsh-workbench/shared';
2
- export declare function KitPreview({ t }: BoardModuleProps): JSX.Element;
3
- export declare const KIT_PREVIEW_MODULE: BoardModule;
@@ -1,9 +0,0 @@
1
- import type { UnitManifest } from '@dsh-workbench/shared';
2
- import type { CapabilityMap } from '../../../shared/hooks/use-capabilities';
3
- import type { MarketMock } from './market-mock-types';
4
- export declare function installedMocks(input: {
5
- readonly id: string;
6
- readonly found: UnitManifest;
7
- readonly mine: UnitManifest;
8
- readonly probe: (unit: string, status: CapabilityMap[string]['status'], extra?: Partial<CapabilityMap[string]>) => CapabilityMap;
9
- }): readonly MarketMock[];