@dsh-workbench/core 0.3.10 → 1.0.0-beta.0

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 (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -105
  3. package/bin/dsh-workbench +132 -31
  4. package/bin/dsh-workbench.cmd +5 -0
  5. package/bin/opencli-isolated +3 -2
  6. package/bin/opencli-isolated.mjs +44 -0
  7. package/bin/opencli-node-mode.cjs +1 -0
  8. package/bin/seed-workshop-windows.mjs +307 -0
  9. package/client.js +8192 -4904
  10. package/cordis.patch.yml +62 -37
  11. package/dist/client/client.body.js +8192 -4904
  12. package/dist/client/index.js +7186 -3898
  13. package/dist/host/index.js +7277 -6956
  14. package/dist/types/app/client.d.ts +3 -1
  15. package/dist/types/app/host.d.ts +2 -1
  16. package/dist/types/app/layouts/approval-detail.d.ts +3 -0
  17. package/dist/types/app/layouts/env-gate/boot-gate.d.ts +1 -12
  18. package/dist/types/app/layouts/env-gate/gate-text.d.ts +2 -1
  19. package/dist/types/app/layouts/market/DiscoverPanel.d.ts +8 -0
  20. package/dist/types/app/layouts/market/add-module-text.d.ts +1 -1
  21. package/dist/types/app/layouts/market/discover-categories.d.ts +8 -0
  22. package/dist/types/app/layouts/market/discover-confirm.d.ts +14 -0
  23. package/dist/types/app/layouts/market/discover-detail.d.ts +12 -0
  24. package/dist/types/app/layouts/market/discover-dialogs.d.ts +7 -0
  25. package/dist/types/app/layouts/market/discover-doc.d.ts +18 -0
  26. package/dist/types/app/layouts/market/discover-init-dialog.d.ts +10 -0
  27. package/dist/types/app/layouts/market/discover-rows.d.ts +24 -0
  28. package/dist/types/app/layouts/market/discover-sources-dialog.d.ts +16 -0
  29. package/dist/types/app/layouts/market/discover-states.d.ts +22 -0
  30. package/dist/types/app/layouts/market/discover-toolbar.d.ts +23 -0
  31. package/dist/types/app/layouts/market/discover-versions.d.ts +9 -0
  32. package/dist/types/app/layouts/market/discover-view.d.ts +38 -0
  33. package/dist/types/app/layouts/market/market-header.d.ts +13 -0
  34. package/dist/types/app/layouts/market/panel.d.ts +1 -1
  35. package/dist/types/app/layouts/market/use-add-module.d.ts +1 -1
  36. package/dist/types/app/layouts/market/use-discover.d.ts +72 -0
  37. package/dist/types/app/layouts/market/use-module-versions.d.ts +6 -2
  38. package/dist/types/app/layouts/rightbar/MarketView.d.ts +6 -3
  39. package/dist/types/app/layouts/rightbar/Rightbar.d.ts +1 -1
  40. package/dist/types/app/layouts/rightbar/board-shape.d.ts +1 -14
  41. package/dist/types/app/layouts/rightbar/market-act.d.ts +6 -3
  42. package/dist/types/app/layouts/rightbar/market-busy.d.ts +0 -22
  43. package/dist/types/app/layouts/rightbar/market-change.d.ts +1 -1
  44. package/dist/types/app/layouts/rightbar/market-hint.d.ts +1 -7
  45. package/dist/types/app/layouts/rightbar/market-plugin-rows.d.ts +0 -7
  46. package/dist/types/app/layouts/rightbar/market-row-icon.d.ts +1 -1
  47. package/dist/types/app/layouts/rightbar/market-row-types.d.ts +2 -2
  48. package/dist/types/app/layouts/rightbar/market-rows.d.ts +1 -1
  49. package/dist/types/app/layouts/rightbar/market-section-icon.d.ts +1 -1
  50. package/dist/types/app/layouts/rightbar/market-settle-hold.d.ts +2 -0
  51. package/dist/types/app/layouts/rightbar/market-settle.d.ts +17 -0
  52. package/dist/types/app/layouts/rightbar/market-shared-rows.d.ts +1 -1
  53. package/dist/types/app/layouts/rightbar/market-update-verdict.d.ts +31 -0
  54. package/dist/types/app/layouts/rightbar/market-view-text.d.ts +8 -1
  55. package/dist/types/app/layouts/rightbar/market-workbench-row.d.ts +1 -1
  56. package/dist/types/app/layouts/rightbar/store.d.ts +2 -0
  57. package/dist/types/app/layouts/sidebar/LongTaskDot.d.ts +6 -0
  58. package/dist/types/app/layouts/sidebar/LongTaskHover.d.ts +6 -0
  59. package/dist/types/app/layouts/sidebar/edition-boot.d.ts +6 -0
  60. package/dist/types/app/layouts/sidebar/edition.d.ts +5 -0
  61. package/dist/types/app/layouts/sidebar/use-attention.d.ts +0 -4
  62. package/dist/types/app/layouts/sidebar/workshop-preset.d.ts +2 -0
  63. package/dist/types/app/layouts/workbench-settings/AdapterSetItem.d.ts +5 -0
  64. package/dist/types/app/layouts/workbench-settings/ConfigSyncItem.d.ts +5 -0
  65. package/dist/types/app/layouts/workbench-settings/ConfigSyncRows.d.ts +11 -0
  66. package/dist/types/app/layouts/workbench-settings/NewWorkbenchItem.d.ts +5 -0
  67. package/dist/types/app/layouts/workbench-settings/SettingsItem.d.ts +8 -0
  68. package/dist/types/app/layouts/workbench-settings/SidebarEditionItem.d.ts +5 -0
  69. package/dist/types/app/layouts/workbench-settings/WorkbenchSettingsSection.d.ts +5 -0
  70. package/dist/types/app/units/manifests.d.ts +1 -1
  71. package/dist/types/{app/units → kernel/client}/registry.d.ts +1 -1
  72. package/dist/types/kernel/contract/bundle-install.d.ts +2 -0
  73. package/dist/types/kernel/contract/config-sync.d.ts +2 -0
  74. package/dist/types/kernel/contract/diy.d.ts +1 -0
  75. package/dist/types/kernel/contract/dsh-plugins.d.ts +2 -0
  76. package/dist/types/kernel/contract/index.d.ts +4 -0
  77. package/dist/types/kernel/contract/long-tasks.d.ts +2 -0
  78. package/dist/types/kernel/contract/market-index.d.ts +2 -0
  79. package/dist/types/kernel/contract/platform.d.ts +1 -0
  80. package/dist/types/kernel/contract/preflight-wake.d.ts +2 -0
  81. package/dist/types/kernel/contract/profile-create.d.ts +2 -0
  82. package/dist/types/kernel/contract/sidebar-edition.d.ts +2 -0
  83. package/dist/types/kernel/contract/unit-manifests.d.ts +2 -0
  84. package/dist/types/{shared/api → kernel}/host/mount-units.d.ts +2 -1
  85. package/dist/types/modules/panels/client.d.ts +1 -1
  86. package/dist/types/modules/panels/model/approval.d.ts +4 -8
  87. package/dist/types/modules/panels/model/diy-browser-tools.d.ts +1 -1
  88. package/dist/types/modules/panels/model/diy-changelog.d.ts +2 -0
  89. package/dist/types/modules/panels/model/diy-context.d.ts +20 -18
  90. package/dist/types/modules/panels/model/diy-page.d.ts +4 -2
  91. package/dist/types/modules/panels/model/diy-record-open.d.ts +0 -15
  92. package/dist/types/modules/panels/model/diy-record-text.d.ts +0 -2
  93. package/dist/types/modules/panels/model/diy-record.d.ts +1 -31
  94. package/dist/types/modules/panels/model/diy-report.d.ts +6 -7
  95. package/dist/types/modules/panels/model/diy-tools.d.ts +1 -0
  96. package/dist/types/modules/panels/model/long-task-tools.d.ts +0 -11
  97. package/dist/types/modules/panels/model/market-dependency-update.d.ts +15 -0
  98. package/dist/types/modules/panels/model/market-dependency.d.ts +15 -10
  99. package/dist/types/modules/panels/model/market-discover-routes.d.ts +3 -0
  100. package/dist/types/modules/panels/model/market-discover.d.ts +33 -0
  101. package/dist/types/modules/panels/model/market-dispatch.d.ts +4 -3
  102. package/dist/types/modules/panels/model/market-env.d.ts +2 -3
  103. package/dist/types/modules/panels/model/market-registry.d.ts +3 -3
  104. package/dist/types/modules/panels/model/market-restart.d.ts +1 -1
  105. package/dist/types/modules/panels/model/market-route.d.ts +5 -3
  106. package/dist/types/modules/panels/model/market-sources-act.d.ts +9 -0
  107. package/dist/types/modules/panels/model/market-types.d.ts +7 -13
  108. package/dist/types/modules/panels/model/market-update-bundle.d.ts +19 -0
  109. package/dist/types/modules/panels/model/market-verify.d.ts +15 -0
  110. package/dist/types/modules/panels/model/market-workbench-update.d.ts +3 -2
  111. package/dist/types/modules/panels/model/market.d.ts +6 -5
  112. package/dist/types/modules/panels/model/plugin-actions.d.ts +2 -1
  113. package/dist/types/modules/panels/model/plugin-section.d.ts +3 -1
  114. package/dist/types/modules/panels/model/publish-preview-routes.d.ts +2 -0
  115. package/dist/types/modules/panels/unit.d.ts +8 -5
  116. package/dist/types/modules/sessions/model/attention.d.ts +0 -11
  117. package/dist/types/modules/sessions/model/session-node.d.ts +0 -10
  118. package/dist/types/shared/api/diy.d.ts +6 -4
  119. package/dist/types/shared/api/host/approval-call.d.ts +0 -9
  120. package/dist/types/shared/api/host/approval-gate.d.ts +26 -0
  121. package/dist/types/shared/api/host/bundle-routes.d.ts +2 -1
  122. package/dist/types/shared/api/host/diy-artifacts.d.ts +3 -0
  123. package/dist/types/shared/api/host/diy-changelog.d.ts +13 -0
  124. package/dist/types/shared/api/host/diy-components.d.ts +2 -3
  125. package/dist/types/shared/api/host/diy-modules.d.ts +25 -0
  126. package/dist/types/shared/api/host/diy-publish-preview.d.ts +4 -0
  127. package/dist/types/shared/api/host/diy-recon-fs.d.ts +2 -2
  128. package/dist/types/shared/api/host/diy-tokens.d.ts +8 -0
  129. package/dist/types/shared/api/host/host-routes.d.ts +10 -0
  130. package/dist/types/shared/api/host/long-task-notice.d.ts +0 -20
  131. package/dist/types/shared/api/host/long-tasks.d.ts +1 -8
  132. package/dist/types/shared/api/host/market-doc.d.ts +21 -0
  133. package/dist/types/shared/api/host/market-index-fetch.d.ts +37 -0
  134. package/dist/types/shared/api/host/market-source-init.d.ts +22 -0
  135. package/dist/types/shared/api/host/market-sources-store.d.ts +15 -0
  136. package/dist/types/shared/api/host/permission-mode.d.ts +4 -0
  137. package/dist/types/shared/api/host/post-channels.d.ts +1 -1
  138. package/dist/types/shared/api/host/sidebar-edition.d.ts +14 -0
  139. package/dist/types/shared/api/host/unit-roster-facts.d.ts +1 -1
  140. package/dist/types/shared/api/host/workspace-root.d.ts +6 -0
  141. package/dist/types/shared/api/platform/client.d.ts +10 -0
  142. package/dist/types/shared/api/unit-board.d.ts +4 -0
  143. package/dist/types/shared/api/write-outcome.d.ts +3 -0
  144. package/dist/types/shared/components/IconModules.d.ts +2 -0
  145. package/dist/types/shared/components/PanelFoot.d.ts +0 -9
  146. package/dist/types/shared/components/blocker-action.d.ts +3 -0
  147. package/dist/types/shared/dev-surface/index.d.ts +5 -0
  148. package/dist/types/shared/dev-surface/types.d.ts +79 -0
  149. package/dist/types/shared/hooks/bundle-queries.d.ts +1 -13
  150. package/dist/types/shared/hooks/fact-transport.d.ts +4 -0
  151. package/dist/types/shared/hooks/fact-transports.d.ts +0 -4
  152. package/dist/types/shared/hooks/market-queries.d.ts +11 -0
  153. package/dist/types/shared/hooks/panel-state-report.d.ts +0 -12
  154. package/dist/types/shared/hooks/sidebar-edition.d.ts +2 -0
  155. package/dist/types/shared/hooks/use-blocker-actions.d.ts +0 -8
  156. package/dist/types/shared/hooks/use-capabilities.d.ts +1 -55
  157. package/dist/types/shared/hooks/use-capability-gate.d.ts +1 -2
  158. package/dist/types/shared/hooks/use-diy-debug.d.ts +0 -13
  159. package/dist/types/shared/hooks/use-diy-record.d.ts +0 -13
  160. package/dist/types/shared/hooks/use-host-write.d.ts +1 -1
  161. package/dist/types/shared/hooks/use-shell-long-tasks.d.ts +1 -7
  162. package/dist/types/shared/hooks/use-unit-board.d.ts +1 -1
  163. package/icon.svg +17 -28
  164. package/package.json +33 -13
  165. package/preset/diy.patch.yml +3 -3
  166. package/profile/isolation.patch.yml +18 -7
  167. package/profile/sandbox.patch.yml +2 -2
  168. package/scripts/clone-profile.mjs +268 -0
  169. package/scripts/create-workbench.mjs +166 -0
  170. package/scripts/seed-profile.sh +22 -10
  171. package/scripts/seed-workshop.sh +17 -19
  172. package/skills/workbench-module-diy/BUILD.md +57 -133
  173. package/skills/workbench-module-diy/COPY.md +89 -0
  174. package/skills/workbench-module-diy/DATASOURCE.md +173 -116
  175. package/skills/workbench-module-diy/DESIGN.md +76 -109
  176. package/skills/workbench-module-diy/FAMILY.md +48 -52
  177. package/skills/workbench-module-diy/KIT.md +78 -133
  178. package/skills/workbench-module-diy/LINKAGE.md +66 -105
  179. package/skills/workbench-module-diy/PANEL.md +81 -171
  180. package/skills/workbench-module-diy/REVIEW.md +67 -81
  181. package/skills/workbench-module-diy/SKILL.md +66 -96
  182. package/skills/workbench-module-diy/STEPS.md +66 -69
  183. package/skills/workbench-module-diy/TOOLS.md +134 -103
  184. package/skills/workbench-module-diy/WIRING.md +64 -84
  185. package/skills/workbench-module-diy/WRITES.md +115 -142
  186. package/dist/types/app/layouts/config-sync/ConfigSyncSection.d.ts +0 -5
  187. package/dist/types/shared/api/bundle-install.d.ts +0 -123
  188. package/dist/types/shared/api/config-sync.d.ts +0 -35
  189. package/dist/types/shared/api/dsh-plugins.d.ts +0 -11
  190. package/dist/types/shared/api/host/bundle-manager.d.ts +0 -11
  191. package/dist/types/shared/api/host/config-sync.d.ts +0 -46
  192. package/dist/types/shared/api/host/diy-preset-health.d.ts +0 -35
  193. package/dist/types/shared/api/host/diy-workshop.d.ts +0 -23
  194. package/dist/types/shared/api/host/dsh-plugins.d.ts +0 -5
  195. package/dist/types/shared/api/host/installed-module.d.ts +0 -54
  196. package/dist/types/shared/api/host/installed-module.test.d.ts +0 -1
  197. package/dist/types/shared/api/host/opencli-command.d.ts +0 -10
  198. package/dist/types/shared/api/host/opencli-command.test.d.ts +0 -1
  199. package/dist/types/shared/api/host/opencli.test.d.ts +0 -1
  200. package/dist/types/shared/api/host/package-content.d.ts +0 -6
  201. package/dist/types/shared/api/host/package-content.test.d.ts +0 -1
  202. package/dist/types/shared/api/host/package-kind.d.ts +0 -21
  203. package/dist/types/shared/api/host/package-kind.test.d.ts +0 -1
  204. package/dist/types/shared/api/host/package-route.d.ts +0 -23
  205. package/dist/types/shared/api/host/package-route.test.d.ts +0 -1
  206. package/dist/types/shared/api/host/plugin-catalog.d.ts +0 -65
  207. package/dist/types/shared/api/host/plugin-login-hint.d.ts +0 -2
  208. package/dist/types/shared/api/host/plugin-tools.d.ts +0 -14
  209. package/dist/types/shared/api/host/plugin-units.d.ts +0 -48
  210. package/dist/types/shared/api/host/preflight-route.d.ts +0 -15
  211. package/dist/types/shared/api/host/preflight.d.ts +0 -75
  212. package/dist/types/shared/api/host/probe-cache.d.ts +0 -6
  213. package/dist/types/shared/api/host/probe-libs.d.ts +0 -11
  214. package/dist/types/shared/api/host/probe-units.d.ts +0 -17
  215. package/dist/types/shared/api/host/probe-verdict.d.ts +0 -7
  216. package/dist/types/shared/api/host/profile-registries.d.ts +0 -21
  217. package/dist/types/shared/api/host/registry-declaration.d.ts +0 -23
  218. package/dist/types/shared/api/host/release.d.ts +0 -24
  219. package/dist/types/shared/api/host/runtime-seed.d.ts +0 -38
  220. package/dist/types/shared/api/host/self-update.d.ts +0 -45
  221. package/dist/types/shared/api/host/version-range.d.ts +0 -2
  222. package/dist/types/shared/api/host/workshop-root.d.ts +0 -16
  223. package/dist/types/shared/api/long-tasks.d.ts +0 -19
  224. package/dist/types/shared/api/unit-manifests.d.ts +0 -6
  225. package/docs/HANDOFF.md +0 -333
  226. package/docs/OPERATIONS.md +0 -229
  227. package/skills/workbench-module-diy/TOOLING.md +0 -55
  228. /package/dist/types/{app/layouts/rightbar/registry.d.ts → kernel/client/board-registry.d.ts} +0 -0
  229. /package/dist/types/{app/layouts/rightbar/registry.test.d.ts → kernel/contract/contracts.test.d.ts} +0 -0
  230. /package/dist/types/{shared/api/host/bundle-manager.test.d.ts → kernel/contract/index.test.d.ts} +0 -0
  231. /package/dist/types/{shared/api → kernel}/host/unit-readiness.d.ts +0 -0
  232. /package/dist/types/{shared/api → kernel}/host/unit-registry.d.ts +0 -0
  233. /package/dist/types/shared/{api/host/diy-workshop.test.d.ts → components/blocker-action.test.d.ts} +0 -0
  234. /package/dist/types/shared/{api/host/dsh-plugins.test.d.ts → dev-surface/install.d.ts} +0 -0
@@ -1,142 +1,103 @@
1
- # 联动:agent 做完,用户看到什么
1
+ # 联动:谁在动、何时变、哪一格变
2
2
 
3
- 步骤 3 的参考。写的是用户什么时候看到哪一格变,不写这条链怎么接。
3
+ 步骤 3 的参考。实现见 §8。
4
4
 
5
- ## 1 什么时候面板该动
5
+ ## 1 触发规则
6
6
 
7
- | 谁在动 | 用户看到什么 |
7
+ | 触发 | 面板 |
8
8
  |---|---|
9
- | agent **读**了面板这一格的数据 | **那一格**变(按最窄的那个切片重读),值跟对话里那份一样 |
10
- | agent 读的是面板上没有的东西(明细、日志、某一档子集) | **不动**(面板没有那一格) |
11
- | agent 只预览、还没真的做 | **不动**(预览不改任何东西) |
12
- | agent 真的做了 | 相关的那一格**变成新值** |
13
- | 他自己按的动作 | 那一格**立刻变**,并在原地看到"正在做 / 做完了" |
14
- | 他自己改了偏好 | 保存后立刻按新的显示 |
15
- | 别的窗口 / 另一个会话也在改 | 他这里也会变(不需要他刷新) |
9
+ | agent 读面板这一格 | 该格按最窄切片重读;值与对话一致 |
10
+ | agent 读面板外的东西(明细 / 日志 / 子集) | 不变 |
11
+ | agent 只预览 | 不变 |
12
+ | agent 真写 | 相关格变新值 |
13
+ | 用户自按动作 | 该格立即变,原地显示进行中 / 完成 |
14
+ | 用户改偏好 | 保存后按新偏好显示 |
15
+ | 其他窗口 / 会话改动 | 跟随变,无需刷新 |
16
16
 
17
- ⚠️ **"读 → 也变"这条是用户定的口径**:理由是「agent 调用工具的时候面板数据也受益」—— agent 刚在对话里
18
- 念了数字,面板得是同一份,否则他到底信哪个。
17
+ 一次说清变哪一级:整板 / 一张卡 / 一行。"刷新一下"不合格。只动该动的格,粒度落到"某投影 + 最窄参数"
18
+ (`inventory/builds?env=dev`);否则会整卡重读。
19
19
 
20
- **一次说清动的是哪一格**:整块板、某一张卡、还是某一行。写"刷新一下"不算说清 —— 那会让实现的人整卡重读。
20
+ ## 2 进行中
21
21
 
22
- **只动该动的那一格**:agent 在一个环境做了一次,不该让别的环境、别的列、整张卡一起重新读一遍(读一次很慢,他会看到整块退回"在读")。**颗粒度就是这句话在实现里的样子**:动的那一格要能落到"某条投影 + 最窄的那个参数"(`cmdb/builds?env=dev` 这种),写进联动表里。
22
+ - 显示可读的步骤名,不用内部步骤号。
23
+ - 要登录:给登录入口;登录后续跑,不重来。
24
+ - 失败:卡在哪步、一句原因、原始输出(折叠)、一条可照做的路。
25
+ - 不画进度条、不画流程控制台。
23
26
 
24
- ## 2 agent 正在干的时候
27
+ 中途停止可续:用户说"接着做"即从上次继续。
25
28
 
26
- - 显示到**哪一步**("正在合并分支"这种他能读懂的一步,不是内部步骤名);
27
- - 要**登录**就给他一条去登录的路,登录完这次继续,不用他重来;
28
- - **失败**给他:卡在哪一步、一句能读的原因、原始输出(折叠起来),以及一条能照做的路;
29
- - **不画进度条、不画流程控制台**:状态 + 链接 + 原始输出就够。
29
+ ## 3 "交给 agent"的内容
30
30
 
31
- 一次做一半就停也不是问题:他回来说一句"接着做",能接着上一次继续,不用从头再来。
31
+ - 哪一类 + 哪个对象 + 多少(按用户点的那一行,不是全量)。
32
+ - 一句"用哪个能力取明细"(agent 打不开面板的 ↗)。
33
+ - 不塞明细本身。
34
+ - 保持用户点的分类;认不出就报错,不退回全量。
32
35
 
33
- ## 3 他点"交给 agent"之后,agent 拿到什么
36
+ ## 4 收起模块
34
37
 
35
- - **哪一类 + 哪个对象 + 多少**(他点的是哪一行,agent 就该拿到哪一类,不能四行点了都给它同一份全部);
36
- - 加一句**该用哪个能力往下拿明细**(agent 打不开面板上那个 ↗,明细只能它自己再问一次);
37
- - **明细本身不要塞进去**(一页几十行按会话付费,而 agent 拿到那句指引自己会去要);
38
- - 他点的那一类要跟着走(点"圈复杂度"就只给圈复杂度,不能悄悄退回整份);
39
- - 认不出的那一类要**当场说错**,不许默默退回整份(他要的是这一块,给全部比报错更糟)。
38
+ 收起 = 该项目内 agent 也失去该能力。收起时说明;收起后能力清单更新,对话显示"能力有更新";其他项目不受影响。
40
39
 
41
- ## 4 收起模块意味着什么
40
+ ## 5 不陈旧
42
41
 
43
- 把一块面板收起来 = **这个项目里 agent 也做不了这件事**。
42
+ 覆盖三种:切项目 → 立刻显示新项目;其他窗口 / 会话改动 → 跟随;程序刚更新 → 不因"我比你还新"而不收更新。
43
+ 允许秒级延迟,但要说明;不得停在旧值等手动刷新。
44
44
 
45
- - 这一条要在**点头收起的时候**就说清("这个项目里它的能力也一起下线");
46
- - 收起之后 agent 手上的能力清单会变,用户会在对话里看到一句"能力有更新";
47
- - 别的项目不受影响。
45
+ ## 6 联动表(步骤 3 产出)
48
46
 
49
- ## 5 面板凭什么不旧
50
-
51
- 三种情况都要有答案:
52
-
53
- 1. **他切了项目** —— 看到的立刻是新项目的数据;
54
- 2. **别的窗口 / 另一个会话也改了** —— 他这里会跟着变;
55
- 3. **程序刚更新过(开发时最常见)** —— 不会因为"我比你还新"这种判断而永远收不到更新。
56
-
57
- 允许有延迟(几秒),但延迟要说清;**不允许停在旧值上、只有手动点刷新才动**。
58
-
59
- ## 6 联动场景表(步骤 3 的产出)
60
-
61
- | 谁在动 | 面板什么时候变 | 哪一格变 | 用户看到什么 |
47
+ | 谁在动 | 何时变 | 哪一格 | 看到什么 |
62
48
  |---|---|---|---|
63
- | agent 读了面板这一格的数据 | 读完自动 | 那一格(最窄那个切片) | 那一格出已有的加载态(约半秒)→ 与对话同值 |
64
- | agent 读了面板上没有的那份 | 不变 | — | 对话里一段结果 |
65
- | agent 预览 | 不变 | — | 对话里"将要做什么" |
66
- | agent 真的做 | 做完之后自动 | 相关那一格 | 新值 |
67
- | 他自己按动作 | 立刻 + 做完再更新 | 那一格 | 确认条 → "正在做" → 结果 |
68
- | 他改偏好 | 保存后 | 整张卡按新偏好 | 回到看板、数据已换 |
69
- | agent 改他的面板 | 自动 | 面板多了 / 少了 / 换了顺序 | 界面变了 + 对话里"能力有更新" |
70
- | 装 / 卸能力 | 自动 | 相关的那几处 | 状态变 |
71
- | 一件长事在跑 | 自动刷新进度 | 那张卡的进度那一行 | 到哪一步 / 要登录 / 失败原因 |
72
- | 别的窗口也在改 | 自动 | 同"真的做" | 同"真的做" |
73
- | 程序刚更新过 | 全部重读一次 | 整块 | 不会退回旧值 |
74
- | 他自己点刷新 | 立刻 | 那一份 | 转圈,然后新值 |
75
- | 他切项目 | 立刻 | 整块 | 新项目的数据 |
76
- | 模块在这个项目被收起 | 自动 | 少一张卡 | 对话里"能力有更新" |
77
-
78
- ## 7 读工具也要说清"它对应面板哪一格"
79
-
80
- 用户会在对话里问到面板上就有的那格数字 —— 两处必须对得上(否则他得决定信哪个)。
81
- 所以每把**读**工具在设计时就要回答三句:
82
-
83
- - 它读的那份数据,是面板上**哪一格**?
84
- - 那一格**最窄的切片**是什么(哪个环境的哪一列 / 哪一档筛选 / 就是整张卡)?
85
- - 手里那份**是不是就是**那一格的值?
86
-
87
- 第三种答案决定面板怎么动:
88
-
89
- | 它读的是 | 面板 |
49
+ | agent 读面板这一格 | 读完 | 该格(最窄切片) | 加载态(约半秒)→ 与对话同值 |
50
+ | agent 读面板外 | 不变 | — | 对话内结果 |
51
+ | agent 预览 | 不变 | — | 对话内"将要做什么" |
52
+ | agent 真写 | 完成 | 相关格 | 新值 |
53
+ | 用户自按 | 立即 + 完成再更新 | 该格 | 确认条 → 进行中 → 结果 |
54
+ | 用户改偏好 | 保存后 | 整卡 | 回看板、数据已换 |
55
+ | agent 改面板 / 装卸能力 | 自动 | 增删或顺序,或相关几处 | 界面变化 + "能力有更新" |
56
+ | 长任务运行 | 自动推进度 | 卡的进度行 | 到哪步 / 要登录 / 失败原因 |
57
+ | 其他窗口 / 程序更新 | 自动 | 同"真写" / 整板 | 同"真写" / 不回旧值 |
58
+ | 切项目 / 点刷新 | 立即 | 整板 / 该份 | 新项目 / 转圈后新值 |
59
+ | 模块在项目内被收起 | 自动 | 少一张卡 | "能力有更新" |
60
+
61
+ ## 7 读工具对应哪一格
62
+
63
+ 每把读工具回答三句,写进能力清单:
64
+
65
+ 1. 读的数据是面板哪一格?
66
+ 2. 该格最窄切片是什么(哪个环境哪一列 / 哪档筛选 / 整卡)?
67
+ 3. 手里这份是否就是该格的值?
68
+
69
+ | 读的范围 | 面板 |
90
70
  |---|---|
91
- | 面板这一格范围内的数据 | 那一格重读;**手里那份就是那一格的值**时可以直接交出去(面板不再打一遍平台) |
92
- | 面板上没有的东西(明细 / 日志 / 单条) | **不动**(面板没有那一格) |
93
- | 面板某一格的**子集**(只读 TODO、limit 更小) | **不动**,而且**不许**把子集当那一格交出去(那是错值)—— 要对得上就让 agent 读全量那一档 |
94
-
95
- 三句都写进能力清单(用户看的是"哪一格会跟着动")。
96
-
97
- → 实现:本文 §1 与 §7。
71
+ | 该格范围内 | 该格重读;手里就是该格值时可直接交出(不再重打平台) |
72
+ | 面板外(明细 / 日志 / 单条) | 不变 |
73
+ | 该格的子集(只读 TODO、更小 limit) | 不变;不得当该格交出(错值)—— 要一致就读全量档 |
98
74
 
99
- ## 8 宿主侧的四个口子(实现形状)
75
+ ## 8 宿主侧实现
100
76
 
101
- 上面说的"哪一格变",落到代码就四个可选字段;**不写 `factsOf` 的模块,面板那一格不会自己新**。
77
+ 四个可选字段。不写 `factsOf` 的模块,面板格不会自己新。
102
78
 
103
79
  ```ts
104
80
  factsOf: (call) => (call.source === REBUILD_TOOL ? [factOfRoute(HEALTH_ROUTE)] : undefined),
105
81
  ```
106
82
 
107
- * `call.source` 是**能力名**、`call.args` 是它这次收到的参数;返回"这次动到了哪几条事实",
108
- 返回 `[]` = 涉及但没有具体事实,`undefined` = 跟面板无关(例:明细、日志那种面板上没有的东西)。
109
- * 事实名不要自己拼字符串:用 `factOfRoute('<unit>/<路由>')`(`@dsh-workbench/shared`)——
110
- **卡片读的那条路由对应哪条事实,就是它算出来的那条**。
111
- * **读能力也要认领**(§1 与 §7 的口径):agent 只是读了一次,那一格也该重读。
112
- * 长任务动完也要认领:`longTasks.create({ …, facts: () => [factOfRoute(HEALTH_ROUTE)] })`。
83
+ - `call.source` = 能力名,`call.args` = 本次参数。返回本次涉及的事实:`[]` = 涉及但无具体事实;
84
+ `undefined` = 与面板无关。
85
+ - 事实名用 `factOfRoute('<unit>/<路由>')`(`kit.api.factOfRoute`),不要手拼。读能力也认领;长任务写
86
+ `longTasks.create({ …, facts: () => [factOfRoute(HEALTH_ROUTE)] })`。
113
87
 
114
88
  ```tsx
115
89
  const rev = useFactRevision(factOfRoute(HEALTH_ROUTE));
116
90
  const resource = useApiResource(ROUTE, query, rev, {});
117
91
  ```
118
92
 
119
- 卡片的 `useApiResource` **默认就订阅** `factOfRoute(route)`(`use-api-resource.ts` 里那句
120
- `options.fact ?? factOfRoute(route)`),所以多数情况你什么都不用接;用户自己按的那个动作做完,
121
- 用 `useFactInvalidate()()` 把这条事实标脏。
93
+ `useApiResource` 默认订阅 `factOfRoute(route)`;用户自按动作完成后用 `useFactInvalidate()()` 标脏。
122
94
 
123
95
  ```ts
124
96
  context: { kinds: ['module'], render: async (ref) => `模块 ${ref.parts[0]}:…` },
125
97
  warmReads: () => [['<unit>', '<target>']],
126
98
  ```
127
99
 
128
- * `context`:agent 上下文里引用你这一格时(例:`diy-doctor/module/fx-rate`),由你把它渲染成人话;
129
- `kinds` 列出你认哪几类,**参数形状不对就 `throw`**(说清"形状不对",别默默回一段错的)。
130
- 判据只查形状(`kinds` 非空、`render` 是函数),**不会拿假参数调它** —— 那些参数只有真引用才有。
131
- * `warmReads`:**只给"走 opencli 适配器"的读用**。条目就是那条 opencli 命令的 argv,外壳在启动的
132
- preflight 里拼成 `opencli <argv…> --site-session persistent -f json` 先跑一遍(把站点登录态与首屏焐热)。
133
- 例:`[['cmdb', 'enterprises']]`(一条 opencli 命令的 argv,还带测试)。
134
- **本机读盘、browser bridge、直接打接口的读一律不要写这里** —— 写了外壳会去跑一条不存在的命令,
135
- preflight 只会给个 warn;这些读没有"冷启动"可省,焐不热任何东西。
136
- * `values`(`deps.values`,`ValueHandoff`):把一次写的结果交给别的单元 —— `values.hand({fact, key}, 值)`,
137
- 另一边 `values.take({fact, key})` 取;`key` 自己起(例:一次发布的结果给联动那一格用)。
138
-
139
- ## 9 范例
140
-
141
- 要一个"同形状、能跑"的样子:[SKILL.md](SKILL.md) 的「找不到一件事的时候」—— 模板
142
- (`template-diy/` / `template/`)与装机模块的源码都可以直接读。
100
+ - `context`:把 agent 上下文里的引用渲染成人话;`kinds` 列出识别的类型;形状不对就 `throw`。
101
+ - `warmReads`:只给走 opencli 适配器的读。条目是该 opencli 命令的 argv,启动 preflight 先跑一遍。
102
+ 本地读盘、browser bridge、直连接口的读不要写。
103
+ - `values`:跨单元传值。`values.hand({fact, key}, 值)` / `values.take({fact, key})`。
@@ -1,219 +1,129 @@
1
- # 面板:他看什么、他配什么、画成什么样
1
+ # 面板:内容、配置、状态、样式
2
2
 
3
- 步骤 1 的参考:问什么、他看到什么。正文用**他的视角**写,唯一的例外是 §5.1 ——
4
- "这份配置存不存"有代码形状,那一节给写法。
3
+ 步骤 1 的参考。
5
4
 
6
- ## 1 面板上该有的东西只有三类
5
+ ## 1 只放三类东西
7
6
 
8
- | 类别 | 例子 | 谁来承接 |
7
+ | 类 | 例 | 承接 |
9
8
  |---|---|---|
10
- | **导航** | 换项目、切面板、折叠 | 界面自己(只改他看到的视图) |
11
- | **呈现** | 状态、数字、最近几条历史 | 只读呈现给他 |
12
- | **交代** | "交给 agent"、预填一句指令、一个动作按钮 | 转给 agent |
9
+ | 导航 | 换项目、切面板、折叠 | 界面自身 |
10
+ | 呈现 | 状态、数字、最近几条 | 只读 |
11
+ | 交代 | "交给 agent"、预填指令、动作按钮 | 转给 agent |
13
12
 
14
- **他不该在面板上做的事**:
13
+ 不放:平台写操作(评论、流转、发布)→ agent;详情 / 评论 / 日志 / 翻页 → "去平台看";
14
+ 多步、长等、中途要人、失败要续 → 封成一个动作(一个按钮 + 一个交代入口)。
15
15
 
16
- - 平台上的写(评论、流转、发布)→ 交给 agent;
17
- - 详情、评论、日志、翻页 → 给他一个"去平台看"的去处;
18
- - 一次要动好几下、要等很久、中途要他登录或点头、失败还要接着来的 → **封成一个动作**,面板上只给他一个按钮 + 一个交代入口;中间那些来回留在对话里。
16
+ ## 2 封动作还是交 agent
19
17
 
20
- ## 2 判"封成一个动作"还是"交给 agent"
18
+ 任一为是则封动作:要动平台好几下;要等分钟级;中途需用户本人(登录、点头、冲突);失败要续。
19
+ 都不是 → 交给 agent。
21
20
 
22
- 问他四个问题,任一为"是"就封成一个动作:
21
+ ## 3 什么算配置
23
22
 
24
- 1. 一次要动平台上好几下?
25
- 2. 要等很久(分钟级)?
26
- 3. 中途需要他本人(登录、点头、撞上冲突)?
27
- 4. 失败了要能接着来?
23
+ 只有用户在本面板的偏好:看哪份、显示哪些、钉哪个环境、绑定哪个对象。碰平台的不算配置。
24
+ 形态:一屏选完 + 保存前校验;不做分页向导、多步流程。
28
25
 
29
- 都不是(单步、马上、能先看一遍)→ 交给 agent 就够了。
26
+ ## 4 展示清单
30
27
 
31
- ## 3 什么算"配置"
28
+ 每行三项:
32
29
 
33
- 只有**他自己在这块面板上的偏好**算配置:看哪一份、显示哪些、钉哪个环境、绑定到哪个对象。
34
-
35
- 碰平台的一律不是配置。
36
-
37
- 配置的形态是一个面里**一次选完 + 保存前替他校验**;不做分页向导、不做好几步的流程(他看不到全局,出错也难查)。
38
-
39
- ## 4 展示清单怎么写
40
-
41
- 每条一行,就这三样:
42
-
43
- | 写什么 | 判据 |
30
+ | 项 | 标准 |
44
31
  |---|---|
45
- | 这一格是什么 | 一句他会说的话;出现平台内部术语就重写 |
46
- | 一眼能得出什么结论 | 他要拿它做决定;说不出决定的格子就别放 |
47
- | 点一下去哪 | 去平台看详情,或者交给 agent —— 两者至少有一个 |
48
-
49
- - 一屏不要塞太多:他要的结论放最上面,历史、明细沉到下面。
50
- - 同一列里几张卡要长得一样(标题、刷新、设置、"去平台"的位置一致)。
51
- - 面板上的每个数字,agent 都要能通过自己的能力拿到;每个按钮都要有一句等价的话。做不到就别放。
32
+ | 这一格是什么 | 用户会说的话;有平台术语就重写 |
33
+ | 一眼得出什么结论 | 能支撑决定;不能就不放 |
34
+ | 点一下去哪 | 去平台或交给 agent,至少一个 |
52
35
 
53
- ## 5 配置清单怎么写
36
+ 同列卡片结构一致(标题、刷新、设置、"去平台"位置)。每个数字都要有 agent 能力能取到;每个按钮都要有等价的一句话。
54
37
 
55
- 每项说清这七件事:
38
+ ## 5 配置清单
56
39
 
57
- | 项 | 说清什么 |
58
- |---|---|
59
- | 管什么 | 一句话,用他的词 |
60
- | 默认 | 不给偏好时他看到的会是什么 |
61
- | 能选什么 | 候选从**现在真实存在**的里列;过期的候选不列 |
62
- | 选错会怎样 | 拒绝并说清(还认的候选有哪些),不悄悄换成一个别的 |
63
- | 记多久、记在哪 | 按项目分别记;换项目不串;换仓库/换对象时旧选择作废并让他重选 |
64
- | 怎么生效 | 他按下保存才生效;保存成功直接回到看板并立刻按新的显示;保存失败留在原地告诉他为什么 |
65
- | 怎么清 | 他自己显式清;收起或卸载这块面板**不删**他的配置 |
66
-
67
- ### 5.1 两种配置写法,别混
40
+ 每项七栏:管什么 / 默认 / 候选(只列现存) / 选错(拒绝并列出仍可选项,不静默替换) /
41
+ 记录范围(按项目,换项目不串;换仓库或对象时作废旧选择并要求重选) / 生效(保存后生效,成功回看板刷新,失败留在原地说原因) /
42
+ 清除(用户显式清;收起或卸载面板不删)。
68
43
 
69
- 配置要分清**存不存** —— 它决定代码怎么写,也决定他刷新之后看到什么。`design.json` 的
70
- `config[].persistence` 这一格写的就是这个(`prefs` = 存起来;`view` = 只选一下)。
44
+ ### 5.1 persistence:`view` 还是 `prefs`
71
45
 
72
- | 写法 | 什么时候用 | 刷新后 | 怎么实现 |
46
+ | 写法 | 场景 | 刷新后 | 实现 |
73
47
  |---|---|---|---|
74
- | `view` | 卡片底部一次性的选择(看哪种口径、看几天) | 回默认 | 当 **route 参数**传给模块自己的只读口;非法的退路写进 `wrongChoice` |
75
- | `prefs` | 他配一次、以后一直算数(钉哪个环境、忽略哪些、超时多久) | **还在** | `mount` 返回 `prefs: { resource, handle }`,`handle` 里用 `deps.store` 落盘 |
48
+ | `view` | 卡片底部一次性选择(口径、天数) | 回默认 | 作 route 参数传给只读口;非法值写进 `wrongChoice` |
49
+ | `prefs` | 配一次长期有效(环境、忽略项、超时) | 保留 | `mount` 返回 `prefs: { resource, handle }`,`handle` 用 `deps.store` 落盘 |
76
50
 
77
- **宿主半侧**(最小可抄):
51
+ 宿主侧:
78
52
 
79
53
  ```ts
80
- // mount(deps) 里。按项目分开记:这个项目一份,换项目不串
54
+ // mount(deps) 内;按项目分文件
81
55
  const store = deps.store.for(UNIT_ID, workspace);
82
56
  return {
83
- // …
84
57
  prefs: {
85
58
  resource: 'your-module',
86
- // 校验 + 落盘 + 把新的整份偏好回给调用方(别只回 ok)
87
- handle: (payload) => applyPref(store, payload),
59
+ handle: (payload) => applyPref(store, payload), // 校验 + 落盘 + 返回整份新偏好
88
60
  },
89
61
  };
90
62
  ```
91
63
 
92
- **浏览器半侧**:写走 `prefs` 通道,读还是模块自己的只读口(别为配置另开一条)。
93
- 排版与内边距都是外壳给的默认(`Field` / `TextField`),**模块不需要为"能看"写 CSS**:
64
+ 浏览器侧:写走 `prefs`,读取仍走模块只读口。布局与内边距用外壳默认(`Field` / `TextField`),不必为可读性写 CSS。
94
65
 
95
66
  ```tsx
96
67
  const write = useHostWrite({ channel: 'prefs', resource: 'your-module' });
97
- // 控件用 kit 的(Field + TextField / ChoiceGroup),外面套 SettingsSection,保存用 SaveBar;失败留在原地
98
- write.send({ ignored, timeoutSeconds, workspace });
68
+ write.send({ ignored, timeoutSeconds, workspace }); // 控件:Field + TextField / ChoiceGroup;容器 SettingsSection;保存 SaveBar
99
69
  ```
100
70
 
101
- `handle` 里那几件事(成熟模块都这么做):
102
-
103
- - **未设置 ≠ 空**:没写过就出"第一次选"那一屏;显式选空是"空态",两者不能混;
104
- - **清空 = 回到默认,并把文件收掉**(不留一个空对象);
105
- - **按项目 / 工坊分开记**,换项目不串;
106
- - **不认识的值报错,并把还认的候选列出来**(不悄悄换一个别的);
107
- - 去重、按他给的顺序存。
108
-
109
- **他会看到什么**:面板上多一段"他能自己配的"(填 / 选 + 保存 + 回到默认);存成功卡上立刻按新的显示
110
- (写偏好会 bump 这个单元声明过的事实,见 [LINKAGE.md](LINKAGE.md) §8);**存失败留在原地并说清为什么**。
111
- agent 那一侧也要能通过模块自己的能力读到同一份偏好。
112
-
113
- ## 6 界面的几个习惯
114
-
115
- - **有不打扰的默认就别弹设置**:能用默认值读出他关心的那份,就直接显示,别先问他。真的分不清是哪一份,才把选择摆到他面前(不是先让他读一句话再点一次)。
116
- - **能选的直接摆出来**:候选就两三条时,平铺一行一行给他点,别藏进下拉。
117
- - **量词写在值旁边**("3 条"、"6 个文件"),别让他猜单位。
118
- - **时间写成他看得懂的样子**,不要原始时间戳。
119
- - **默认收起**:历史、明细折叠,露出最近一条;只有一条时不给折叠三角(没有可展开的东西)。
120
- - **屏幕上的字越少越好**:他能看懂的(红点绿点、数字)就不用再写一段规则解释;删掉的东西不要留一行说明。
121
- - **默认状态点**只有四种意思:在做 / 做完了 / 出错 / 没在跑。
122
- - **外链一律用 kit 的 `Link`**(`h(Link, { href: … }, 文案)` —— `h` 从 `react` 引,**不在 kit 面里**):新窗口 + `rel` + 自带外链箭头,
123
- **它自带的样子就是唯一一份,别去掉箭头、别换箭头、别自己调**(没有 `icon` 这个口子)——
124
- 全仓的链接必须长得一样。
125
- 模块源码里手写 `<a>` / `h('a', …)` 会被「样式归属」判据**直接判红**。
126
- **文案里也不许自带箭头**(`'去网关看账单 →'` 这种)—— 箭头由组件给,自带的话页面上就是两颗。
127
- 它内部已经把 dsh 的图标原语包好了,所以模块**不用**为它声明 `client.external`。
128
- - **哪几种手写 `<a>` 不算 `Link`(判据不该咬、也别硬迁)**:判据钉的是**"手写 `<a>` 这件事本身"**
129
- (`Link` 是唯一出处),下面三类**有意**留着,因为它们**不是"正文链接"**——
130
- - **图标链**(icon-only 的 `<a>`,靠 `title` / `aria-label` 顶着):`Link` 一定会多画一颗 ↗,
131
- 套进去就是两颗,尺寸与槽位它也表达不了 ⇒ 留 `<a>`。
132
- - **按钮皮的链**(`.anchorButton` 那类 28 高 / 描边的"看起来像按钮、实际是链接"):**必须是链接的动作
133
- 留真 `<a>`** —— `href` 带来的是中键新开、右键复制链接、悬停看 URL;塞成
134
- `onClick: () => window.open(…)` 的按钮,这三件一起丢。
135
- - **整行链**(一行整体可点,`flex: 1` / `color: inherit`):它是**那条行的布局槽**,不是正文里的字。
136
- **要放宽这一条就走棘轮**:那张已知豁免表(`module-tools` 的 `style` 判据里,`ANCHOR_EXEMPT`)
137
- **只许减不许加**(迁一处删一行);真要加一格,那是**改判据口径**,得写清"为什么 `Link` 表达不了它"。
138
- 口径的权威那份是 `style.mjs` 里 `BARE_ANCHOR` 那一段注释(`ANCHOR_EXEMPT` 上面)
139
- 与 `module-tools/README.md` 的 `style` 那一行。
140
- - **"去看某处"用哪个**:跳**整张卡对应的系统** → 卡头那颗图标按钮(`CardHead.platformHref`,给这一个就够);
141
- 跳**一个具体页面 / 一条具体记录** → `Link`(正文里的文字链接);**触发一个动作**(刷新、重建、去登录)→
142
- dsh 的 `Button`,或阻断屏里的 `action`。区别在"跳去哪"和"它是不是一个动作",不在好看不好看。
143
- - **标签 + 输入框用 `Field` + `TextField`**(排布与内边距是外壳的默认,别自己写 CSS,见 §5.1)。
144
- - **要做什么用哪件,照 [KIT.md](KIT.md) 抄**("要做什么 → 用哪件 → 最小写法"的表)。
145
- 下面几条是口径,KIT.md 是写法。
146
- - **字号与重点**:走那把刻度(`--dsw-font-*`:11 / 12 / 13 / 14 / 16 / 20 / 24),
147
- **但不许"整张卡一样大"** —— 要有重点。最该大的那个数字(余额、总数、还剩多少)
148
- 就用刻度里最大那档 `--dsw-font-xl-24`(24/32、600 重),它旁边的说明 12。
149
- 这一档是**给重点留的、鼓励用**:卡里最大的字比正文大一倍,比全卡 12 号好读得多。
150
- 刻度外非要一个字面值(28/32 那种)时,在模块 `README.md` 里写一句为什么,别静悄悄写。
151
- 成列的数字加 `font-variant-numeric: tabular-nums`。
152
- **别为了"统一"把重点压回正文大小**——那才是不合口径。
153
- - **颜色与间距也走令牌**(`--dsw-*` / `--wb-*`);自己写 CSS 只写布局(flex / grid / gap / 对齐)。
154
-
155
- ## 7 状态矩阵怎么写
156
-
157
- 把每种状态都走一遍,一个不落:
158
-
159
- 没有绑定 / 还没接入 / **分不清是哪一份** / 正在读 / 有数据 / 正在做 / 卡住了(要登录、没权限、超时、能力没装好)/ 读到了但是空 / 数字是上一轮的。
160
-
161
- 每一格写三样:
162
-
163
- | 列 | 写法 |
164
- |---|---|
165
- | 他看到什么 | 屏幕上是什么(哪句话、哪个画面、哪颗点) |
166
- | 他能做什么 | 一个动作(去哪补、点哪个、重试) |
167
- | agent 能接着做什么 | 一句 agent 能照做的话 |
71
+ `handle` 规则:未设置 ≠ 空(首次进入"第一次选");清空 = 回默认并删文件;按工作区分文件;
72
+ 未知值报错并列出候选;去重、保留用户顺序。
73
+ 保存成功后卡片按新偏好显示(写偏好 bump 该单元的事实,[LINKAGE.md](LINKAGE.md) §8);失败留在原地说原因。
74
+
75
+ ## 6 界面规则
76
+
77
+ 文案(主句 / 原文、通俗、zh / en)见 [COPY.md](COPY.md) §3。
78
+
79
+ - 有默认可读的数据就直接显示,不先弹设置;只有分不清时才摆选择。
80
+ - 候选 ≤3 个时平铺,不放进下拉。
81
+ - 历史、明细默认折叠,露出最近一条;只有一条时不给折叠控件。
82
+ - 状态点只有四义:在做 / 完成 / 出错 / 未运行。
83
+ - 外链一律 `Link`(`h(Link, { href }, 文案)`;`h` 从 `react` 引):新窗口 + `rel` + 箭头,唯一形态,
84
+ 没有 `icon` 口子;文案里不自带箭头。手写 `<a>` / `h('a')` 会被 `style` 判据判红。
85
+ 例外仅三类非正文链接:图标链、按钮样式的链、整行链。放宽走 `ANCHOR_EXEMPT`,只减不加。
86
+ - 跳整张卡对应的系统 → 卡头 `CardHead.platformHref`;跳具体页面 / 记录 → `Link`;触发动作 → dsh `Button` 或阻断屏 `action`。
87
+ - 标签 + 输入框用 `Field` + `TextField`,不自写 CSS。
88
+ - 组件选型照 [KIT.md](KIT.md)。
89
+ - **字号与重点**:走刻度,不整卡同字号 —— 刻度以 `--dsw-font-*` 的定义为准,别背数字
90
+ (`workbench_diy_components` `scope: 'tokens'`、`bucket=font` 现查)。
91
+ 最重点的数字用最大一档(`--dsw-font-xl-24`),旁注用最小一档;刻度外字面值需在模块 `README.md` 说明。
92
+ 成列数字加 `font-variant-numeric: tabular-nums`。
93
+ - 颜色与间距走令牌;名字现查不猜:`workbench_diy_components` 给 `scope: 'tokens'`(`bucket` 按族、`name` 连浅/深值)。
94
+ 写进 CSS 的令牌名由 `check --only style` 对着现读的清单验,拼错判红。自写 CSS 只写布局(flex / grid / gap / 对齐)。
168
95
 
169
- 规矩:
96
+ ## 7 状态矩阵
170
97
 
171
- - 每句都要**能照做**:缺什么、去哪补、谁补。
172
- - **平台没给的那一格就不占位**(不留孤零零的字段名、不留空的一行)。
173
- - **读不到就说读不到**,并说清为什么(例:手上这份能力太旧);**绝不显示 0**。
174
- - 有确定答案就不打扰他(能按默认读出来就别弹设置面)。
175
- - 真机上造不出来的状态也要**在设计上**画出来(照这一格写清)—— 模块自己的 `plugin.test.ts` 把五态各喂一遍就够(`check --only cards` 会拿**七种外壳侧输入**各喂一遍 —— 它只问"退化得干不干净",**不断言**"画的是哪一态那一屏")。
98
+ 状态全集:没有绑定 / 未接入 / 分不清是哪一份 / 正在读 / 有数据 / 正在做 / 卡住(登录、权限、超时、能力未装) /
99
+ 读到但空 / 数字是上一轮。
176
100
 
177
- ### 7.1 图例就是把屏幕画成 ASCII
101
+ 每格三列:看到什么(哪句话、哪个画面、哪颗点)/ 能做什么(去哪补、点哪、重试)/ agent 能接着做什么(可照做的一句)。
178
102
 
179
- **跟用户沟通主要就靠这些图。** 矩阵左列写**图号**(A / B / C…),图放在矩阵前面,一张 ASCII = 那一种状态在屏幕上是什么样。至少要有这几屏:
103
+ 规则:每句可照做;平台没给的格不留占位;读不到就说读不到并给原因,不显示 0;有确定答案就不打扰。
104
+ 真机造不出的状态也要在设计里画;`plugin.test.ts` 覆盖五态(`check --only cards` 用七种外壳侧输入各跑一遍,
105
+ 只判"是否干净退化",不判画的是哪一态)。
180
106
 
181
- - **有数据**(正常那张卡)
182
- - **空态**(图标 + 一句话,居中,**没有按钮**)
183
- - **阻断 / 卡住**(**整张卡换成这一屏**:图标 + 一句话 + 按钮)
184
- - **提示**(卡片照常画数据,只在最上面多一条细提示行)
185
- - **骨架**(几行灰条:正在读、还没有数据)
186
- - **在转**(列表照常在,只有卡片头那颗刷新在转)
187
- - **一行里那些记号挨着的样子**(状态点 + 编号 + 元信息 + 行尾两颗)
188
- - **状态点的几档**(只有颜色不同;**撞色的那两档要在图下点明靠什么分开**)
189
- - **可点的筛选**(几颗、选中的那颗什么样)
190
- - **只在某种模式出现的东西**
191
- - **审批弹窗**(哪一行是套件给的、哪一行是系统给的、按钮在哪)
107
+ ### 7.1 图例
192
108
 
193
- 三条写法:
109
+ 矩阵左列写图号,图按图号排。至少这些屏:有数据 · 空态(图标 + 一句话,无按钮)· 阻断(整卡替换:图标 + 话 + 按钮)·
110
+ 提示(数据照常,顶部一条)· 骨架 · 在转(列表在,卡头刷新转)· 行内记号(状态点 + 编号 + 元信息 + 行尾两颗)·
111
+ 状态点各档(撞色两档在图下注明区分方式)· 可点筛选 · 仅某模式出现 · 审批弹窗(每行谁给的)。
194
112
 
195
- - **用真字**:图里的文案用界面上真实那句(例「没有指派给你的缺陷。」),别写"一句空态文案"。
196
- - **别拿图标代替画面**:给状态起个名字、配个 `⛔` 这类符号,用户还是分不清;一眼能认的是**形状**(整卡换掉 vs 多一行)与**位置**(行首的点、行尾的两颗)。
197
- - **画不成的才写词**:动作、agent 的下一步、时间性的"不变 / 自己变",写成词并说清意思。
198
- - **真机上造不出来的状态**:沟通时照样画(画的是设计意图);实现时**要让它能用真实输入走到**(换个空目录、换个坏路径、先不选),模块自己的 `plugin.test.ts` 把五态各喂一遍就够。
113
+ 图里用界面真实文案;不用符号代替画面(形状与位置才是识别点);画不成的写词并定义。
114
+ 真机造不出的照样画;实现时用真实输入走到(空目录、坏路径、未选择)。
199
115
 
200
- ## 8 范例(真实产出的形状)
116
+ ## 8 范例
201
117
 
202
- 要一个"同形状、能跑"的样子:[SKILL.md](SKILL.md) 的「找不到一件事的时候」—— 模板
203
- (`template-diy/` / `template/`)与装机模块的源码都可以直接读。
118
+ `template-diy/`(带数据源)与 `template/`(空壳)。
204
119
 
205
- ## 9 界面边界:kit 不够用时怎么办
120
+ ## 9 kit 不够时
206
121
 
207
- **先从 kit 拿**(`@dsh-workbench/core/client`,`check --only kit` 会列全这份外壳有什么)。
208
- kit 里确实没有、而你要的又是标准控件(按钮、选择器、设置区块那种)时,可以引 dsh 的客户端原语 ——
209
- **有哪些**问 `dsh-wb-module check --only primitives`(它还会把"kit 里已有"的那批挑出来):
122
+ 先查 kit(`check --only kit`)。确无且需要标准控件时,可引 dsh 客户端原语(清单:`check --only primitives`):
210
123
 
211
- * 只在**浏览器侧**引(`src/client.tsx` 与 `src/components/**` 那一侧);
212
- * 在 `package.json` 的 `dsh.client.external` 里**声明** `@deepseek-ai/dsh-client-ui-primitives`,
213
- 同时把 `devDependencies` 里那行**精确版**对齐到外壳钉的那版(骨架默认已经两处都写好了;
214
- 声明完记得 `pnpm install`,否则 `pnpm typecheck` 找不到它);
215
- * 宿主侧(`src/host.ts`)**一个字都不许碰** —— `check` 的源码边界判据会红;宿主侧 import
216
- `src/components/**` 还会被 `arch` 按跨运行时(S23)判红 —— 组件整片算 client 面。
124
+ - 只在浏览器侧引(`src/client.tsx`、`src/components/**`)。
125
+ - `dsh.client.external` 声明 `@deepseek-ai/dsh-client-ui-primitives`;`devDependencies` 用与外壳一致的精确版。
126
+ 改完 `pnpm install`。
127
+ - 宿主侧不引:`source` 判据红;宿主 import `src/components/**` 还会被 `arch` 的 S23 判红。
217
128
 
218
- 理由不是"能省事":装机成熟模块里有一半的界面是这么搭的。但**能拿 kit 的时候别自己画** —— kit 那套跟着外壳一起换主题、跟着语言走,
219
- 自己画的不会。
129
+ kit 优先:kit 跟随外壳主题与语言。