@deepseek-harness-tui/dsh-tui 0.15.0 → 0.16.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 (301) hide show
  1. package/README.md +92 -5
  2. package/guide/dsh-tui-guide/codex-backend.en.md +13 -3
  3. package/guide/dsh-tui-guide/codex-backend.md +9 -2
  4. package/guide/dsh-tui-guide/configuration.en.md +39 -2
  5. package/guide/dsh-tui-guide/configuration.md +34 -2
  6. package/guide/dsh-tui-guide/getting-started.en.md +15 -0
  7. package/guide/dsh-tui-guide/getting-started.md +15 -0
  8. package/guide/dsh-tui-guide/interaction.en.md +8 -1
  9. package/guide/dsh-tui-guide/interaction.md +8 -1
  10. package/guide/dsh-tui-guide/plugins.en.md +66 -5
  11. package/guide/dsh-tui-guide/plugins.md +37 -3
  12. package/guide/dsh-tui-guide/user-guide.en.md +3 -2
  13. package/guide/dsh-tui-guide/user-guide.md +3 -2
  14. package/lib/settings.json +1 -1
  15. package/lib/types/adapter/channel/projection.d.ts.map +1 -1
  16. package/lib/types/adapter/channel/projection.js +1 -0
  17. package/lib/types/adapter/channel/ui-policy.d.ts +1 -1
  18. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  19. package/lib/types/adapter/channel/ui-policy.js +1 -0
  20. package/lib/types/adapter/ports/channel-catalog.d.ts +5 -1
  21. package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
  22. package/lib/types/adapter/ports/channel-settings.d.ts +5 -3
  23. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  24. package/lib/types/adapter/ports/channel-ui.d.ts +7 -1
  25. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  26. package/lib/types/adapter/ports/channel-view.d.ts +47 -0
  27. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  28. package/lib/types/adapter/ports/channel.d.ts +2 -0
  29. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  30. package/lib/types/agent/events.d.ts +3 -2
  31. package/lib/types/agent/events.d.ts.map +1 -1
  32. package/lib/types/backends/codex/contract.d.ts +3 -0
  33. package/lib/types/backends/codex/contract.d.ts.map +1 -1
  34. package/lib/types/backends/codex/contract.js +3 -0
  35. package/lib/types/backends/codex/session/async-questions.d.ts +17 -0
  36. package/lib/types/backends/codex/session/async-questions.d.ts.map +1 -0
  37. package/lib/types/backends/codex/session/async-questions.js +89 -0
  38. package/lib/types/backends/codex/session/session.d.ts.map +1 -1
  39. package/lib/types/backends/codex/session/session.js +35 -9
  40. package/lib/types/backends/codex/text.d.ts +3 -3
  41. package/lib/types/backends/codex/text.js +1 -1
  42. package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
  43. package/lib/types/backends/codex/translate/items.js +3 -1
  44. package/lib/types/backends/codex/translate/question-reply.d.ts +11 -0
  45. package/lib/types/backends/codex/translate/question-reply.d.ts.map +1 -0
  46. package/lib/types/backends/codex/translate/question-reply.js +53 -0
  47. package/lib/types/channel/projection.d.ts.map +1 -1
  48. package/lib/types/channel/projection.js +10 -0
  49. package/lib/types/commands.d.ts +10 -0
  50. package/lib/types/commands.d.ts.map +1 -1
  51. package/lib/types/commands.js +11 -2
  52. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  53. package/lib/types/components/CommandSuggestions.js +4 -1
  54. package/lib/types/components/LogoV2.d.ts +4 -1
  55. package/lib/types/components/LogoV2.d.ts.map +1 -1
  56. package/lib/types/components/LogoV2.js +5 -3
  57. package/lib/types/components/MessageList.d.ts.map +1 -1
  58. package/lib/types/components/MessageList.js +95 -14
  59. package/lib/types/components/PermissionsPicker.d.ts +10 -1
  60. package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
  61. package/lib/types/components/PermissionsPicker.js +24 -16
  62. package/lib/types/components/PluginInstallPane.d.ts +21 -0
  63. package/lib/types/components/PluginInstallPane.d.ts.map +1 -0
  64. package/lib/types/components/PluginInstallPane.js +84 -0
  65. package/lib/types/components/PluginManagePane.d.ts +21 -0
  66. package/lib/types/components/PluginManagePane.d.ts.map +1 -0
  67. package/lib/types/components/PluginManagePane.js +69 -0
  68. package/lib/types/components/PromptInput.d.ts.map +1 -1
  69. package/lib/types/components/PromptInput.js +7 -3
  70. package/lib/types/components/SubagentCard.d.ts +13 -1
  71. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  72. package/lib/types/components/SubagentCard.js +27 -12
  73. package/lib/types/components/SubagentDashboard.d.ts +8 -1
  74. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  75. package/lib/types/components/SubagentDashboard.js +58 -16
  76. package/lib/types/components/launchpadLayout.d.ts +14 -1
  77. package/lib/types/components/launchpadLayout.d.ts.map +1 -1
  78. package/lib/types/components/launchpadLayout.js +36 -17
  79. package/lib/types/components/messages/TeamMessageBubble.d.ts +20 -0
  80. package/lib/types/components/messages/TeamMessageBubble.d.ts.map +1 -0
  81. package/lib/types/components/messages/TeamMessageBubble.js +15 -0
  82. package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -1
  83. package/lib/types/components/sidePanel/PanelHost.js +5 -1
  84. package/lib/types/components/sidePanel/PanelStore.d.ts +8 -0
  85. package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
  86. package/lib/types/components/sidePanel/PanelStore.js +11 -0
  87. package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
  88. package/lib/types/components/sidePanel/SidePanelColumn.js +13 -1
  89. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +7 -0
  90. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -1
  91. package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +4 -0
  92. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +3 -0
  93. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
  94. package/lib/types/components/sidePanel/btw/BtwComposer.js +20 -8
  95. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +2 -1
  96. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -1
  97. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +104 -13
  98. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +6 -2
  99. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -1
  100. package/lib/types/components/sidePanel/btw/BtwThreadScene.js +61 -15
  101. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +14 -4
  102. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
  103. package/lib/types/components/sidePanel/btw/BtwThreadView.js +90 -5
  104. package/lib/types/components/sidePanel/btw/threads.d.ts +18 -0
  105. package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -1
  106. package/lib/types/components/sidePanel/btw/threads.js +51 -0
  107. package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
  108. package/lib/types/components/sidePanel/builtinPanels.js +5 -1
  109. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +5 -1
  110. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -1
  111. package/lib/types/components/sidePanel/companion/SplashMascot.js +19 -4
  112. package/lib/types/components/sidePanel/companion/skins.d.ts +8 -0
  113. package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
  114. package/lib/types/components/sidePanel/companion/skins.js +57 -12
  115. package/lib/types/components/sidePanel/types.d.ts +6 -0
  116. package/lib/types/components/sidePanel/types.d.ts.map +1 -1
  117. package/lib/types/components/splashArtRows.d.ts +29 -0
  118. package/lib/types/components/splashArtRows.d.ts.map +1 -0
  119. package/lib/types/components/splashArtRows.js +31 -0
  120. package/lib/types/components/teamRoster.d.ts +70 -0
  121. package/lib/types/components/teamRoster.d.ts.map +1 -0
  122. package/lib/types/components/teamRoster.js +78 -0
  123. package/lib/types/dsh-adapter/admission-loader.d.ts +82 -0
  124. package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/admission-loader.js +73 -28
  126. package/lib/types/dsh-adapter/agent-view.d.ts.map +1 -1
  127. package/lib/types/dsh-adapter/agent-view.js +3 -1
  128. package/lib/types/dsh-adapter/approvals.d.ts +7 -0
  129. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  130. package/lib/types/dsh-adapter/approvals.js +45 -1
  131. package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/backend/translate.js +68 -8
  133. package/lib/types/dsh-adapter/backend-assembly.d.ts +31 -0
  134. package/lib/types/dsh-adapter/backend-assembly.d.ts.map +1 -0
  135. package/lib/types/dsh-adapter/backend-assembly.js +225 -0
  136. package/lib/types/dsh-adapter/backend-contribution.d.ts +36 -0
  137. package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/backend-contribution.js +41 -0
  139. package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/backend-registry.js +22 -3
  141. package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
  142. package/lib/types/dsh-adapter/backends.js +4 -5
  143. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  144. package/lib/types/dsh-adapter/bundled-presets.js +60 -3
  145. package/lib/types/dsh-adapter/channel/binding-events.d.ts +1 -0
  146. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  147. package/lib/types/dsh-adapter/channel/binding-events.js +1 -0
  148. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  149. package/lib/types/dsh-adapter/channel/command-completions.js +64 -7
  150. package/lib/types/dsh-adapter/channel/compaction.d.ts +7 -2
  151. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  152. package/lib/types/dsh-adapter/channel/compaction.js +100 -26
  153. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +3 -0
  154. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
  155. package/lib/types/dsh-adapter/channel/core/binding-feed.js +2 -1
  156. package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
  157. package/lib/types/dsh-adapter/channel/core/compose.js +12 -0
  158. package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/extensions.js +68 -8
  160. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +6 -0
  161. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +104 -12
  163. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  164. package/lib/types/dsh-adapter/channel/model-actions.js +8 -1
  165. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  166. package/lib/types/dsh-adapter/channel/permissions.js +4 -1
  167. package/lib/types/dsh-adapter/channel/projection-helpers.d.ts.map +1 -1
  168. package/lib/types/dsh-adapter/channel/projection-helpers.js +2 -0
  169. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  170. package/lib/types/dsh-adapter/channel/session-metadata.js +4 -3
  171. package/lib/types/dsh-adapter/channel/session-reset.js +2 -2
  172. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  173. package/lib/types/dsh-adapter/channel/session-resume.js +7 -0
  174. package/lib/types/dsh-adapter/channel/settings-host.d.ts +3 -0
  175. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  176. package/lib/types/dsh-adapter/channel/settings-host.js +135 -5
  177. package/lib/types/dsh-adapter/channel/state.d.ts +6 -0
  178. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  180. package/lib/types/dsh-adapter/channel/subagent-projection.js +18 -6
  181. package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -0
  182. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  183. package/lib/types/dsh-adapter/channel/transcript.js +19 -2
  184. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts +55 -0
  185. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts.map +1 -0
  186. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.js +96 -0
  187. package/lib/types/dsh-adapter/contract.d.ts +4 -4
  188. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  189. package/lib/types/dsh-adapter/contract.js +5 -5
  190. package/lib/types/dsh-adapter/effect-ledger.d.ts +7 -0
  191. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  192. package/lib/types/dsh-adapter/effect-ledger.js +8 -1
  193. package/lib/types/dsh-adapter/entry-slot.d.ts +3 -1
  194. package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -1
  195. package/lib/types/dsh-adapter/entry-slot.js +2 -2
  196. package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -1
  197. package/lib/types/dsh-adapter/fresh-agent.js +6 -1
  198. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
  199. package/lib/types/dsh-adapter/host-access.js +95 -0
  200. package/lib/types/dsh-adapter/host-contract.d.ts +1 -1
  201. package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -1
  202. package/lib/types/dsh-adapter/host-contract.js +3 -2
  203. package/lib/types/dsh-adapter/host-dsh.d.ts +8 -2
  204. package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/host-dsh.js +45 -30
  206. package/lib/types/dsh-adapter/host-entry.js +35 -10
  207. package/lib/types/dsh-adapter/index.d.ts +9 -10
  208. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  209. package/lib/types/dsh-adapter/index.js +8 -6
  210. package/lib/types/dsh-adapter/invariant.d.ts +7 -2
  211. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -1
  212. package/lib/types/dsh-adapter/invariant.js +6 -3
  213. package/lib/types/dsh-adapter/migrate/index.js +2 -2
  214. package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
  215. package/lib/types/dsh-adapter/panels.js +6 -0
  216. package/lib/types/dsh-adapter/plugin-declaration.d.ts +99 -1
  217. package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -1
  218. package/lib/types/dsh-adapter/plugin-declaration.js +132 -2
  219. package/lib/types/dsh-adapter/plugin-feed.d.ts +94 -0
  220. package/lib/types/dsh-adapter/plugin-feed.d.ts.map +1 -0
  221. package/lib/types/dsh-adapter/plugin-feed.js +135 -0
  222. package/lib/types/dsh-adapter/plugin-guard.d.ts +115 -0
  223. package/lib/types/dsh-adapter/plugin-guard.d.ts.map +1 -0
  224. package/lib/types/dsh-adapter/plugin-guard.js +108 -0
  225. package/lib/types/dsh-adapter/plugin-install.d.ts +160 -0
  226. package/lib/types/dsh-adapter/plugin-install.d.ts.map +1 -0
  227. package/lib/types/dsh-adapter/plugin-install.js +545 -0
  228. package/lib/types/dsh-adapter/plugin-manage.d.ts +178 -0
  229. package/lib/types/dsh-adapter/plugin-manage.d.ts.map +1 -0
  230. package/lib/types/dsh-adapter/plugin-manage.js +468 -0
  231. package/lib/types/dsh-adapter/plugin-manager.d.ts +78 -2
  232. package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -1
  233. package/lib/types/dsh-adapter/plugin-manager.js +32 -0
  234. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  235. package/lib/types/dsh-adapter/plugin.js +49 -2
  236. package/lib/types/dsh-adapter/plugins-info.d.ts +87 -1
  237. package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
  238. package/lib/types/dsh-adapter/plugins-info.js +131 -26
  239. package/lib/types/dsh-adapter/process-exit.d.ts +1 -1
  240. package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -1
  241. package/lib/types/dsh-adapter/process-exit.js +1 -1
  242. package/lib/types/dsh-adapter/session-projection-store.d.ts +66 -0
  243. package/lib/types/dsh-adapter/session-projection-store.d.ts.map +1 -0
  244. package/lib/types/dsh-adapter/session-projection-store.js +149 -0
  245. package/lib/types/dsh-adapter/settingsEditor.js +2 -2
  246. package/lib/types/dsh-adapter/sideQuestion.d.ts +21 -0
  247. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  248. package/lib/types/dsh-adapter/sideQuestion.js +53 -0
  249. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  250. package/lib/types/dsh-adapter/subagents.js +2 -1
  251. package/lib/types/dsh-adapter/team-mode.d.ts +74 -0
  252. package/lib/types/dsh-adapter/team-mode.d.ts.map +1 -0
  253. package/lib/types/dsh-adapter/team-mode.js +188 -0
  254. package/lib/types/dsh-adapter/team-roster.d.ts +67 -0
  255. package/lib/types/dsh-adapter/team-roster.d.ts.map +1 -0
  256. package/lib/types/dsh-adapter/team-roster.js +136 -0
  257. package/lib/types/dsh-adapter/team-tools.d.ts +58 -0
  258. package/lib/types/dsh-adapter/team-tools.d.ts.map +1 -0
  259. package/lib/types/dsh-adapter/team-tools.js +208 -0
  260. package/lib/types/dsh-adapter/types.d.ts +1 -1
  261. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  262. package/lib/types/i18n.d.ts +607 -16
  263. package/lib/types/i18n.d.ts.map +1 -1
  264. package/lib/types/i18n.js +295 -9
  265. package/lib/types/ink/components/ScrollBox.d.ts +9 -0
  266. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  267. package/lib/types/ink/components/ScrollBox.js +23 -0
  268. package/lib/types/ink/dom.d.ts.map +1 -1
  269. package/lib/types/kernelPrefs.d.ts +1 -1
  270. package/lib/types/kernelPrefs.d.ts.map +1 -1
  271. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  272. package/lib/types/native-ts/yoga-layout/index.js +8 -1
  273. package/lib/types/permissionPresetLabels.d.ts +25 -0
  274. package/lib/types/permissionPresetLabels.d.ts.map +1 -0
  275. package/lib/types/permissionPresetLabels.js +33 -0
  276. package/lib/types/preset-patch.d.ts +22 -0
  277. package/lib/types/preset-patch.d.ts.map +1 -0
  278. package/lib/types/preset-patch.js +14 -0
  279. package/lib/types/screens/Chat.d.ts +33 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +301 -9
  282. package/lib/types/screens/Launchpad.d.ts +7 -1
  283. package/lib/types/screens/Launchpad.d.ts.map +1 -1
  284. package/lib/types/screens/Launchpad.js +19 -4
  285. package/lib/types/screens/Settings.d.ts.map +1 -1
  286. package/lib/types/screens/Settings.js +1 -0
  287. package/lib/types/screens/chat/usePluginWriteFlow.d.ts +68 -0
  288. package/lib/types/screens/chat/usePluginWriteFlow.d.ts.map +1 -0
  289. package/lib/types/screens/chat/usePluginWriteFlow.js +92 -0
  290. package/lib/types/screens/chatOverlay.d.ts +19 -1
  291. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  292. package/lib/types/sessionModes.d.ts +5 -3
  293. package/lib/types/sessionModes.d.ts.map +1 -1
  294. package/lib/types/sessionModes.js +9 -3
  295. package/lib/types/tips.js +2 -2
  296. package/lib/types/utils/paths.d.ts +11 -0
  297. package/lib/types/utils/paths.d.ts.map +1 -1
  298. package/lib/types/utils/paths.js +13 -0
  299. package/package.json +126 -120
  300. package/tui-profile/feed/README.md +63 -0
  301. package/tui-profile/feed/first-party.json +10 -0
package/README.md CHANGED
@@ -27,7 +27,7 @@
27
27
  ## Highlights
28
28
 
29
29
  - **Pixel whale pet** — three startup intros, click to wake; freezes after the first task.
30
- - **Launchpad and first-run guide** — every ordinary launch lands on a landing page with a **real input box** (big text + whale + quick actions, dropping whole blocks on short/narrow terminals; on by default — /settings `launchpad` off boots straight into chat); command completion matches chat: `Tab` fills the input, `Enter` runs the command and clears it. The first run walks a four-step wizard (API key / language+theme / model+workspace / shortcuts), re-runnable with `/setup`.
30
+ - **Launchpad and first-run guide** — every ordinary launch lands on a landing page with a **real input box** (big text + whale + quick actions, dropping whole blocks on short/narrow terminals; whale-girl images use a compact native-canvas footprint instead of leaving a large gap before the title; on by default — /settings `launchpad` off boots straight into chat); command completion matches chat: `Tab` fills the input, `Enter` runs the command and clears it. The first run walks a four-step wizard (API key / language+theme / model+workspace / shortcuts), re-runnable with `/setup`.
31
31
  - **Terminal-native UI** — streaming Markdown, tool cards, `/` and `@` completion, `#L12-14` ranges, history search, zh/en UI.
32
32
  - **Task completion notifications** — DSH, Claude and Codex notify after successful live work settles, with no queued follow-up or active goal. The title is “dsh-TUI · Task complete”; the body shows the latest settled reply as a single-line plain-text preview (Markdown formatting removed, up to 200 characters). OSC 777/9 apply an additional 2048-byte sequence budget, including title and protocol bytes, preserving whole graphemes. No reply shows only the title; BEL only rings. `/settings` → Conversation: `taskNotifications` = `unfocused` (default), `always`, or `off`; `notificationMethod` = `auto` (default), `osc9`, or `bel`. Auto uses separate title/body fields on Ghostty/WezTerm (OSC 777) and Kitty (OSC 99); iTerm2/Warp and explicit `osc9` use a title prefix; other terminals ring the bell; delivery follows your terminal's notification/bell settings. tmux requires `set -g allow-passthrough on` for OSC notifications and `set -g focus-events on` for focus reporting. Terminals without focus reporting need `always`. Replay, cancellation and failures do not notify. Works in inline and fullscreen modes.
33
33
  - **Native cursor** — focused text inputs inherit your terminal's cursor shape, color, blinking, and enabled animation or trail effects in both inline and fullscreen modes. The `/model` picker shows the same cursor during movement between provider tabs, model rows, and effort levels, then hides it after **0.5 seconds at rest**; clipped regions fall back to the model row. The session manager also moves this cursor between the workspace rail, session rows, and search box; typing claims the search caret, and navigation returns it to the focused row. Configure animation and trail effects in your terminal.
@@ -98,10 +98,15 @@ The `deepseek-official` API-key route needs `DEEPSEEK_API_KEY`. On DSH
98
98
  and select the separate account route through `/model`. Other supported
99
99
  accounts can sign in through `/provider` or `/auth` after startup.
100
100
 
101
- The primary compatibility target is DSH `0.2.0-rc.2`. This adapter supports its
101
+ The primary compatibility target is DSH `0.2.1-rc.2`. This adapter supports its
102
102
  Shell API, V4 session messages, declarative presets, and profile-backed settings;
103
103
  older supported hosts retain their compatibility paths. See [configuration](docs/configuration.en.md).
104
104
 
105
+ On DSH rc.2, `/settings` also selects DeepSeek Search / Fetch APIs and edits their
106
+ endpoint and result limits, supporting custom Loader entry IDs and a masked API
107
+ key input saved through DSH's credential store. Official Flash model labels show the `1017` release
108
+ marker while retaining the `deepseek-flash` model ID.
109
+
105
110
  On DSH 0.1.7, `/settings` uses the TUI's actual Loader entry ID, including custom
106
111
  IDs. It requires matching profile dependencies with `@deepseek-ai/schemastery`
107
112
  3.18.3 or newer; an incompatible schema stops TUI startup with repair guidance
@@ -253,7 +258,9 @@ subscription credentials and `/channel` connections use private app-server proce
253
258
 
254
259
  Streaming/tool cards, approvals, questions, steer/queue/interrupt, model and
255
260
  effort controls, Plan, `/review`, `/diff`, `/usage`, `/init`, skills and MCP
256
- share the existing UI. **Shift+Tab only toggles Plan**, keeping its underlying
261
+ share the existing UI. Async questions open the questionnaire while Codex
262
+ continues working; answers steer the turn (or queue if unavailable), and
263
+ dismissing the question leaves work running. **Shift+Tab only toggles Plan**, keeping its underlying
257
264
  permission preset; Full Access requires an explicit choice. Existing Codex
258
265
  settings are respected, not overwritten with defaults. `/login` offers
259
266
  ChatGPT OAuth, a device code or an API key (the last writes to Codex’s own
@@ -270,7 +277,8 @@ start notice: Codex itself rejects every turn of that provider.
270
277
  TPS includes hidden reasoning time and excludes tool execution time. Live
271
278
  text estimates are corrected when Codex reports output token usage.
272
279
 
273
- Native browsing/archive, fork/conversation rewind, paged history, images,
280
+ Native browsing/archive, fork/conversation rewind (the first message requires
281
+ Codex app-server 0.160.1+), paged history, images,
274
282
  subagents, polled background terminals, goals and `/btw`/`/recap` use the
275
283
  existing surfaces. `/logout` removes only the matching dsh-auth credential;
276
284
  already-loaded managed tokens require a normal restart, not native logout.
@@ -282,6 +290,58 @@ Using ChatGPT subscription tokens in third-party clients is subject to
282
290
  OpenAI’s terms. Full instructions and current boundaries:
283
291
  [Codex backend](docs/codex-backend.en.md).
284
292
 
293
+ ### Experimental: DSH Agent Teams
294
+
295
+ DSH's experimental Agent Teams lets the session's agent (the Lead) create
296
+ named teammates that share the working directory, message each other and
297
+ coordinate on a shared task board. It is off by default. Install the
298
+ upstream bundle into the TUI profile once:
299
+
300
+ ```sh
301
+ dsh plugin --profile dsh-tui add @deepseek-ai/dsh-experimental-agent-team-profile@0.2.1-rc.2
302
+ ```
303
+
304
+ Then switch it with `/team on` / `/team off` (`/team` alone reports the
305
+ bundle, the service and this session's teammates). The switch enables or
306
+ disables the bundle in the profile, so it persists across restarts, and on a
307
+ `dsh --profile` launch it applies at once — running sessions included: the
308
+ model is told which tools came and went. Turning it off while teammates run
309
+ asks first, and switching off stops them: the team service releases the
310
+ teammates still running as it unloads. Inside a teammate session the other
311
+ teammates' runs are not visible, so the question counts them as possibly
312
+ running. The team record stays in the session for the next `/team on`.
313
+ `/plugin enable|disable` on the bundle does the same.
314
+
315
+ Pin the version to exactly your installed DSH version (the command above
316
+ uses the primary line `0.2.1-rc.2`; on DSH `0.2.1-alpha.5`, `0.2.0-rc.1` or
317
+ `0.2.0-rc.2` install `…-profile@` that same version). The team packages ship in lockstep with DSH and pin
318
+ their DSH peers exactly, so neither the untagged install nor `next` works.
319
+ When the package is missing, `/team on` prints the command with your
320
+ DSH version filled in on those lines (`0.2.1-rc.2` when the version cannot
321
+ be read); on any other DSH version it asks you to switch DSH to one of those lines first, since
322
+ no team bundle installs there.
323
+
324
+ While a request carries `spawn_teammate`, dsh-TUI drops `subagent` /
325
+ `subagent_fork` from it, and the team's `send_message` / `list_agents` /
326
+ `interrupt_agent` / `wait_agent` take the place of the legacy controls of the
327
+ same names, so `spawn_teammate` is the delegation tool; with the team off
328
+ the legacy tools are back. Subagents that are not team members (workflow,
329
+ ralph) keep `subagent`. A teammate shows up as a subagent row, a message between
330
+ members as a `✉ <sender>` bubble in the receiving session (a teammate's
331
+ received messages show on its subagent detail as agent messages), and the
332
+ other team tools as one-line cards (`send_message` with its target and
333
+ `sent`). The agents dashboard (Ctrl+A) and the agents side
334
+ panel switch to a team view: each teammate under its member name with
335
+ `running` / `idle` / `provisioning` / `failed` (a teammate whose turn ended
336
+ is idle — a message wakes it — not done), the Lead line, the remaining
337
+ subagents, a read-only task board (status, owner, `blocked`, write-scope
338
+ warnings) and a banner when the team record was rejected.
339
+
340
+ Limits: the switch covers the whole profile, not one session (a launch
341
+ without the profile plugin service, or without hot reload, needs `dsh plugin`
342
+ and a restart); there is no "enter teammate session" yet, and `/export` leaves team messages out. Upstream limits apply: teammates share one working directory, a
343
+ team lives in one process, and a task owner is never released automatically.
344
+
285
345
  ## Keybindings & Mouse
286
346
 
287
347
  `Enter` send · `Tab` complete · `Ctrl+Enter` interrupt and send · `Alt+Up` recall the last message · `Esc` dismiss, double-`Esc` rewinds · `Ctrl+B` side panel · `Ctrl+O` details · `Ctrl+R` history (`↑`/`↓` and `Ctrl+R` are scoped to the current project) · `Ctrl+V` paste · `Ctrl+Shift+E` fullscreen draft editor · `?` shortcuts · `←` open the session manager (DSH backgrounds the current session first).
@@ -400,8 +460,33 @@ questionnaire, or tool-card changes also need the matching regression scripts.
400
460
 
401
461
  Plugin development: [admission & development guide](tui-profile/docs/plugin-admission-and-development.md) · [plugin-template](https://github.com/dsh-tui-ecosystem/plugin-template) · [dsh-tui-ecosystem](https://github.com/dsh-tui-ecosystem). Reference implementation: `dsh-working-activity`.
402
462
 
463
+ Exported plugin subcomponents are admitted using the nearest package manifest of their ESM entry, including import-only and conditional exports; they do not inherit an outer package's identity.
464
+
465
+ A backend plugin (the `tui.dsh/v1alpha1` `Backend` contribution family) is in the kernel picker after a restart: the boot scans the bundles the profile declares, admits and registers each package-root `dsh-plugin.json` declaration, and reads the implementation from the package's `backend` export — importing that module only when the backend is actually selected.
466
+ Each bundle may declare one backend, and its handler id must match the declaration. Entries awaiting authorization are neither probed nor loaded, including when explicitly requested at startup.
467
+
403
468
  Seam grading and API notes: [Plugin development](docs/plugins.en.md). The organization maintains the listing only; it does not endorse community plugins.
404
469
 
470
+ Installing a plugin from inside the TUI: `/plugin install <package | path | git url>`. It goes through the host's profile plugin manager — a pre-install notice, a trust confirmation, cancellable progress, build-script approval and exact-version exemptions. Packages on the first-party feed this package ships (`tui-profile/feed/first-party.json`, pinned per release and decided offline) skip the trust confirmation, and only a spec that names that exact version qualifies: a bare name, a tag or a range is resolved again at install time, so it is confirmed with the person instead. What was confirmed is what gets installed — the run pins the exact `name@version` the inspection read — and a turn that is still running refuses the install (finish it, or `/new`, first). The same actions remain available from the CLI (`dsh plugin --profile dsh-tui …`).
471
+
472
+ A spec names one of three things:
473
+
474
+ ```sh
475
+ /plugin install /path/to/repo
476
+ /plugin install https://github.com/exam/ple.git
477
+ /plugin install @scope/package@1.2.3
478
+ ```
479
+
480
+ Typing `/plugin install ` lists these three shapes in the completion popup, and the same shapes follow the installed names on `/plugin info `. They are examples, never candidates: `Tab` leaves the draft exactly as it is, and `Enter` runs the line you typed — the subcommand's usage line while the spec is still empty, your own spec once it is not. No example can therefore be inserted or installed by accident, and a real path that merely starts like one is never swallowed.
481
+
482
+ During installation, `esc` attempts cancellation and keeps the pane open until the write settles; if cancellation is too late, it waits for the installation to finish. During exemption registration, it waits for the current write and stops subsequent grants and the retry. Exemptions already written remain.
483
+
484
+ Failed installs show up to six redacted log lines; lines larger than 16 KiB are omitted with a notice.
485
+
486
+ Managing what is installed: `/plugin remove <bundle>`, `/plugin enable <name | row id>` and `/plugin disable <name | row id>`. A bundle is a composition layer and a row is one patch entry, so the two are separate actions, and a bundle name is matched before any row identity. A module name shared by multiple rows requires a specific row ID. **Gate 2 refuses the three ways this app could switch itself off** — removing or disabling the bundle that provides it, the host layer `dsh-base`, or one of its own rows — and says which rule it broke, without calling the service at all; that holds whether or not hot reload is live, which is the path the host's own guard misses. `enable` is never refused by gate 2 (it is the repair action). Every enable and removal asks first; `disable` asks only about a host-layer row. The host does not attest installed package sources, so even an exact feed match requires confirmation before enabling.
487
+
488
+ These three actions have no cancellation — the service offers none — so `esc` only closes the pane while the write finishes and reports itself into the transcript. Enable and disable have no CLI verb either (the service writes them into the profile's own files), and a removal never deletes your own data: anything left under `~/.dsh-tui` is reported once and left for you to delete.
489
+
405
490
  ## Documentation
406
491
 
407
492
  - **Start** — [Getting started](docs/getting-started.en.md) · [VS Code](docs/vscode.en.md)
@@ -437,7 +522,9 @@ Everything, bilingual: [docs/README.md](docs/README.md).
437
522
 
438
523
  No sandbox of its own: dsh-TUI uses the active DSH profile's filesystem, shell, sandbox and approval policies. Permission presets come from the DSH `permissionPresets` registry.
439
524
 
440
- **Permission persistence** (all three backends): the Claude and Codex backends keep their `/permission` picks in `~/.dsh-tui/backends/<id>/prefs.json`; the DSH pick is kept at `~/.dsh-tui/permission.json`. Every durable preset switch teaches it (picker, typed `/permission`, Shift+Tab static modes, or a switch the official command performed on its own), and a session that never customized its permission planes starts on the remembered preset — applied through the same official switch path. "Never customized" is about the user: the composition writes its own default preset into every fresh session at creation, and those events do not count. Plan-mode transients are excluded, a `DSH_PERMISSION_MODE` launch pin (this run's initial permission plane) outranks the file, and an identity the mounted roster no longer offers is skipped.
525
+ **Permission persistence** (all three backends): the Claude and Codex backends keep their `/permission` picks in `~/.dsh-tui/backends/<id>/prefs.json`; the DSH pick is kept at `~/.dsh-tui/permission.json`. Every durable preset switch teaches it (picker, typed `/permission`, Shift+Tab static modes, or a switch the official command performed on its own), and a session that never customized its permission planes starts on the remembered preset — applied through the same official switch path. "Never customized" is about the user: the composition writes its own default preset into every fresh session at creation, and those events do not count. Plan-mode transients and the experimental Auto review preset (see below) are excluded, a `DSH_PERMISSION_MODE` launch pin (this run's initial permission plane) outranks the file, and an identity the mounted roster no longer offers is skipped.
526
+
527
+ **Auto review** (DSH, experimental): when the `dsh-experimental-auto-review` plugin is enabled, the `auto` preset (shown as "Auto review", tagged `EXP`) appears in `/permission` and its completions live, and disappears when the plugin is removed. It is session-only: the model reviews every tool call before it runs, there is no file sandbox, and each call costs one extra model request; its approval prompts show the localized reason, and a subagent denial reads "Auto review denied; not executed". Picking it in the picker first shows a risk confirmation (`Enter` enables, `Esc` goes back; in fullscreen its Enable / Go back rows are clickable); a typed `/permission auto` switches directly. Once the current session has selected it, the picker skips the confirmation and Shift+Tab stops skipping it.
441
528
 
442
529
  **Upstream auto-retry** (DSH): whenever a session binds (boot, `/model` switch, resume), the TUI seeds a retry policy — 5 attempts, transport-drop-aware failure codes including `STREAM_CLOSED` (a dropped upstream stream) — on **the provider route that session actually uses**, through the official `llm-pi-ai` settings section (the policy the kernel's `llm-retry` plugin executes). Only routes without an explicit `retryPolicy` are seeded — dormant channels are never written — and `upstreamRetry: false` in cordis.yml opts out.
443
530
 
@@ -184,13 +184,20 @@ changes during a turn apply to the next one, not to reasoning already in progres
184
184
  - Command, file, network and permission approvals use server-provided choices. Allow-once,
185
185
  session allowance or remembered rules appear only when supported. Questions and MCP forms
186
186
  share the existing panel, with secret answers masked.
187
+ - Codex's `request_user_input_async` opens the questionnaire while the agent continues
188
+ working. The first suggestion is selected by default; free text is also available.
189
+ Answers use the native question-reply envelope to steer, falling back to a queued
190
+ follow-up when steering is unavailable. Dismissal closes that question without
191
+ interrupting. Turn completion, connection loss and exit withdraw unanswered questions;
192
+ historical resume never reopens old questionnaires. Codex's persisted echo renders
193
+ as a quoted question and answer, including when rebuilding history.
187
194
 
188
195
  ## Daily commands and input
189
196
 
190
197
  | Entry | Behavior |
191
198
  | --- | --- |
192
199
  | `Enter` / `Tab` / `Ctrl+Enter` while working | Steer / queue a follow-up / interrupt and send now; non-steerable turns fall back to follow-up |
193
- | `Esc` / `Ctrl+C` | Dismiss the focused panel or interrupt. Cancelling a model question also interrupts its turn rather than leaving it hung |
200
+ | `Esc` / `Ctrl+C` | Dismiss the focused panel or interrupt. Cancelling a blocking question interrupts its turn; dismissing an async question only closes that question |
194
201
  | `/review` | Review uncommitted changes inline; requires idle state and consumes model usage |
195
202
  | `/review base <branch>` / `/review commit <sha>` | Review against a branch or commit; other arguments are custom review instructions |
196
203
  | `/diff` | Latest turn’s aggregated diff; otherwise try Git diff against the remote, then show an empty-state notice |
@@ -238,8 +245,11 @@ past tokens/cost. Fresh usage notifications update the readings.
238
245
  - `/rename` changes the official thread title; `/color` stores a session accent, not a global theme.
239
246
  - `/fork` creates a resumable copy without switching. Double `Esc` or `/rewind` conversation
240
247
  rewind creates a copy before the selected question, returns the question to the composer
241
- and preserves the original. Rewinding the first question creates an empty thread. **File-only
242
- and conversation+files rewind are unsupported**; the Git working tree does not revert.
248
+ and preserves the original. Rewinding the first question creates an empty, resumable fork.
249
+ First-question rewind, or rewind without a loaded predecessor, requires Codex app-server
250
+ **0.160.1+**, checked from the connection handshake. Older or unknown server versions
251
+ receive an explicit upgrade notice; rewind with a loaded predecessor keeps its existing path.
252
+ **File-only and conversation+files rewind are unsupported**; the Git working tree does not revert.
243
253
  - Resume replays the newest 20 full turns before live continuation. Load older messages uses
244
254
  prefetched full-item pages, not tool-omitting summaries. Retry when prefetch is still pending;
245
255
  repeated failure reports a notice. Active resume deduplicates redelivered approvals and
@@ -149,13 +149,17 @@ Chat Completions 端点当作 Responses 使用。通过 `/channel` 选择/新建
149
149
  的路径以新 thread 继续,原 thread 保留;批准计划不会暗中打开 Full Access。
150
150
  - 命令、文件改动、网络/权限请求由 Codex 给出的选项驱动;允许本次、会话内允许、
151
151
  记住规则等选项只在服务端支持时出现。问卷与 MCP 表单共用现有面板,保密答案掩码。
152
+ - Codex 的 `request_user_input_async` 在运行中打开问卷,智能体继续执行。建议答案默认
153
+ 聚焦第一项,也可自由输入;提交通过原生问题回复信封插话,不可插话时排队到下一回合。
154
+ 取消只关闭该题,不中断回合。回合结束、连接断开或退出时撤回未答问题;历史恢复不会
155
+ 重新打开旧问卷。答案由 Codex 持久化回显投影成「问题 + 答案」,恢复历史时同样显示。
152
156
 
153
157
  ## 日常命令与输入
154
158
 
155
159
  | 入口 | 行为 |
156
160
  | --- | --- |
157
161
  | 工作时 `Enter` / `Tab` / `Ctrl+Enter` | 插话(steer)/ 排队下一回合 / 打断并立即发送;不可 steer 时退为排队 |
158
- | `Esc` / `Ctrl+C` | 按当前焦点关闭面板或中断;取消提问也会中断相应回合,避免挂起 |
162
+ | `Esc` / `Ctrl+C` | 按当前焦点关闭面板或中断;取消阻塞提问会中断相应回合,取消异步提问只关闭该题 |
159
163
  | `/review` | 审查未提交改动,结果 inline 展示;需要空闲,消耗模型用量 |
160
164
  | `/review base <branch>` / `/review commit <sha>` | 按分支基线或提交审查;其他参数作为自定义审查说明 |
161
165
  | `/diff` | 最近回合的聚合 diff;没有时尝试相对远端的 Git diff,再无内容则提示 |
@@ -199,7 +203,10 @@ used = max(0, T - 12000)
199
203
  - `/rename` 改官方 thread 标题;`/color` 只保存会话强调色,不改全局主题。
200
204
  - `/fork` 创建可恢复副本,不自动切换;双击 `Esc` 或 `/rewind` 的对话回退在
201
205
  所选提问之前创建副本并继续,提问回到输入框、原 thread 保留。首条提问回退会
202
- 得到空 thread。**不支持文件回退或对话+文件回退**,Git 工作树不会随对话恢复。
206
+ 得到可恢复的空分支。首条消息及上一回合未加载时的回退需要 Codex app-server
207
+ **0.160.1+**;按连接握手中的服务端版本判断,版本未知或更旧时明确拒绝并提示升级。
208
+ 上一回合已加载时沿用原有回退方式。
209
+ **不支持文件回退或对话+文件回退**,Git 工作树不会随对话恢复。
203
210
  - 恢复先回放最近 20 个完整回合,再接 live;加载更早消息使用预取的完整分页,
204
211
  不拿省略工具项的 summary 当全转录。预取尚未就绪时可再试一次,连续失败会提示。
205
212
  运行中的恢复会去重重发审批;历史没有的完整用量不伪造。
@@ -26,6 +26,43 @@ only for a genuinely new service.
26
26
  > When a row is overridden, its `config` block is replaced as a whole. It is
27
27
  > not deep-merged, so repeat every key that must remain active.
28
28
 
29
+ ## Web search and fetch (DSH 0.2.1-rc.2)
30
+
31
+ The standard DSH profile loads the new DeepSeek Search / Fetch API providers,
32
+ while Messages search and local HTTP fetch remain the defaults. In `/settings`,
33
+ use the arrow keys in **Web search** to select **Search API** and **Fetch API**.
34
+ Each selection saves immediately and applies to the next operation. Choose
35
+ **Messages** / **HTTP** to restore the original providers. Enter accepts a custom
36
+ provider ID. Sections use the plugin's actual Loader entry ID, including custom IDs.
37
+
38
+ **Web search** has one **API key** input. Paste the key for the selected search API;
39
+ typing is masked and confirmation saves it in DSH's credential store, outside
40
+ profile configuration. Reopening shows only whether a key is configured. Blank
41
+ input preserves the saved key, and switching APIs selects that API's credential.
42
+
43
+ The **DeepSeek Search / Fetch API** section edits the API base URL,
44
+ result count (1–50), and **Send original question**. The base URL
45
+ includes the path prefix without `/search` or `/fetch`; its default is
46
+ `https://api.deepseek.com/v1/tools`. DSH supplies an authorized account token for the account route.
47
+ Search sends the first 128 characters of the latest user prompt by default;
48
+ the section can disable this. Messages search has its own endpoint and maximum
49
+ search count section.
50
+
51
+ The user profile patch can also select both providers:
52
+
53
+ ```yaml
54
+ - id: web
55
+ config:
56
+ searchProvider: deepseek-search-api
57
+ fetchProvider: deepseek-fetch-api
58
+ ```
59
+
60
+ The TUI uses DSH's tools, authentication, cancellation and persisted results;
61
+ it does not make an additional model request. Older hosts and compositions
62
+ without the API plugin omit these new settings. The official `deepseek-official`
63
+ and `deepseek-account` routes show a `1017` marker for `DeepSeek-V4.1-Flash` in
64
+ the model list, retaining the original route IDs.
65
+
29
66
  ## Official request metadata and feedback reporting
30
67
 
31
68
  The TUI bundle inherits reporting configuration from the installed official DSH
@@ -438,8 +475,8 @@ The `/provider` add branch signs in to ChatGPT/Codex (`openai-codex`), Claude
438
475
  (`anthropic`), or Grok (`xai`) subscriptions. When the installed host's pi-ai
439
476
  catalog ships the corresponding flows, it also offers OpenAI direct ChatGPT sign-in
440
477
  (`openai`, using the OpenAI API rather than the legacy Codex backend) and Meta
441
- Muse (`meta`). The primary validated DSH `0.2.0-rc.2` fixture carries pi-ai
442
- `0.87.1`, which includes Meta Muse but not OpenAI direct sign-in.
478
+ Muse (`meta`). The primary validated DSH `0.2.1-rc.2` development fixture resolves pi-ai
479
+ `1.2.0`, which includes Meta Muse and OpenAI direct sign-in.
443
480
  `/auth status`, `/auth login [provider]`, and `/auth logout <provider>` use
444
481
  that credential store for these pi-ai routes. Browser authorization tries to open the page
445
482
  automatically and offers the authorization link and manual callback URL/code
@@ -25,6 +25,38 @@ Profile 启动按顺序叠加:
25
25
  > 覆盖某一行时,`config` 是整块替换,不是逐字段深合并。需要继续生效的字段必须
26
26
  > 在用户补丁中全部重写。
27
27
 
28
+ ## 网页搜索与抓取(DSH 0.2.1-rc.2)
29
+
30
+ 标准 DSH profile 会加载新的 DeepSeek Search / Fetch API 提供者,默认仍使用
31
+ Messages 搜索和本地 HTTP 抓取。在 `/settings` 的「网页搜索」分区,用左右键将
32
+ 「搜索」选为「搜索 API」、「抓取」选为「抓取 API」;选择立即保存,从下一次操作
33
+ 生效,不需要重启。切回 `Messages` / `HTTP` 可恢复原提供者。Enter 可输入第三方
34
+ 提供者 ID。分区使用插件实际的 Loader 行 ID,也支持自定义 ID。
35
+
36
+ 「网页搜索」分区只有一个 API key 输入框,可直接粘贴当前搜索 API 的密钥。
37
+ 输入时显示掩码,确认后保存到 DSH 凭据库,不写入 profile 配置;重新打开只显示
38
+ 是否已设置,不回显原值。留空保留已有密钥,切换搜索 API 后使用该 API 的凭据。
39
+
40
+ 「DeepSeek 搜索 / 抓取 API」分区可修改 API 基础地址、搜索结果数
41
+ (1–50)和「发送原始问题」。基础地址包含路径前缀,不含 `/search` 或 `/fetch`,
42
+ 默认 `https://api.deepseek.com/v1/tools`。账号路由由 DSH 使用已授权的账号令牌。
43
+ 默认会将最近一条
44
+ 用户提示的前 128 个字符随搜索请求发送,可在该分区关闭。Messages 搜索的端点与
45
+ 最大搜索次数在独立分区设置。
46
+
47
+ 也可通过用户 profile 补丁选择两个提供者:
48
+
49
+ ```yaml
50
+ - id: web
51
+ config:
52
+ searchProvider: deepseek-search-api
53
+ fetchProvider: deepseek-fetch-api
54
+ ```
55
+
56
+ TUI 沿用 DSH 的工具、鉴权、取消和结果持久化,不额外发起模型请求;旧宿主或未加载
57
+ API 插件的组合不显示这些新增设置。官方 `deepseek-official` / `deepseek-account`
58
+ 路由的 `DeepSeek-V4.1-Flash` 在模型列表中显示 `1017` 标记,路由 ID 不变。
59
+
28
60
  ## 官方请求元数据与反馈上报
29
61
 
30
62
  TUI bundle 继承已安装 DSH 官方组合的上报配置;上游未提供的服务不会由 TUI
@@ -382,8 +414,8 @@ Profile 模式不再使用旧的 `DSH_TUI_COMPACT_RATIO`、`DSH_TUI_COMPACT_RETA
382
414
  `dsh-auth` 插件包**。`/provider` 的添加分支提供 ChatGPT/Codex(`openai-codex`)、
383
415
  Claude(`anthropic`)、Grok(`xai`)订阅账号登录。宿主 pi-ai catalog 提供相应流程
384
416
  时还可使用 OpenAI 直连 ChatGPT 登录(`openai`,使用 OpenAI API 而非旧版 Codex
385
- 后端)和 Meta Muse(`meta`)。当前主验证线 DSH `0.2.0-rc.2` 携带 pi-ai
386
- `0.87.1`,包含 Meta Muse,但不提供 OpenAI 直连登录。`/auth status`、`/auth login [provider]`、
417
+ 后端)和 Meta Muse(`meta`)。当前主验证线 DSH `0.2.1-rc.2` 的开发依赖解析到 pi-ai
418
+ `1.2.0`,包含 Meta Muse 与 OpenAI 直连登录。`/auth status`、`/auth login [provider]`、
387
419
  `/auth logout <provider>` 对这些 pi-ai 路由操作同一套凭据。浏览器授权会尝试自动打开页面,并在同一
388
420
  问卷中提供授权链接与手动粘贴回调 URL/代码的输入;设备码流程在轮询期间显示可复制的
389
421
  短码。无交互问卷服务的宿主会明确拒绝登录。
@@ -387,6 +387,21 @@ that starts `dsh`. Check `DEEPSEEK_BASE_URL` too for a custom endpoint. For
387
387
  `deepseek-account` or a subscription model, inspect `/auth status` and sign in again with
388
388
  `/auth login <provider>` if needed.
389
389
 
390
+ ### The browser connects but dsh-tui cannot reach a self-hosted HTTPS endpoint (self-signed cert / private CA)
391
+
392
+ Self-hosted LLM token servers on a private network are often fronted with HTTPS certificates issued by Caddy, mkcert, Step CA, or similar, whose root certificate is not in Node.js's built-in Mozilla CA bundle. The browser and system `curl` then work fine, but after switching dsh-tui to that provider the TLS handshake fails with `self-signed certificate in certificate chain` or `UNABLE_TO_VERIFY_LEAF_SIGNATURE`.
393
+
394
+ The reason is that dsh-tui's HTTP requests run on Node.js's TLS layer, and Node.js trusts only two things: the Mozilla CA bundle compiled into it, plus the PEM file named by the `NODE_EXTRA_CA_CERTS` environment variable (merged with the built-in list). macOS Keychain "trust" settings have no effect on a Node.js process — Node does not call the system Security.framework, so the trust chain the browser and `curl` use is irrelevant here.
395
+
396
+ Export the root certificate as PEM and set the variable before launching dsh-tui:
397
+
398
+ ```sh
399
+ export NODE_EXTRA_CA_CERTS=/path/to/your-ca-root.pem
400
+ dsh-tui
401
+ ```
402
+
403
+ Note that `NODE_EXTRA_CA_CERTS` is a bootstrap-protected variable for the DSH launcher: no `.env` file may set it (neither the project directory's `.env` nor `~/.dsh/.env`), and putting it there makes startup fail with an error telling you to `export` it instead — it can only come from the shell environment that launches dsh. The same protected group covers other certificate / TLS variables such as `SSL_CERT_FILE`, `SSL_CERT_DIR`, and `NODE_TLS_REJECT_UNAUTHORIZED`.
404
+
390
405
  ### The activity row appears twice
391
406
 
392
407
  Check whether `dsh-working-activity` was added separately to the profile. Keep
@@ -387,6 +387,21 @@ dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui@latest
387
387
  自定义端点同时检查 `DEEPSEEK_BASE_URL`。若使用 `deepseek-account` 或订阅模型,
388
388
  用 `/auth status` 检查登录状态,必要时重新运行 `/auth login <provider>`。
389
389
 
390
+ ### 浏览器能访问、dsh-tui 连不上自建 HTTPS 端点(自签证书 / 私有 CA)
391
+
392
+ 内网自建的 LLM token 服务器常用 Caddy、mkcert、Step CA 等签发 HTTPS 证书,这类根证书不在 Node.js 内置的 Mozilla CA 列表里。于是浏览器和系统级 `curl` 都能正常访问,dsh-tui 切到该 provider 后却在 TLS 握手阶段失败,报 `self-signed certificate in certificate chain` 或 `UNABLE_TO_VERIFY_LEAF_SIGNATURE`。
393
+
394
+ 原因是 dsh-tui 的 HTTP 请求跑在 Node.js 的 TLS 层上,而 Node.js 只信任两样东西:编译时打包的 Mozilla CA bundle,以及环境变量 `NODE_EXTRA_CA_CERTS` 指向的 PEM 文件(与内置列表合并)。macOS Keychain 里的「信任」设置对 Node.js 进程无效——Node 不调用系统的 Security.framework,浏览器和 `curl` 用的信任链跟它无关。
395
+
396
+ 解决办法是把根证书导出成 PEM,在启动 dsh-tui 之前设置该变量:
397
+
398
+ ```sh
399
+ export NODE_EXTRA_CA_CERTS=/path/to/your-ca-root.pem
400
+ dsh-tui
401
+ ```
402
+
403
+ 注意 `NODE_EXTRA_CA_CERTS` 属于 DSH 启动器的 bootstrap 保护变量:任何 `.env` 文件(项目目录的 `.env` 与 `~/.dsh/.env` 都算)都不允许设置它,写进去会在启动时直接报错退出并提示改用 `export`,只能由启动 dsh 的那个 Shell 环境继承。同组受保护的证书 / TLS 变量还有 `SSL_CERT_FILE`、`SSL_CERT_DIR`、`NODE_TLS_REJECT_UNAUTHORIZED` 等。
404
+
390
405
  ### 工作状态行重复
391
406
 
392
407
  检查 profile 是否曾单独添加 `dsh-working-activity`。保留本包 patch 自动插入的
@@ -473,6 +473,13 @@ Notes:
473
473
  and never reaches the main context or token counts (closing the panel discards it).
474
474
  - **Never interrupts the running turn**: it can be triggered while the model is streaming; the main task keeps going.
475
475
  - Inside the panel: `↑`/`↓` scroll, `Space`/`Enter`/`Esc` dismiss, `c` copies the answer; `Esc` cancels while the answer is still pending.
476
+ - The sidebar panel (when the panel column is open) has two layers: the default **reading layer** — `←`/`→` switch panels, `↑`/`↓` move the **selection** between turns, `PgUp`/`PgDn` page, `n` starts a new topic, `s` sends the **selected** turn's answer to the main composer (press `s` again to take it back), `c` copies the selected turn's answer; `Enter`/`Tab` (or a click on the input) enters the **editing layer** (`Esc` leaves one layer at a time: editing first, draft kept), where `←`/`→` move the caret first and, once the caret sits at the start/end, the same key falls through and switches panels again, while `↑` goes straight back up to the titles.
477
+ - The sidebar's bottom hint line **follows the layer** (the panel advertises it, the host only stitches it): with the cursor in the **list** it says `↑/↓ select · s to chat · c copy` (or `s unsend` for the attached turn); with the cursor in the **input** it drops s/c (there `s` is just a letter) and says `↑ select` instead. An empty thread advertises nothing there. The input box keeps only an `Enter to ask` placeholder.
478
+ - The selection shows itself in exactly two ways: the title's **text** is inverted (not the whole row) and the terminal cursor parks on that row — so `↑`/`↓` visibly walks the native caret between titles. Both are hidden while the cursor sits in the main input or the side composer: they mean "the list owns the keyboard". **Clicking a title row** moves the selection there too.
479
+ - Scrolling only happens when it must: a target title already inside the viewport scrolls nothing at all; one outside it scrolls just far enough to **exactly reveal** that row (flush to the top edge when walking up, flush to the bottom edge when walking down).
480
+ - **Focus returns to the main composer after sending**: the chip is right there, you can keep typing, and `Esc` removes it immediately (inside the panel `Esc` leaves the panel instead of dropping the chip).
481
+ - Clicking the **message area** (question or answer text) only hands the column focus to the panel, exactly like clicking anywhere else in it — it never injects anything; `s` is the only way in.
482
+ - The `⤢` full-screen scene shares the sidebar's keys and selection state (both read the same thread store); the only difference is that after sending it steps aside and returns you to the main composer.
476
483
  - Triggering `/btw` again aborts the previous side question.
477
484
 
478
485
  ### Trajectory scene (/trace / Ctrl+T)
@@ -802,7 +809,7 @@ The command menu merges local commands with the DSH command registry. Type `/` t
802
809
 
803
810
  **Account and policy**
804
811
 
805
- - `/provider`, `/login`, `/logout`, `/permission`, `/add-dir`, `/hooks`, `/mcp`, `/plugin` — `list` shows the plugins you added (the installation-supplied bundles stay out); `check <path>` validates a plugin manifest, `info <id>` describes an installed entry or an install spec, `registries` lists where installations ask; bare `/plugin` gives the full diagnostics (reserved for the plugin management panel).
812
+ - `/provider`, `/login`, `/logout`, `/permission`, `/add-dir`, `/hooks`, `/mcp`, `/plugin` — `list` shows the plugins you added (the installation-supplied bundles stay out); `install <spec>` installs a plugin into this profile (a pre-install notice and a trust confirmation; first-party packages on the packaged feed skip the confirmation; `esc` closes the pane, and during an install it attempts cancellation and waits for writes to settle, or for completion if too late; exemptions already written remain; blocked build scripts are approved in the pane, and an incompatible version can be exempted for that exact version); `remove <bundle>` / `enable <name|id>` / `disable <name|id>` are the lifecycle actions (a bundle name wins over a row identity; a module name matching multiple rows requires a specific row ID; gate 2 refuses the bundle providing this app, the host layer `dsh-base` and this package's own rows, with a reason and no service call, while every enable and removal asks first because installed sources cannot be verified; **no cancellation** — `esc` only closes the pane and the write goes on, and a removal does not delete your own data); `check <path>` validates a plugin manifest, `info <id>` describes an installed entry or an install spec, `registries` lists where installations ask; bare `/plugin` gives the full diagnostics.
806
813
  - After `/auth login deepseek-account` or `/provider` signs in, a Platform-confirmed, unshown login bonus appears with its amount and expiry as a “Whale coupon” in the whale-maid dialog; Enter/Esc closes it.
807
814
 
808
815
  **Skills**
@@ -461,6 +461,13 @@ Windows `dsh-tui.cmd --resume` 使用 `~/.dsh-tui/resume.txt` 中最后选择的
461
461
  - **不进会话历史**:问答不写入 session log,也不会出现在主上下文与 token 计数里(关闭面板即消失)。
462
462
  - **不打断主回合**:模型正在流式输出时也可以触发,主任务继续运行。
463
463
  - 面板内 `↑`/`↓` 滚动,`Space`/`Enter`/`Esc` 关闭,`c` 复制答案;等待答案时 `Esc` 取消。
464
+ - 侧栏面板形态(面板列展开时)分两层:默认**阅读层**——`←`/`→` 切面板、`↑`/`↓` 在轮之间移动**选中**、`PgUp`/`PgDn` 翻页、`n` 新话题、`s` 把**选中轮**的答案送进主输入框(再按一次 `s` = 撤回)、`c` 复制选中轮的答案;`Enter`/`Tab`(或点击输入框)进**编辑层**(`Esc` 逐层退出:先退编辑、草稿保留),编辑层里 `←`/`→` 先移光标,光标贴到行首/行尾后再按同一个键就交回宿主切面板,`↑` 则直接回到标题(列表)。
465
+ - 侧栏那行底栏提示**按层换**(面板自己广告、宿主只拼):光标在**列表**里说 `↑/↓ 选择 · s 送聊天 · c 复制`(已附加的那一轮说 `s 撤回`),光标在**输入框**里则不说 s/c(那里 `s` 只是打字),改说 `↑ 选择`;空线程没有可选的轮,这一段不画。输入框里只留一句 `Enter 提问` 占位。
466
+ - 选中的标记只有两点:标题**文字**反色(不铺满整行),以及终端光标停在那一行(所以按 `↑`/`↓` 时原生光标的拖尾是在标题之间上下走)。光标在主输入框或侧栏输入框里时两者都不显示——它表示的是「列表正拿着键盘」。**点标题行**也能把选中挪到那一轮。
467
+ - 滚动只在必要时发生:目标标题已经在视口里就一行都不滚;走出视口才滚,而且只滚到**恰好露出**这一行(往上走贴视口顶、往下走贴视口底)。
468
+ - **送聊天之后焦点自动回主输入框**:chip 就在眼前、可以直接接着打字,`Esc` 也立刻能把它撤掉(在面板里按 `Esc` 是退出面板,不是撤 chip)。
469
+ - 点**消息区**(问题/答案正文)跟点面板其它地方一样,只把列焦点交给面板,不会注入任何东西——注入只有 `s` 一个入口。
470
+ - `⤢` 全屏场景与侧栏面板同一套键位与选中态(线程 store 共享),区别只是送完聊天后整屏场景让位、回到主输入框。
464
471
  - 再次触发 `/btw` 会中止上一个侧问。
465
472
 
466
473
  ### 轨迹场景(/trace / Ctrl+T)
@@ -804,7 +811,7 @@ Claude 后端的审批来自 CLI:CLI 给出建议时多一个「始终允许
804
811
 
805
812
  - `/provider`、`/login`、`/logout`、`/permission`、`/add-dir`、`/hooks`、`/mcp`。
806
813
  - `/auth login deepseek-account` 或 `/provider` 完成 DeepSeek 登录后,若 Platform 返回尚未展示的登录赠金,鲸鱼女仆娘弹窗会显示“鲸鱼券”的金额与到期时间;按 Enter/Esc 关闭。
807
- - `/plugin`:`list` 简洁列出你装的额外插件(不含安装自带);`check <路径>` 校验插件清单、`info <id>` 查已装条目或待装 spec、`registries` 列安装源;无参 `/plugin` 给完整诊断(预留为插件管理面板)。
814
+ - `/plugin`:`list` 简洁列出你装的额外插件(不含安装自带);`install <spec>` 把插件装进当前 profile(装前提醒 + 信任确认,嫡系包按随包清单免确认;`esc` 收起面板,安装中尝试取消并等待写操作结束,来不及时等待安装完成,已登记的版本豁免保留;构建脚本被拦时在面板里批准,版本不兼容可登记精确版本豁免);`remove <bundle>` / `enable <名称|id>` / `disable <名称|id>` 是生命周期动作(bundle 名优先于行身份,模块名匹配多行时须改用具体行 ID;门禁 2 对提供本应用的 bundle、宿主层 `dsh-base` 与本包自己的行硬拒并给原因,任何启用与卸载都要确认(已装包来源无法验证);**没有取消**——`esc` 只关面板,写入继续,卸载不删你自己的数据);`check <路径>` 校验插件清单、`info <id>` 查已装条目或待装 spec、`registries` 列安装源;无参 `/plugin` 给完整诊断。
808
815
 
809
816
  **Skills**
810
817
 
@@ -43,6 +43,10 @@ reference**, not a promise:
43
43
  Also an experimental public surface:
44
44
 
45
45
  - `@deepseek-harness-tui/dsh-tui/api` (types-only entry).
46
+ - **Rows inside a preset (experimental, seam VII)**: a bundle changes the `config` of a row
47
+ inside a preset dsh-TUI registers (for example, turning off `standard`'s
48
+ `compaction-basic` auto-compaction) with a `@deepseek-harness-tui/dsh-tui/preset-patch` row;
49
+ see seam VII of the [admission and development guide](../tui-profile/docs/plugin-admission-and-development.md).
46
50
  - **Side panels (experimental, §18)**: `ctx.tuiPanels.register({ apiVersion:
47
51
  1, id, title, icon?, component | compact })` registers a right-sidebar
48
52
  panel (the host prefixes `<pluginId>:`; ≤4 panels per plugin, ≤32 globally;
@@ -59,11 +63,68 @@ Also an experimental public surface:
59
63
  - **The backend contribution family (`tui.dsh/v1alpha1` `Backend`, seam XIV) has its
60
64
  public surface frozen with the first published apiVersion**: the type surface
61
65
  (`BackendSpec`, `validateBackendSpec`, `backendAdmission`) and conformance
62
- (`TUI-BACKEND-001`) are usable, and the **admission chain (manifest →
63
- registry → descriptor) is wired**; what is still missing is the step that
64
- reads a mounted bundle's declaration into the registry and the kernel picker
65
- (the install chain), so "install a third-party backend, restart, see it in the
66
- picker" does not hold end to end yet.
66
+ (`TUI-BACKEND-001`) are usable, and **both the admission chain (manifest →
67
+ registry → descriptor) and the install chain are wired**: the boot scans the
68
+ bundles the profile declares (`dsh.profile.bundles`, written by `/plugin install`
69
+ and by `dsh plugin add` alike), reads `dsh-plugin.json` from the package root
70
+ nearest the actual ESM entry, and registers what the validator and the admission
71
+ accept — so "install a third-party backend, restart, see it in the picker" holds.
72
+ Three boundaries: that scan runs **before** backend-choice registry membership
73
+ is checked (the Config schema checks syntax only, and the standalone entry's
74
+ full/light composition follows the final, assembled kernel); a backend's
75
+ implementation is read from its entry module's `backend` export
76
+ (`backendExport` is an in-tree private field, so a declaration cannot name another
77
+ export) and that module is imported only when the backend is actually selected;
78
+ and installing **without restarting** still does not put it in the picker — that
79
+ is not a promise.
80
+ Each bundle currently binds one `Backend` declaration. Its manifest must pass
81
+ canonical projection, including unique contribution identities, and the handler
82
+ id must match the declaration. Entries awaiting authorization stay registered
83
+ but are neither probed nor loaded; explicitly selecting one at startup fails too.
84
+ - **Installing a package is available in the terminal itself (C-4)**: `/plugin
85
+ install <spec>` goes through the host's `ctx.pluginManager` — a pre-install
86
+ notice, a trust confirmation decided by provenance of the package (the judge is
87
+ the packaged `tui-profile/feed/first-party.json`, decided offline; anything it
88
+ cannot vouch for falls back to the confirmation), and `esc` to close the pane.
89
+ During an install, it attempts cancellation and waits for profile writes to
90
+ settle: the service rolls the profile back on cancellation, or finishes the
91
+ install if applying has already made cancellation too late. Blocked build
92
+ scripts can be approved in the pane, and an incompatible version can receive
93
+ an **exact-version exemption**. Cancelling during exemption registration waits
94
+ for the current write and stops subsequent grants and the retry; exemptions
95
+ already written remain. **Known gaps**:
96
+ provenance is only a one-vote-to-veto seam with no online check at all (the
97
+ host service exposes no such API), and with no service the transcript reports
98
+ the CLI command and the reason instead of **running `dsh plugin` on the user's
99
+ behalf** (no pane opens: there is no flow to drive).
100
+ - **Lifecycle actions are available in the terminal itself (C-5)**: `/plugin remove
101
+ <bundle>`, `/plugin enable <name|id>` and `/plugin disable <name|id>` go through the
102
+ same host service. **A bundle and a row are two levels**: a bundle is a composition
103
+ layer (the profile manifest's `dsh.profile.bundles`), a row is one patch entry's
104
+ `disabled`. The argument resolves against one snapshot, a bundle name first and
105
+ exactly, then `entryId` → `patchId` → module name; nothing that matches is reported
106
+ with what is addressable rather than guessed at. A module name matching multiple rows
107
+ is refused with their row IDs; use a specific ID. **Gate 2** (this application may not
108
+ switch itself off) refuses three kinds of target hard — the bundle providing this app,
109
+ the host layer `@deepseek-ai/dsh-base`, and this application's own rows (those loading
110
+ a module of this package, **or inserted by its own patch**: measured, that patch inserts
111
+ 17 rows and 8 of them load a first-party `@deepseek-ai/*` module, of which the host locks
112
+ exactly one) — with a reason line and **no service call at all**, and it does so whether or not hot
113
+ reload is live (the host's own `stop-profile` guard only fires without HMR, and this
114
+ profile runs `patchReload: live`). `enable` is never refused by gate 2: it is the
115
+ repair action, and refusing it would seal off the only in-UI way back from a profile
116
+ somebody edited by hand. The host's own lock (`management-required` / `unaddressable`)
117
+ refuses both directions and its reason is quoted as given. **Every `enable` and `remove` requires confirmation** (a removal lists the
118
+ rows and overrides it drops), while `disable` asks only about a row the host layer
119
+ owns (switching one off unloads services this app injects). The host does not attest
120
+ installed package sources: local and Git packages can claim the same name and version,
121
+ so an exact feed match cannot waive confirmation when enabling. These actions have **no
122
+ cancellation**: the service offers none, so `esc` only closes the pane while the write
123
+ finishes and reports itself into the transcript (same session). **Known gaps**: a
124
+ removal deletes no user data — `~/.dsh-tui/backends/<id>/`, grants and storage
125
+ namespaces are **reported once** and left for the person to delete; when a package's
126
+ declaration cannot be read, the flow says it could not judge rather than claiming the
127
+ removal was clean.
67
128
  - `grants` is now the narrower `HostGrantFacade`; see that PR for migration
68
129
  details.
69
130
  - On `TuiSceneProps.channel` (`ChannelUi`), `minimal` / `setMinimal()` were
@@ -38,6 +38,9 @@
38
38
  另:
39
39
 
40
40
  - `@deepseek-harness-tui/dsh-tui/api`(纯类型入口)为实验性公开面。
41
+ - **preset 内的行(实验性,接缝七)**:bundle 用 `@deepseek-harness-tui/dsh-tui/preset-patch`
42
+ 行改 dsh-TUI 注册的 preset 里某一行的 `config`(例如关掉 `standard` 的
43
+ `compaction-basic` 自动压缩),写法见[准入与开发指南](../tui-profile/docs/plugin-admission-and-development.md)接缝七。
41
44
  - **侧栏 Panel(实验性,§18)**:`ctx.tuiPanels.register({ apiVersion: 1,
42
45
  id, title, icon?, component | compact })` 向右侧栏注册面板(宿主自动加
43
46
  `<pluginId>:` 前缀;每插件 ≤4 个、全局 ≤32 个;`open()` 限速每 5s 一次;
@@ -50,9 +53,40 @@
50
53
  `ctx.tuiPluginHost.grants.corrupt` 已随 adapter 分层重构(#705)移除。
51
54
  - **后端贡献族(`tui.dsh/v1alpha1` `Backend`,接缝十四)的公开面已随第一版 apiVersion 冻结**:类型面
52
55
  (`BackendSpec`、`validateBackendSpec`、`backendAdmission`)与 conformance
53
- (`TUI-BACKEND-001`)已可用,**准入链路(清单 → registry → descriptor)已接线**;
54
- 仍未做的是把已挂载 bundle 的声明接进注册表与 kernel picker(装链路),所以
55
- 「装一个第三方后端、重启后出现在 picker 里」这条端到端流程尚未成立。
56
+ (`TUI-BACKEND-001`)已可用,**准入链路(清单 → registry → descriptor)与装链路都已接线**:
57
+ 启动时扫 profile 声明的已装 bundle(`dsh.profile.bundles`——`/plugin install` 与 `dsh plugin add`
58
+ 都写它),按**实际 ESM 入口最近的包根**读 `dsh-plugin.json`,校验 + 准入后注册,于是
59
+ 「装一个第三方后端、重启后出现在 picker 里」成立。三条边界:这份扫描**早于**后端选择的注册表成员判定
60
+ (Config Schema 只校验语法,独立入口的完整/轻量组合由装配后的最终内核决定);后端实现从包入口模块的 `backend` 导出取
61
+ (`backendExport` 是 in-tree 私有项,声明里写不了别的导出名),模块只在真的选中时才 import;
62
+ 装完**不重启**仍然不会出现在 picker 里——那不是承诺。
63
+ 当前每个 bundle 只接一个 `Backend` 声明;清单须通过规范投影(含贡献身份唯一性),handler 的 id 必须与声明一致。
64
+ 等待授权的条目仍注册身份,但不探测、不加载;启动参数或配置显式指定它也会报错。
65
+ - **装包本身已在终端里可用(C-4)**:`/plugin install <spec>` 走宿主
66
+ `ctx.pluginManager`,装前给提醒、按来源决定要不要确认信任(嫡系判据是随包发布的
67
+ `tui-profile/feed/first-party.json`,离线可判;验不过一律 fail closed 退回确认),
68
+ `esc` 收起面板;安装进行中会尝试取消,面板等写操作结束后才关闭。取消成功由服务回滚 profile,
69
+ 已进入应用阶段而来不及时则等待安装完成。构建脚本被拦时在面板里批准,
70
+ 版本不兼容可登记 **精确版本豁免**;登记期间取消会等待当前写入、停止后续登记和重试,
71
+ 已写入的豁免保留。**已知缺口**:provenance 只留了「一票否决」的缝、
72
+ 没有任何在线校验(宿主服务不暴露这类 API);服务缺席时由转录给出 CLI 命令与原因
73
+ (不弹面板:没有可驱动的流程),**不在 TUI 内代跑 `dsh plugin`**。
74
+ - **生命周期动作已在终端里可用(C-5)**:`/plugin remove <bundle>`、`/plugin enable
75
+ <名称|id>`、`/plugin disable <名称|id>` 走同一套宿主服务。**bundle 与行是两级语义**:
76
+ bundle 是组合层(写 profile 清单的 `dsh.profile.bundles`),行是 patch 的 `disabled`;
77
+ 解析顺序是 bundle 名精确匹配优先,其次 `entryId` → `patchId` → 模块名,都不中就给可寻址
78
+ 清单、不猜;模块名匹配多行时,列出行 ID 并拒绝写入,须改用具体 ID。**门禁 2**(不能自己杀自己)在 TUI 侧硬拒三类目标——提供本应用的 bundle、
79
+ 宿主层 `@deepseek-ai/dsh-base`、本应用自己的行(加载本包模块的行,**或由本包 patch
80
+ 插入的行**:实测本包的 patch 插入 17 行,其中 8 行加载的是首方 `@deepseek-ai/*` 模块,
81
+ 上游只锁住其中一个)——拒绝时给一行原因且**不发起任何服务调用**,与 HMR 是否生效无关(上游 `stop-profile` 守卫只在没有 HMR 时生效,本 profile 是
82
+ `patchReload: live`,所以那道守卫靠不住)。`enable` 不因门禁 2 被拒:它是复原动作,把手工
83
+ 改坏的 profile 关在门外等于封死唯一的 UI 退路;上游自己的锁(`management-required` /
84
+ `unaddressable`)则两个方向都拒,并原样转述上游的理由。**任何 `enable` 与 `remove` 都要确认**(卸载列出它会动的行数与覆盖数),
85
+ `disable` 只对宿主层自己的行问一句(关掉它会卸载本应用注入的服务)。宿主不提供
86
+ 已装包的来源证明,本地或 Git 包也能声明嫡系的名称与版本,因此即使命中 feed 也不能免确认。这些动作**没有取消面**:
87
+ 服务不提供,Esc 只关面板,写入照旧跑完并(在同一会话里)把结果写进转录。**已知缺口**:
88
+ 卸载不删用户数据——`~/.dsh-tui/backends/<id>/`、grants、存储命名空间只**报告一次**,由
89
+ 用户自己决定删不删;包内声明读不到时明说「判断不了」,不制造「已清理」的假象。
56
90
  - `grants` 收窄为 `HostGrantFacade`,迁移细节见该 PR。
57
91
  - `TuiSceneProps.channel`(`ChannelUi`)上的 `minimal` / `setMinimal()` 已更名为
58
92
  `minimalUi` / `setMinimalUi()`;旧名保留为 **deprecated 别名**,读写同一个