dsh-plugin-dev-kb 1.8.0 → 1.8.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 (229) hide show
  1. package/CHANGELOG.md +186 -178
  2. package/README.en.md +172 -172
  3. package/README.md +183 -183
  4. package/kb/INDEX.md +236 -234
  5. package/kb/README.md +88 -88
  6. package/kb/extra/AGENTS.md +77 -77
  7. package/kb/extra/deepseek-llm-api-wire-extensions.md +162 -162
  8. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +162 -162
  9. package/kb/extra/defensive-patterns/package-surface.md +233 -232
  10. package/kb/extra/defensive-patterns/package-surface.zh.md +233 -232
  11. package/kb/extra/defensive-patterns/remote-and-api.md +117 -117
  12. package/kb/extra/defensive-patterns/remote-and-api.zh.md +117 -117
  13. package/kb/extra/development.md +221 -221
  14. package/kb/extra/development.zh.md +228 -228
  15. package/kb/extra/event-producer-consumer.md +133 -123
  16. package/kb/extra/event-producer-consumer.zh.md +135 -125
  17. package/kb/extra/module-graph.md +1961 -1888
  18. package/kb/extra/module-graph.zh.md +1963 -1890
  19. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.md +60 -0
  20. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.zh.md +60 -0
  21. package/kb/extra/persistence-changes/README.md +92 -92
  22. package/kb/extra/persistence-changes/README.zh.md +92 -92
  23. package/kb/extra/persistence-changes/historical-formats/README.md +75 -75
  24. package/kb/extra/persistence-changes/historical-formats/README.zh.md +75 -75
  25. package/kb/extra/persistence-changes/releases/README.md +103 -103
  26. package/kb/extra/persistence-changes/releases/README.zh.md +103 -103
  27. package/kb/extra/rescope.md +55 -55
  28. package/kb/extra/rescope.zh.md +55 -55
  29. package/kb/extra/subsystems/boot.md +631 -621
  30. package/kb/extra/subsystems/boot.zh.md +631 -621
  31. package/kb/extra/subsystems/computer-use.md +179 -137
  32. package/kb/extra/subsystems/computer-use.zh.md +179 -137
  33. package/kb/extra/subsystems/extensions.md +387 -384
  34. package/kb/extra/subsystems/extensions.zh.md +387 -384
  35. package/kb/extra/subsystems/feedback.md +418 -400
  36. package/kb/extra/subsystems/feedback.zh.md +418 -400
  37. package/kb/extra/subsystems/forge.md +2169 -1226
  38. package/kb/extra/subsystems/forge.zh.md +2171 -1226
  39. package/kb/extra/subsystems/liveshare.md +167 -158
  40. package/kb/extra/subsystems/liveshare.zh.md +167 -158
  41. package/kb/extra/subsystems/mcp.md +237 -234
  42. package/kb/extra/subsystems/mcp.zh.md +237 -234
  43. package/kb/extra/subsystems/office-kit.md +122 -0
  44. package/kb/extra/subsystems/office-kit.zh.md +122 -0
  45. package/kb/extra/subsystems/working-directory.md +95 -64
  46. package/kb/extra/subsystems/working-directory.zh.md +95 -64
  47. package/kb/extra/subsystems/worktrees.md +187 -127
  48. package/kb/extra/subsystems/worktrees.zh.md +187 -127
  49. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.md +21 -21
  50. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.zh.md +21 -21
  51. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.md +18 -0
  52. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.zh.md +18 -0
  53. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.md +18 -0
  54. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.zh.md +18 -0
  55. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.md +34 -0
  56. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.zh.md +34 -0
  57. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.md +49 -0
  58. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.zh.md +49 -0
  59. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.md +36 -0
  60. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.zh.md +36 -0
  61. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.md +26 -0
  62. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.zh.md +26 -0
  63. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.md +22 -0
  64. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.zh.md +22 -0
  65. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.md +21 -0
  66. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.zh.md +21 -0
  67. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.md +23 -0
  68. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.zh.md +23 -0
  69. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.md +20 -0
  70. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.zh.md +20 -0
  71. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.md +18 -0
  72. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.zh.md +18 -0
  73. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.md +23 -0
  74. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.zh.md +23 -0
  75. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.md +35 -0
  76. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.zh.md +35 -0
  77. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.md +26 -0
  78. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.zh.md +26 -0
  79. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.md +26 -0
  80. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.zh.md +26 -0
  81. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.md +19 -0
  82. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.zh.md +19 -0
  83. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.md +26 -0
  84. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.zh.md +26 -0
  85. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.md +22 -0
  86. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.zh.md +22 -0
  87. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.md +25 -0
  88. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.zh.md +25 -0
  89. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.md +48 -0
  90. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.zh.md +48 -0
  91. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.md +45 -0
  92. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.zh.md +45 -0
  93. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.md +19 -0
  94. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.zh.md +19 -0
  95. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.md +17 -0
  96. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.zh.md +17 -0
  97. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.md +27 -0
  98. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.zh.md +27 -0
  99. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.md +20 -0
  100. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.zh.md +20 -0
  101. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.md +19 -0
  102. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.zh.md +19 -0
  103. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.md +18 -0
  104. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.zh.md +18 -0
  105. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.md +41 -0
  106. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.zh.md +41 -0
  107. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.md +21 -0
  108. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.zh.md +21 -0
  109. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.md +29 -0
  110. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.zh.md +29 -0
  111. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.md +25 -0
  112. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.zh.md +25 -0
  113. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.md +31 -0
  114. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.zh.md +31 -0
  115. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.md +24 -0
  116. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.zh.md +24 -0
  117. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.md +24 -0
  118. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.zh.md +24 -0
  119. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.md +19 -0
  120. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.zh.md +19 -0
  121. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.md +15 -0
  122. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.zh.md +15 -0
  123. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.md +28 -0
  124. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.zh.md +28 -0
  125. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.md +36 -0
  126. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.zh.md +36 -0
  127. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.md +22 -0
  128. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.zh.md +22 -0
  129. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.md +31 -0
  130. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.zh.md +31 -0
  131. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.md +18 -0
  132. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.zh.md +18 -0
  133. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.md +30 -0
  134. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.zh.md +30 -0
  135. package/kb/extra/web-styling.md +57 -57
  136. package/kb/extra/web-styling.zh.md +57 -57
  137. package/kb/meta/search-index.json +4508 -3980
  138. package/kb/meta/source.json +18 -18
  139. package/kb/site/develop/practice/llm-adapter.md +192 -192
  140. package/kb/site/en/develop/practice/llm-adapter.md +192 -192
  141. package/kb/site/en/guide/desktop-uninstall-cleanup.md +63 -0
  142. package/kb/site/en/guide/plugin-market.md +153 -151
  143. package/kb/site/en/guide/providers.md +234 -234
  144. package/kb/site/en/guide/quickstart.md +35 -34
  145. package/kb/site/en/reference/capability-seams.md +789 -767
  146. package/kb/site/en/reference/config-catalog.md +5432 -5128
  147. package/kb/site/en/reference/cookbook/adding-a-package.md +175 -175
  148. package/kb/site/en/reference/cookbook/adding-a-tool.md +105 -104
  149. package/kb/site/en/reference/cookbook/extension-cookbook.md +178 -135
  150. package/kb/site/en/reference/cordis-api/context.md +373 -369
  151. package/kb/site/en/reference/cordis-api/fiber.md +457 -433
  152. package/kb/site/en/reference/cordis-api/inherited.md +44 -44
  153. package/kb/site/en/reference/cordis-api/service.md +118 -107
  154. package/kb/site/en/reference/experimental-persistence-catalog.md +36 -23
  155. package/kb/site/en/reference/index.md +174 -174
  156. package/kb/site/en/reference/persistence-catalog.md +9453 -9432
  157. package/kb/site/en/reference/subsystems/compaction.md +288 -288
  158. package/kb/site/en/reference/subsystems/core.md +1172 -1171
  159. package/kb/site/en/reference/subsystems/credentials.md +526 -497
  160. package/kb/site/en/reference/subsystems/filesystem.md +708 -708
  161. package/kb/site/en/reference/subsystems/index.md +82 -82
  162. package/kb/site/en/reference/subsystems/llm-streaming.md +1290 -1288
  163. package/kb/site/en/reference/subsystems/lsp.md +230 -206
  164. package/kb/site/en/reference/subsystems/persistence.md +451 -432
  165. package/kb/site/en/reference/subsystems/plan.md +91 -91
  166. package/kb/site/en/reference/subsystems/ptc-runtime.md +295 -261
  167. package/kb/site/en/reference/subsystems/sandbox.md +250 -232
  168. package/kb/site/en/reference/subsystems/session-query.md +525 -515
  169. package/kb/site/en/reference/subsystems/session-reference.md +231 -229
  170. package/kb/site/en/reference/subsystems/session.md +1478 -1431
  171. package/kb/site/en/reference/subsystems/sidebar-right.md +165 -165
  172. package/kb/site/en/reference/subsystems/skills.md +356 -356
  173. package/kb/site/en/reference/subsystems/slots.md +235 -231
  174. package/kb/site/en/reference/subsystems/terminal.md +188 -188
  175. package/kb/site/en/reference/subsystems/tools.md +902 -891
  176. package/kb/site/en/reference/subsystems/user-questions.md +330 -327
  177. package/kb/site/en/reference/subsystems/web-client.md +161 -104
  178. package/kb/site/en/reference/subsystems/web-server.md +434 -351
  179. package/kb/site/en/reference/subsystems/web.md +268 -268
  180. package/kb/site/en/reference/subsystems/workflow.md +287 -282
  181. package/kb/site/en/reference/subsystems/workspace.md +743 -651
  182. package/kb/site/en/reference/tool-catalog.md +2867 -2704
  183. package/kb/site/guide/desktop-uninstall-cleanup.md +63 -0
  184. package/kb/site/guide/plugin-market.md +153 -151
  185. package/kb/site/guide/providers.md +234 -234
  186. package/kb/site/guide/quickstart.md +35 -34
  187. package/kb/site/reference/capability-seams.md +789 -767
  188. package/kb/site/reference/config-catalog.md +5432 -5128
  189. package/kb/site/reference/cookbook/adding-a-package.md +175 -175
  190. package/kb/site/reference/cookbook/adding-a-tool.md +107 -106
  191. package/kb/site/reference/cookbook/extension-cookbook.md +182 -139
  192. package/kb/site/reference/cordis-api/context.md +373 -369
  193. package/kb/site/reference/cordis-api/fiber.md +459 -435
  194. package/kb/site/reference/cordis-api/inherited.md +44 -44
  195. package/kb/site/reference/cordis-api/service.md +118 -107
  196. package/kb/site/reference/experimental-persistence-catalog.md +36 -23
  197. package/kb/site/reference/index.md +178 -178
  198. package/kb/site/reference/persistence-catalog.md +9453 -9432
  199. package/kb/site/reference/subsystems/compaction.md +288 -288
  200. package/kb/site/reference/subsystems/core.md +1184 -1183
  201. package/kb/site/reference/subsystems/credentials.md +526 -497
  202. package/kb/site/reference/subsystems/filesystem.md +708 -708
  203. package/kb/site/reference/subsystems/index.md +82 -82
  204. package/kb/site/reference/subsystems/llm-streaming.md +1296 -1294
  205. package/kb/site/reference/subsystems/lsp.md +230 -206
  206. package/kb/site/reference/subsystems/persistence.md +451 -432
  207. package/kb/site/reference/subsystems/plan.md +91 -91
  208. package/kb/site/reference/subsystems/ptc-runtime.md +295 -261
  209. package/kb/site/reference/subsystems/sandbox.md +250 -232
  210. package/kb/site/reference/subsystems/session-query.md +525 -515
  211. package/kb/site/reference/subsystems/session-reference.md +231 -229
  212. package/kb/site/reference/subsystems/session.md +1482 -1435
  213. package/kb/site/reference/subsystems/sidebar-right.md +165 -165
  214. package/kb/site/reference/subsystems/skills.md +356 -356
  215. package/kb/site/reference/subsystems/slots.md +239 -235
  216. package/kb/site/reference/subsystems/terminal.md +188 -188
  217. package/kb/site/reference/subsystems/tools.md +902 -891
  218. package/kb/site/reference/subsystems/user-questions.md +330 -327
  219. package/kb/site/reference/subsystems/web-client.md +161 -104
  220. package/kb/site/reference/subsystems/web-server.md +434 -351
  221. package/kb/site/reference/subsystems/web.md +268 -268
  222. package/kb/site/reference/subsystems/workflow.md +287 -282
  223. package/kb/site/reference/subsystems/workspace.md +743 -651
  224. package/kb/site/reference/tool-catalog.md +2872 -2709
  225. package/lib/index.js +359 -359
  226. package/package.json +68 -68
  227. package/skills/dsh-plugin-dev-kb.md +71 -70
  228. package/kb/extra/subsystems/office-to-pdf.md +0 -87
  229. package/kb/extra/subsystems/office-to-pdf.zh.md +0 -87
@@ -1,235 +1,239 @@
1
- ---
2
- editSource: "docs/subsystems/slots.zh.md"
3
- rawMarkdownPath: "reference/subsystems/slots.md"
4
- outline: [2,3]
5
- ---
6
-
7
- # Web Client Slots
8
-
9
- Slots 是 Web Client 的类型化 React 组合系统。[`dsh-client-ui-slots`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-slots/README.zh.md)定义不依赖 React 的注册表与类型代数;[`dsh-client-ui-renderer`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-renderer/README.zh.md)把可观测源绑定成钩子、渲染整棵树,并在内部拥有 React context。功能插件通过 `ctx.slots.register()` 贡献 UI,绝不导入其他功能插件的组件。
10
-
11
- 本文记录 slot 的所有权、组件输入、扩展 API 与当前层级。外围的启动、Remote、Client model 与 Conversation 数据通路见 [Web Client 架构](./web-client.md)。
12
-
13
- `plugins.bundle.config` 以 npm 包名为 key,提供 Bundle 详情配置。`plugins.bundle.activation` 在用户显式启用后渲染可选引导,由拥有者提供关闭引导和打开该 Bundle 详情的回调。`conversation.input.activity` 提供模型选择器与发送按钮之间的单个活动控件,可展开工具栏并在卸载时释放展开状态。
14
-
15
- 插件目录声明 `plugins.add.actions`,它是 root 作用域的 list,在添加插件菜单的安装项之后提供 `MenuItemButton` 行。owner 提供 `onDismiss()`,用于开始动作前关闭菜单。该 slot 遵循所属插件页面声明的生命周期。
16
-
17
- root 作用域的 list `sidebar.panellist.actions`、`conversation.session.header.views.actions` 和 `sidebar.right.tab.guide.actions` 提供面板行、View 标签和右侧栏引导卡片之后“更多”菜单的菜单行。区域只在其 list 有注册项时画“更多”按钮与菜单,并传入可自定义的入口及其 Pin 状态、`onOpen`、`onPinnedChange` 与 `onDismiss`。面板和 View 入口还通过可选的 `active` 状态标识当前选中项,该状态独立于 Pin 状态。root 作用域的 `sidebar.panel.icon` factory 拥有 `sidebar.panellist` list,按 `id`、`size` 与 `active` 为侧栏行和更多菜单入口渲染已注册图标。各区域在内存中维护已收起的入口 id;[`ui-entry-customization`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-entry-customization/README.zh.md) 注册随产品提供的菜单行。
18
-
19
- [ui-workspace](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-workspace/README.zh.md#understand-the-implementation) 记录 Session 行的扩展位置、显示条件和键盘行为。
20
-
21
- [ui-settings](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-settings/README.zh.md#filling-the-settings-slots) 记录设置页面与导航图标扩展点。
22
-
23
- ## 声明与生命周期
24
-
25
- `SlotMap` 是编译期注册表。包通过声明合并写入 key、cardinality(基数)、scope、owner props、keyed props 与可选的 slot 级 inject face。运行时声明则是拥有该渲染位置的组件在 `children` 中给出的对应条目。
26
-
27
- 声明一个 child 会同时产生三种效果:令该 child key 生效、授权 parent entry 调用 `renderSlot` 或 `renderSlotChain`,以及记录运行时 dispatch 规格。每个声明只能有一个存活 owner。向未声明 slot 注册,或重复声明其他 entry 已拥有的 child,都会在插件激活时失败。
28
-
29
- `root` 是唯一内建声明,也是唯一由 Cordis service 自身渲染的 key。`ui-renderer` 调用 `ctx.slots.renderSlot('root', {})`;其余每个后代都通过声明它的 entry 所收到的 `renderSlot` 或 `renderSlotChain` prop 渲染。
30
-
31
- 注册和声明遵循 Cordis effect 生命周期。销毁一个 entry 会移除其贡献,并递归折叠它声明的 child slots。因此,向其他包的 slot 贡献功能时使用 `ctx.slots.inject(key, callback)`:callback 会在每段声明生命周期内运行,owner 折叠时其 effect 随之移除,owner 再次挂载时则重新运行。
32
-
33
- ```tsx ignore-check
34
- import type { Context } from '@deepseek-ai/cordis'
35
- import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
36
- import type {} from '@deepseek-ai/dsh-client-ui-session/client'
37
- import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
38
-
39
- type HeaderActionProps = PropsRuntime<'conversation.session.header.actions'>
40
-
41
- function HeaderAction({ useSession }: HeaderActionProps) {
42
- const running = useSession(snapshot => snapshot.running)
43
- return <button disabled={running}>Review</button>
44
- }
45
-
46
- export const inject = ['slots']
47
-
48
- export function apply(ctx: Context): void {
49
- ctx.slots.inject('conversation.session.header.actions', () =>
50
- ctx.slots.register({
51
- name: 'conversation.session.header.actions',
52
- id: 'review',
53
- order: 100,
54
- }, HeaderAction))
55
- }
56
- ```
57
-
58
- ## Cardinality 与 scope
59
-
60
- Slot 声明固定两个相互独立的维度。
61
-
62
- | 维度 | 值 | 含义 |
63
- |---|---|---|
64
- | cardinality | `single` | 单个 cell,渲染当前 priority 胜者;需要并列内容时应声明 child slot,而不是把它当作列表。 |
65
- | cardinality | `list` | cell 由必填 `id` 定址,先按 `order`、再按注册顺序排列。 |
66
- | cardinality | `keyed` | owner 传入 `entryKey`;匹配 cell 以该 key 对应的 props 渲染。 |
67
- | cardinality | `chain` | 每个 entry 提供纯 `select(owner)` 函数;按 priority 顺序遇到的第一个非 null 结果获选,并以 `matched` 传给组件;全部拒绝时渲染 owner fallback。 |
68
- | cardinality | `hoc` | entry 层层包裹 owner 经 `renderSlot(key, owner, { children })` 传入的内容,最小者在最外层;见 [Hoc 层](#hoc-layers)。 |
69
- | scope | `root` | 一个 root 作用域组件和 store 实例。 |
70
- | scope | `session-maybe` | 继承外围 Provider binding,但没有 binding 时仍可渲染;Session 值是可选的。 |
71
- | scope | `session` | 要求可解析的外围 Provider binding,并收到确定存在的 Session 值。 |
72
-
73
- 对于 `single`、`list`、`keyed` 和 `hoc` cell,`priority` 是遮蔽优先级;对于 `chain`,它是选举顺序。数值越小越先运行或渲染。普通增量贡献应选用新的 list 或 hoc `id`,或 keyed `key`;复用已有 cell 表示有意替换其展示。
74
-
75
- <a id="hoc-layers"></a>
76
-
77
- ### Hoc 层
78
-
79
- hoc entry 是以必填 `id` 寻址的一层。各层依次按 `order`、`priority`、注册顺序升序嵌套,最小者在最外层。每层收到同一份 owner props,并以 `children` 收到内一层(最内层是 owner 的内容),且只渲染一次;owner props 不得使用 `children` 这个名字。省略 `children` 时各层包裹空内容;没有存活的层时原样渲染内容。
80
-
81
- - 重新挂载:增减一层会让其内部内容重新挂载,崩溃的层退出 slot 也是如此;`session` 或 `session-maybe` 作用域的层在 Session binding 变化时也会让内部内容重新挂载。
82
- - 错误:崩溃的层渲染它的 `children` 并退出 slot。被包裹内容抛出的错误穿过所有层,不记到任何层名下;层如果自己在 `children` 外包错误边界,捕获到的是内部包装错误而不是原始错误。
83
- - 布局:outlet 会在 owner 与内容之间插入一个 `display: contents` 的 `[data-slot]` 元素,所以 owner 侧的选择器不能假定内容是直接子元素。层自身不得产生盒子——例如应使用 `display: contents`——否则内容会脱离父元素的布局。
84
-
85
- <a id="component-inputs"></a>
86
-
87
- [右键菜单插件](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-context-menu/README.zh.md) 通过 `provideRoot` 贡献 `useContextMenu`;每个作用域接收同一个由插件拥有的触发器工厂。提供方卸载时,注入属性与保留的处理器一并失效。其根作用域 keyed Slot `contextMenu.icon` 根据操作元数据渲染业务方提供的图标。
88
-
89
- ## 组件输入
90
-
91
- 注册组件会在 binding 位置收到组装后的输入。组件应从这些类型推导 props,不要重新抄写成员。
92
-
93
- | 输入 | 声明者 | 组件类型 |
94
- |---|---|---|
95
- | owner 值与标准 scope 值 | `SlotMap` 条目与已安装的 scope adapter | `PropsRuntime<K>` |
96
- | 获授权的 child renderer | 注册项的 `children` keys | `PropsRenderSlots<S>` |
97
- | 共享视图状态的 selector hook 与 mutation callback | 注册项的 `store` | `PropsStore<H>` |
98
- | 私有数据、callback 与 observable hook | 注册项的 `inject` factory | `InjectFace<I>` |
99
- | 本地化 `t` 函数 | 注册项的 `locale` namespace | `PropsLocale<N>` |
100
- | chain 选中的值 | 注册项的 `select` 结果 | 通过 `ComposedProps` 提供的 `matched` |
101
- | 被包裹的 owner 内容 | `SlotMap` 条目的 `hoc` kind | 通过 `ComposedProps` 提供的 `children` |
102
-
103
- 当 entry 声明 `session` 或 `session-maybe` child 时,`PropsRenderSlots` 还会提供 `SessionProvider`。不传 `session` prop 时,它继承外围 binding;显式传入 `SessionReference` 或 `undefined` 时,只覆盖该子树。Provider 不为整个 body 设置 key。严格 `session` entry 在 binding generation 改变时重新挂载。空白 `session-maybe` entry 接受首个 binding 时不重新挂载,后续 generation 变化或回到缺失状态时才重新挂载。
104
-
105
- 组件绝不会收到 `ctx`。父组件在某次渲染时已经知道的值通过 `renderSlot` 的 owner 参数进入;共享视图状态使用声明的 store;service 与 model object 留在 `apply` closure 中,只向组件投影 callback 或 observable source。
106
-
107
- ## 框架提供的 hooks
108
-
109
- 当前组合中的 adapter 会添加以下标准 props。它们按目标 slot 的 scope 提供,与注册组件来自哪个包无关。
110
-
111
- | 可用范围 | Props | Owner |
112
- |---|---|---|
113
- | 所有 scope | `useSessions`、`useSessionStatus`、`useSessionRetainInfo`、`useSessionAccess` | `ui-session` |
114
- | 所有 scope | `useWorkspaces`、`useWorkspaceAccess` | `ui-workspace` |
115
- | 所有 scope | `useRemoteAccess`(`global` 资源) | `api-remote-access` |
116
- | 所有作用域 | `usePanelInfo` | `ui-layout` |
117
- | `session` | `sessionId`、`useSession`、`useProjection`、`useAccess`(所绑定 Session 的答案) | `ui-session` |
118
- | `session-maybe` | 结果可选的 `sessionId`、`useSession`、`useProjection`、`useAccess` | `ui-session` |
119
- | `session` | `useConversation`、`useInput`、`inputActions` | `ui-conversation` |
120
- | `session-maybe` | 结果可选的 `useConversation`、`useInput`、`inputActions` | `ui-conversation` |
121
- | `session` | `useChat` | `ui-chat` |
122
- | `session` | `useTrajectory` | `ui-trajectory` |
123
-
124
- Renderer 还会根据声明的 store 创建 `useStore`,并根据声明的 locale namespace 创建 `t`。这些是由注册项推导的 props,不属于全局标准 props。
125
-
126
- 框架与领域 adapter owner 可以通过 `ctx.slots.provideRoot()` 或 `ctx.uiSession.provide()` 扩展标准集合,同时提供对应的 `GlobalStandardProps`、`SessionStandardProps` 或 `SessionMaybeStandardProps` 声明合并。普通功能组件不应自行创建 React hook prop,也不应为 entry 私有数据添加全局标准 prop。
127
-
128
- ## 开发者提供的 injection
129
-
130
- 注册项的 `inject` 选项是通常使用的功能私有注入点。它的 factory 在插件的 `apply` 世界中运行,可以闭包捕获已经注入的 Cordis service,并且只返回组件所需的数据与 callback。对于 `session` slot,它会收到 `sessionId`;对于 `session-maybe`,它收到 `sessionId | undefined`;声明 store 后,它还会收到该 store 绑定后的 actions。
131
-
132
- 返回值中保留的 `hooks` 对象接收裸 `getSnapshot`/`subscribe` source。Renderer 把 `hooks: { status }` 转换为组件 prop `useStatus(selector)`,并按 source identity 缓存绑定。组件不会收到 source 本身,也不直接调用 `useSyncExternalStore`。
133
-
134
- 当每个 occupant 都需要同一种能力时,slot owner 可以在 child 声明里放置 `inject` face。普通成员会原样交给所有 occupant;其 `hooks` 对象中的函数成员是 hook factory,它会收到 slot 的标准 props 与可选的逐次渲染 `hookContext`,再返回提供给 occupant 的受限 hook。`conversation.chat.node` 正是通过这种机制,为当前渲染的 node 提供 `useTurnData(key)`。
135
-
136
- 一次渲染时 owner 已知的值走 owner props;单个 entry 的 callback 与私有 observable 走注册项 `inject`;由 slot owner 控制、所有 occupant 共享的能力走 slot 级 `inject`;需要跨 entry 共享或跨重新挂载保留的可变视图状态走声明的 store。React node 通过 child slot 组合,不通过注入值传递。
137
-
138
- <a id="current-hierarchy"></a>
139
-
140
- ## Conversation 层级
141
-
142
- 下面的 Conversation 路径区分声明所有者与可复用 Factory 根,省略无关的外壳位置。条目拥有其声明的子 Slot;Factory 在其定义注册期间拥有子 Slot 声明。方括号标出默认 React 组件,普通 React 后代组件可以渲染其所有者的 Slot。Factory 调用指向独立的可复用定义,不是新的 Slot 声明。
143
-
144
- ```text
145
- root [AppFrame]
146
- └─ main[key=conversation] [ConversationPanel]
147
- └─ main.conversation [ConversationRoot / ConversationMainPanel]
148
- ├─ conversation.header [ConversationHeader]
149
- │ ├─ conversation.header.leading
150
- │ └─ conversation.session.header [ConversationSessionHeader]
151
- │ ├─ conversation.session.header.lineage
152
- │ ├─ conversation.session.header.actions
153
- │ ├─ conversation.session.header.utilities
154
- │ ├─ conversation.session.header.views.actions
155
- │ └─ conversation.session.header.corner
156
- └─ calls Factory: conversation.content
157
-
158
- Factory: conversation.content [ConversationContent]
159
- ├─ conversation.session [ConversationSession / DefaultConversationViews]
160
- │ └─ conversation.view
161
- │ ├─ id=chat [ChatView]
162
- │ │ ├─ conversation.chat.text-interaction [list]
163
- │ │ └─ conversation.chat.flow [ChatFlow]
164
- │ │ └─ conversation.chat.node [ChatNodeSeat dispatch]
165
- │ │ ├─ key=user [UserMessageNodeView]
166
- │ │ │ ├─ conversation.chat.user.before [chain]
167
- │ │ │ └─ calls Factory: conversation.chat.user.content
168
- │ │ ├─ key=steering [UserMessageNodeView]
169
- │ │ │ └─ calls Factory: conversation.chat.user.content
170
- │ │ ├─ key=assistant-step [AssistantNodeView / AssistantMarkdown]
171
- │ │ │ ├─ conversation.chat.message.images [MessageImages]
172
- │ │ │ └─ conversation.chat.reasoning.body [DefaultReasoningBody]
173
- │ │ │ └─ calls Factory: conversation.chat.reasoning.content
174
- │ │ ├─ key=tool-call [ToolCallTree]
175
- │ │ │ └─ tool.call.toolview
176
- │ │ │ └─ key=read_image [ReadImageRow / ToolRow]
177
- │ │ │ └─ tool.call.images [MessageImages]
178
- │ │ ├─ key=command-input [GoalCommandInputView]
179
- │ │ │ └─ calls Factory: conversation.user.text
180
- │ │ ├─ key=command [CommandNodeView]
181
- │ │ │ └─ conversation.chat.commandview
182
- │ │ └─ key=turn-tail [TurnTailNodeView]
183
- │ │ ├─ conversation.chat.turnTail
184
- │ │ └─ conversation.chat.assistant-actions
185
- │ └─ id=trajectory [TrajectoryView / TrajectoryTable]
186
- │ └─ conversation.trajectory.images [MessageImages]
187
- ├─ conversation.composer
188
- │ ├─ conversation.approval.detail
189
- │ └─ conversation.plan-review.actions
190
- ├─ conversation.composer.bar [InputBar]
191
- │ ├─ conversation.input.attachments
192
- │ ├─ conversation.input.permission
193
- │ ├─ conversation.input.plan
194
- │ ├─ conversation.input.model
195
- │ │ └─ conversation.input.model.label
196
- │ ├─ conversation.input.overlay
197
- │ ├─ conversation.composer.dock
198
- │ ├─ conversation.input.left
199
- │ └─ conversation.input.right
200
- ├─ conversation.input.dock
201
- │ └─ id=queue [QueueDock]
202
- │ └─ calls Factory: conversation.user.text
203
- ├─ conversation.hero.frame [hoc]
204
- │ └─ id=pixel-whale [PixelWhale]
205
- ├─ conversation.hero.brand.mark
206
- ├─ conversation.hero.workspace
207
- │ └─ conversation.hero.workspace.directoryFlow
208
- ├─ conversation.hero.agentPreset
209
- └─ conversation.hero.options
210
-
211
- Factory: conversation.chat.user.content [UserContent]
212
- ├─ conversation.chat.user.images [MessageImages]
213
- └─ calls Factory: conversation.user.text
214
-
215
- Factory: conversation.user.text [UserText]
216
- └─ conversation.user.text.node [keyed, inline]
217
-
218
- Factory: conversation.images.content [MessageImagesContent / ImageGallery]
219
- Factory: conversation.chat.reasoning.content [ReasoningContent / MarkdownText]
220
- ```
221
-
222
- 四个图片 Slot 默认均填入 `MessageImages`,由它携带调用者的图片引用和授权 loader 调用 `conversation.images.content`。用户与输出图片的替换互不影响。`conversation.user.text` Factory 由用户内容、Queue 和 Goal 共用;其 `inline: true` keyed Slot 使用 span 锚点及行内错误占位,而不是块级包装。
223
-
224
- 生成的 [Client inspect catalog](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/extensions/cordis-client-runner/src/client/slot-catalog.ts) 是包含所有外壳分支及每个 key 的完整参考,包含 cardinality、scope、owner props、标准 props、当前 occupant、声明 owner 与替换风险。运行中的动态包可以用 `cordis_inspect what:"client"` 查询实时树与某个精确 key;源码 catalog 由 `pnpm run gen-client-catalog` 根据 `SlotMap` 声明和 `slots.register()` 调用点生成。
225
-
226
- <a id="extension-rules"></a>
227
-
228
- ## 扩展规则
229
-
230
- - 另一个功能包只能通过 `import type` 引入声明;绝不导入或转发它的运行时值。
231
- - 只在拥有并渲染某个位置的组件中声明新的 child slot。其他包通过 `ctx.slots.inject()` 等待,再通过 `ctx.slots.register()` 贡献内容。
232
- - 业务与传输状态留在所属 Cordis service 或 Client model 中。Slot store 只承载共享的视图与交互状态。
233
- - 可观测 source 及其 snapshot identity 在值变化前保持稳定;值变化时通过同一个 source 发布。
234
- - UI domain 之间只传 JSON 兼容数据和 callback。`hooks` compartment 是裸 observable 的唯一例外;React 内容通过 slot 传递。
235
- - 将 `single` 和已有 occupant 的 keyed cell 视为替换点。增量扩展使用新的 list 或 hoc id,或尚未占用的 key。
1
+ ---
2
+ editSource: "docs/subsystems/slots.zh.md"
3
+ rawMarkdownPath: "reference/subsystems/slots.md"
4
+ outline: [2,3]
5
+ ---
6
+
7
+ # Web Client Slots
8
+
9
+ Slots 是 Web Client 的类型化 React 组合系统。[`dsh-client-ui-slots`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-slots/README.zh.md)定义不依赖 React 的注册表与类型代数;[`dsh-client-ui-renderer`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-renderer/README.zh.md)把可观测源绑定成钩子、渲染整棵树,并在内部拥有 React context。功能插件通过 `ctx.slots.register()` 贡献 UI,绝不导入其他功能插件的组件。
10
+
11
+ 本文记录 slot 的所有权、组件输入、扩展 API 与当前层级。外围的启动、Remote、Client model 与 Conversation 数据通路见 [Web Client 架构](./web-client.md)。
12
+
13
+ `plugins.bundle.config` 以 npm 包名为 key,提供 Bundle 详情配置。`plugins.bundle.activation` 在用户显式启用后渲染可选引导,由拥有者提供关闭引导和打开该 Bundle 详情的回调。`conversation.input.activity` 提供模型选择器与发送按钮之间的单个活动控件,可展开工具栏并在卸载时释放展开状态。
14
+
15
+ 插件目录声明 `plugins.add.actions`,它是 root 作用域的 list,在添加插件菜单的安装项之后提供 `MenuItemButton` 行。owner 提供 `onDismiss()`,用于开始动作前关闭菜单。该 slot 遵循所属插件页面声明的生命周期。
16
+
17
+ root 作用域的 list `sidebar.panellist.actions`、`conversation.session.header.views.actions` 和 `sidebar.right.tab.guide.actions` 提供面板行、View 标签和右侧栏引导卡片之后“更多”菜单的菜单行。区域只在其 list 有注册项时画“更多”按钮与菜单,并传入可自定义的入口及其 Pin 状态、`onOpen`、`onPinnedChange` 与 `onDismiss`。面板和 View 入口还通过可选的 `active` 状态标识当前选中项,该状态独立于 Pin 状态。root 作用域的 `sidebar.panel.icon` factory 拥有 `sidebar.panellist` list,按 `id`、`size` 与 `active` 为侧栏行和更多菜单入口渲染已注册图标。各区域在内存中维护已收起的入口 id;[`ui-entry-customization`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-entry-customization/README.zh.md) 注册随产品提供的菜单行。
18
+
19
+ [ui-workspace](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-workspace/README.zh.md#understand-the-implementation) 记录 Session 行的扩展位置、显示条件和键盘行为。
20
+
21
+ [ui-settings](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-settings/README.zh.md#filling-the-settings-slots) 记录设置页面与导航图标扩展点。
22
+
23
+ ## 声明与生命周期
24
+
25
+ `SlotMap` 是编译期注册表。包通过声明合并写入 key、cardinality(基数)、scope、owner props、keyed props 与可选的 slot 级 inject face。运行时声明则是拥有该渲染位置的组件在 `children` 中给出的对应条目。
26
+
27
+ 声明一个 child 会同时产生三种效果:令该 child key 生效、授权 parent entry 调用 `renderSlot` 或 `renderSlotChain`,以及记录运行时 dispatch 规格。每个声明只能有一个存活 owner。向未声明 slot 注册,或重复声明其他 entry 已拥有的 child,都会在插件激活时失败。
28
+
29
+ `root` 是唯一内建声明,也是唯一由 Cordis service 自身渲染的 key。`ui-renderer` 调用 `ctx.slots.renderSlot('root', {})`;其余每个后代都通过声明它的 entry 所收到的 `renderSlot` 或 `renderSlotChain` prop 渲染。
30
+
31
+ 注册和声明遵循 Cordis effect 生命周期。销毁一个 entry 会移除其贡献,并递归折叠它声明的 child slots。因此,向其他包的 slot 贡献功能时使用 `ctx.slots.inject(key, callback)`:callback 会在每段声明生命周期内运行,owner 折叠时其 effect 随之移除,owner 再次挂载时则重新运行。
32
+
33
+ ```tsx ignore-check
34
+ import type { Context } from '@deepseek-ai/cordis'
35
+ import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
36
+ import type {} from '@deepseek-ai/dsh-client-ui-session/client'
37
+ import type { PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
38
+
39
+ type HeaderActionProps = PropsRuntime<'conversation.session.header.actions'>
40
+
41
+ function HeaderAction({ useSession }: HeaderActionProps) {
42
+ const running = useSession(snapshot => snapshot.running)
43
+ return <button disabled={running}>Review</button>
44
+ }
45
+
46
+ export const inject = ['slots']
47
+
48
+ export function apply(ctx: Context): void {
49
+ ctx.slots.inject('conversation.session.header.actions', () =>
50
+ ctx.slots.register({
51
+ name: 'conversation.session.header.actions',
52
+ id: 'review',
53
+ order: 100,
54
+ }, HeaderAction))
55
+ }
56
+ ```
57
+
58
+ ## Cardinality 与 scope
59
+
60
+ Slot 声明固定两个相互独立的维度。
61
+
62
+ | 维度 | 值 | 含义 |
63
+ |---|---|---|
64
+ | cardinality | `single` | 单个 cell,渲染当前 priority 胜者;需要并列内容时应声明 child slot,而不是把它当作列表。 |
65
+ | cardinality | `list` | cell 由必填 `id` 定址,先按 `order`、再按注册顺序排列。 |
66
+ | cardinality | `keyed` | owner 传入 `entryKey`;匹配 cell 以该 key 对应的 props 渲染。 |
67
+ | cardinality | `chain` | 每个 entry 提供纯 `select(owner)` 函数;按 priority 顺序遇到的第一个非 null 结果获选,并以 `matched` 传给组件;全部拒绝时渲染 owner fallback。 |
68
+ | cardinality | `hoc` | entry 层层包裹 owner 经 `renderSlot(key, owner, { children })` 传入的内容,最小者在最外层;可选的 `key` 按 owner 的 `entryKey` 选层。见 [Hoc 层](#hoc-layers)。 |
69
+ | scope | `root` | 一个 root 作用域组件和 store 实例。 |
70
+ | scope | `session-maybe` | 继承外围 Provider binding,但没有 binding 时仍可渲染;Session 值是可选的。 |
71
+ | scope | `session` | 要求可解析的外围 Provider binding,并收到确定存在的 Session 值。 |
72
+
73
+ 对于 `single`、`list`、`keyed` 和 `hoc` cell,`priority` 是遮蔽优先级;对于 `chain`,它是选举顺序。数值越小越先运行或渲染。普通增量贡献应选用新的 list 或 hoc `id`,或 keyed `key`;复用已有 cell 表示有意替换其展示。
74
+
75
+ <a id="hoc-layers"></a>
76
+
77
+ ### Hoc 层
78
+
79
+ hoc entry 是以必填 `id` 和可选 `key` 寻址的一层。不带 `key` 的层是通配层,作用于每次分派;带 `key` 的层只在 owner 向 `renderSlot` 传入相同 `entryKey` 时生效,省略 `entryKey` 的 owner 只得到通配层。每个 `(key, id)` 组合(通配视为单独的 key)是一个遮蔽 cell;同一 `id` 下,精确 key 的层替换该 key 的通配层。
80
+
81
+ 各层依次按 `order`、`priority`、注册顺序升序嵌套,最小者在最外层。每层收到同一份 owner props,并以 `children` 收到内一层(最内层是 owner 的内容),且至多渲染一次;不渲染 `children` 的层替换其内部的全部内容。owner props 不得使用 `children` 这个名字。省略 `children` 时各层包裹空内容;没有适用的层时原样渲染内容。
82
+
83
+ - 重新挂载:增减一个适用于本次分派的层会让其内部内容重新挂载;`session` 或 `session-maybe` 作用域的层在 Session binding 变化时也会让内部内容重新挂载。分派同一 key 的 outlet 共享一条编译好的层链,因此为其他 key 注册的层不会让它们的内容重新挂载;outlet 切换 `entryKey` 时会换到另一条层链,即使生效的层相同,内容也会重新挂载。
84
+ - 错误:崩溃的层照常上报错误,并在出错的那一处渲染它的 `children`,直到该处本次挂载结束,owner props 变化也不恢复。该层保持注册,因此其他出现处(包括分派同一 key 的出现处)仍保留它,重新挂载的出现处会再次渲染它。被包裹内容抛出的错误穿过所有层,不记到任何层名下;层如果自己在 `children` 外包错误边界,捕获到的是内部包装错误而不是原始错误。
85
+ - 布局:outlet 会在 owner 与内容之间插入一个 `display: contents` 的 `[data-slot]` 元素,所以 owner 侧的选择器不能假定内容是直接子元素。包裹 `children` 的层自身不得产生盒子(其 slot 另有说明的除外)——例如应使用 `display: contents`——否则内容会脱离父元素的布局。
86
+
87
+ <a id="component-inputs"></a>
88
+
89
+ [右键菜单插件](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-context-menu/README.zh.md) 通过 `provideRoot` 贡献 `useContextMenu`;每个作用域接收同一个由插件拥有的触发器工厂。提供方卸载时,注入属性与保留的处理器一并失效。其根作用域 keyed Slot `contextMenu.icon` 根据操作元数据渲染业务方提供的图标。
90
+
91
+ ## 组件输入
92
+
93
+ 注册组件会在 binding 位置收到组装后的输入。组件应从这些类型推导 props,不要重新抄写成员。
94
+
95
+ | 输入 | 声明者 | 组件类型 |
96
+ |---|---|---|
97
+ | owner 值与标准 scope 值 | `SlotMap` 条目与已安装的 scope adapter | `PropsRuntime<K>` |
98
+ | 获授权的 child renderer | 注册项的 `children` keys | `PropsRenderSlots<S>` |
99
+ | 共享视图状态的 selector hook 与 mutation callback | 注册项的 `store` | `PropsStore<H>` |
100
+ | 私有数据、callback 与 observable hook | 注册项的 `inject` factory | `InjectFace<I>` |
101
+ | 本地化 `t` 函数 | 注册项的 `locale` namespace | `PropsLocale<N>` |
102
+ | chain 选中的值 | 注册项的 `select` 结果 | 通过 `ComposedProps` 提供的 `matched` |
103
+ | 被包裹的 owner 内容 | `SlotMap` 条目的 `hoc` kind | 通过 `ComposedProps` 提供的 `children` |
104
+
105
+ 当 entry 声明 `session` 或 `session-maybe` child 时,`PropsRenderSlots` 还会提供 `SessionProvider`。不传 `session` prop 时,它继承外围 binding;显式传入 `SessionReference` 或 `undefined` 时,只覆盖该子树。Provider 不为整个 body 设置 key。严格 `session` entry 在 binding generation 改变时重新挂载。空白 `session-maybe` entry 接受首个 binding 时不重新挂载,后续 generation 变化或回到缺失状态时才重新挂载。
106
+
107
+ 组件绝不会收到 `ctx`。父组件在某次渲染时已经知道的值通过 `renderSlot` 的 owner 参数进入;共享视图状态使用声明的 store;service 与 model object 留在 `apply` closure 中,只向组件投影 callback 或 observable source。
108
+
109
+ ## 框架提供的 hooks
110
+
111
+ 当前组合中的 adapter 会添加以下标准 props。它们按目标 slot 的 scope 提供,与注册组件来自哪个包无关。
112
+
113
+ | 可用范围 | Props | Owner |
114
+ |---|---|---|
115
+ | 所有 scope | `useSessions`、`useSessionRetainInfo`、`useSessionAccess` | `ui-session` |
116
+ | 所有 scope | `useSessionStatus` | `ui-session-status` |
117
+ | 所有 scope | `useWorkspaces`、`useWorkspaceAccess` | `ui-workspace` |
118
+ | 所有 scope | `useRemoteAccess`(`global` 资源) | `api-remote-access` |
119
+ | 所有作用域 | `usePanelInfo` | `ui-layout` |
120
+ | `session` | `sessionId`、`useSession`、`useProjection`、`useAccess`(所绑定 Session 的答案) | `ui-session` |
121
+ | `session-maybe` | 结果可选的 `sessionId`、`useSession`、`useProjection`、`useAccess` | `ui-session` |
122
+ | `session` | `useConversation`、`useInput`、`inputActions` | `ui-conversation` |
123
+ | `session-maybe` | 结果可选的 `useConversation`、`useInput`、`inputActions` | `ui-conversation` |
124
+ | `session` | `useChat` | `ui-chat` |
125
+ | `session` | `useTrajectory` | `ui-trajectory` |
126
+
127
+ Renderer 还会根据声明的 store 创建 `useStore`,并根据声明的 locale namespace 创建 `t`。这些是由注册项推导的 props,不属于全局标准 props。
128
+
129
+ 框架与领域 adapter owner 可以通过 `ctx.slots.provideRoot()` 或 `ctx.uiSession.provide()` 扩展标准集合,同时提供对应的 `GlobalStandardProps`、`SessionStandardProps` 或 `SessionMaybeStandardProps` 声明合并。普通功能组件不应自行创建 React hook prop,也不应为 entry 私有数据添加全局标准 prop。
130
+
131
+ ## 开发者提供的 injection
132
+
133
+ 注册项的 `inject` 选项是通常使用的功能私有注入点。它的 factory 在插件的 `apply` 世界中运行,可以闭包捕获已经注入的 Cordis service,并且只返回组件所需的数据与 callback。对于 `session` slot,它会收到 `sessionId`;对于 `session-maybe`,它收到 `sessionId | undefined`;声明 store 后,它还会收到该 store 绑定后的 actions。
134
+
135
+ 返回值中保留的 `hooks` 对象接收裸 `getSnapshot`/`subscribe` source。Renderer 把 `hooks: { status }` 转换为组件 prop `useStatus(selector)`,并按 source identity 缓存绑定。组件不会收到 source 本身,也不直接调用 `useSyncExternalStore`。
136
+
137
+ 当每个 occupant 都需要同一种能力时,slot owner 可以在 child 声明里放置 `inject` face。普通成员会原样交给所有 occupant;其 `hooks` 对象中的函数成员是 hook factory,它会收到 slot 的标准 props 与可选的逐次渲染 `hookContext`,再返回提供给 occupant 的受限 hook。`conversation.chat.node` 正是通过这种机制,为当前渲染的 node 提供 `useTurnData(key)`。
138
+
139
+ 一次渲染时 owner 已知的值走 owner props;单个 entry 的 callback 与私有 observable 走注册项 `inject`;由 slot owner 控制、所有 occupant 共享的能力走 slot 级 `inject`;需要跨 entry 共享或跨重新挂载保留的可变视图状态走声明的 store。React node 通过 child slot 组合,不通过注入值传递。
140
+
141
+ <a id="current-hierarchy"></a>
142
+
143
+ ## Conversation 层级
144
+
145
+ 下面的 Conversation 路径区分声明所有者与可复用 Factory 根,省略无关的外壳位置。条目拥有其声明的子 Slot;Factory 在其定义注册期间拥有子 Slot 声明。方括号标出默认 React 组件,普通 React 后代组件可以渲染其所有者的 Slot。Factory 调用指向独立的可复用定义,不是新的 Slot 声明。
146
+
147
+ ```text
148
+ root [AppFrame]
149
+ └─ main[key=conversation] [ConversationPanel]
150
+ └─ main.conversation [ConversationRoot / ConversationMainPanel]
151
+ ├─ conversation.header [ConversationHeader]
152
+ │ ├─ conversation.header.leading
153
+ │ └─ conversation.session.header [ConversationSessionHeader]
154
+ │ ├─ conversation.session.header.lineage
155
+ │ ├─ conversation.session.header.actions
156
+ │ ├─ conversation.session.header.utilities
157
+ │ ├─ conversation.session.header.views.actions
158
+ │ └─ conversation.session.header.corner
159
+ └─ calls Factory: conversation.content
160
+
161
+ Factory: conversation.content [ConversationContent]
162
+ ├─ conversation.session [ConversationSession / DefaultConversationViews]
163
+ │ └─ conversation.view
164
+ │ ├─ id=chat [ChatView]
165
+ │ │ ├─ conversation.chat.text-interaction [list]
166
+ │ │ ├─ conversation.chat.markdown.fence [hoc, keyed by fence language]
167
+ │ │ └─ conversation.chat.flow [ChatFlow]
168
+ │ │ └─ conversation.chat.node [ChatNodeSeat dispatch]
169
+ │ │ ├─ key=user [UserMessageNodeView]
170
+ │ │ │ ├─ conversation.chat.user.before [chain]
171
+ │ │ │ └─ calls Factory: conversation.chat.user.content
172
+ │ │ ├─ key=steering [UserMessageNodeView]
173
+ │ │ │ └─ calls Factory: conversation.chat.user.content
174
+ │ │ ├─ key=assistant-step [AssistantNodeView / AssistantMarkdown]
175
+ │ │ │ ├─ conversation.chat.message.images [MessageImages]
176
+ │ │ │ └─ conversation.chat.reasoning.body [DefaultReasoningBody]
177
+ │ │ │ └─ calls Factory: conversation.chat.reasoning.content
178
+ │ │ ├─ key=tool-call [ToolCallTree]
179
+ │ │ │ └─ tool.call.toolview
180
+ │ │ │ └─ key=read_image [ReadImageRow / ToolRow]
181
+ │ │ │ └─ tool.call.images [MessageImages]
182
+ │ │ ├─ key=command-input [GoalCommandInputView]
183
+ │ │ │ └─ calls Factory: conversation.user.text
184
+ │ │ ├─ key=command [CommandNodeView]
185
+ │ │ │ └─ conversation.chat.commandview
186
+ │ │ └─ key=turn-tail [TurnTailNodeView]
187
+ │ │ ├─ conversation.chat.turnTail
188
+ │ │ └─ conversation.chat.assistant-actions
189
+ │ └─ id=trajectory [TrajectoryView / TrajectoryTable]
190
+ │ └─ conversation.trajectory.images [MessageImages]
191
+ ├─ conversation.composer
192
+ │ ├─ conversation.approval.detail
193
+ │ └─ conversation.plan-review.actions
194
+ ├─ conversation.composer.bar [InputBar]
195
+ │ ├─ conversation.input.attachments
196
+ │ ├─ conversation.input.permission
197
+ │ ├─ conversation.input.plan
198
+ │ ├─ conversation.input.model
199
+ │ │ └─ conversation.input.model.label
200
+ │ ├─ conversation.input.overlay
201
+ │ ├─ conversation.composer.dock
202
+ │ ├─ conversation.input.left
203
+ │ └─ conversation.input.right
204
+ ├─ conversation.input.dock
205
+ │ └─ id=queue [QueueDock]
206
+ │ └─ calls Factory: conversation.user.text
207
+ ├─ conversation.hero.frame [hoc]
208
+ │ └─ id=pixel-whale [PixelWhale]
209
+ ├─ conversation.hero.brand.mark
210
+ ├─ conversation.hero.workspace
211
+ │ └─ conversation.hero.workspace.directoryFlow
212
+ ├─ conversation.hero.agentPreset
213
+ └─ conversation.hero.options
214
+
215
+ Factory: conversation.chat.user.content [UserContent]
216
+ ├─ conversation.chat.user.images [MessageImages]
217
+ └─ calls Factory: conversation.user.text
218
+
219
+ Factory: conversation.user.text [UserText]
220
+ └─ conversation.user.text.node [keyed, inline]
221
+
222
+ Factory: conversation.images.content [MessageImagesContent / ImageGallery]
223
+ Factory: conversation.chat.reasoning.content [ReasoningContent / MarkdownText]
224
+ ```
225
+
226
+ 四个图片 Slot 默认均填入 `MessageImages`,由它携带调用者的图片引用和授权 loader 调用 `conversation.images.content`。用户与输出图片的替换互不影响。`conversation.user.text` Factory 由用户内容、Queue 和 Goal 共用;其 `inline: true` keyed Slot 使用 span 锚点及行内错误占位,而不是块级包装。
227
+
228
+ 生成的 [Client inspect catalog](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/extensions/cordis-client-runner/src/client/slot-catalog.ts) 是包含所有外壳分支及每个 key 的完整参考,包含 cardinality、scope、owner props、标准 props、当前 occupant、声明 owner 与替换风险。运行中的动态包可以用 `cordis_inspect what:"client"` 查询实时树与某个精确 key;源码 catalog 由 `pnpm run gen-client-catalog` 根据 `SlotMap` 声明和 `slots.register()` 调用点生成。
229
+
230
+ <a id="extension-rules"></a>
231
+
232
+ ## 扩展规则
233
+
234
+ - 另一个功能包只能通过 `import type` 引入声明;绝不导入或转发它的运行时值。
235
+ - 只在拥有并渲染某个位置的组件中声明新的 child slot。其他包通过 `ctx.slots.inject()` 等待,再通过 `ctx.slots.register()` 贡献内容。
236
+ - 业务与传输状态留在所属 Cordis service 或 Client model 中。Slot store 只承载共享的视图与交互状态。
237
+ - 可观测 source 及其 snapshot identity 在值变化前保持稳定;值变化时通过同一个 source 发布。
238
+ - UI domain 之间只传 JSON 兼容数据和 callback。`hooks` compartment 是裸 observable 的唯一例外;React 内容通过 slot 传递。
239
+ - 将 `single` 和已有 occupant 的 keyed cell 视为替换点。增量扩展使用新的 list 或 hoc id,或尚未占用的 key。