@deepseek-harness-tui/dsh-tui 0.14.1 → 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 (886) hide show
  1. package/README.md +163 -17
  2. package/bin/dsh-tui.js +200 -34
  3. package/cordis.patch.yml +16 -52
  4. package/cordis.yml +6 -2
  5. package/guide/dsh-tui-guide/claude-backend.en.md +44 -7
  6. package/guide/dsh-tui-guide/claude-backend.md +28 -6
  7. package/guide/dsh-tui-guide/codex-backend.en.md +47 -10
  8. package/guide/dsh-tui-guide/codex-backend.md +26 -4
  9. package/guide/dsh-tui-guide/configuration.en.md +168 -18
  10. package/guide/dsh-tui-guide/configuration.md +144 -16
  11. package/guide/dsh-tui-guide/getting-started.en.md +15 -0
  12. package/guide/dsh-tui-guide/getting-started.md +15 -0
  13. package/guide/dsh-tui-guide/interaction.en.md +64 -24
  14. package/guide/dsh-tui-guide/interaction.md +49 -19
  15. package/guide/dsh-tui-guide/plugins.en.md +97 -3
  16. package/guide/dsh-tui-guide/plugins.md +55 -2
  17. package/guide/dsh-tui-guide/themes.en.md +23 -14
  18. package/guide/dsh-tui-guide/themes.md +19 -12
  19. package/guide/dsh-tui-guide/user-guide.en.md +53 -21
  20. package/guide/dsh-tui-guide/user-guide.md +43 -22
  21. package/lib/settings.json +103 -9
  22. package/lib/types/adapter/channel/projection.d.ts.map +1 -1
  23. package/lib/types/adapter/channel/projection.js +1 -0
  24. package/lib/types/adapter/channel/ui-policy.d.ts +1 -1
  25. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  26. package/lib/types/adapter/channel/ui-policy.js +4 -0
  27. package/lib/types/adapter/channel/ui.d.ts +2 -0
  28. package/lib/types/adapter/channel/ui.d.ts.map +1 -1
  29. package/lib/types/adapter/channel/ui.js +6 -2
  30. package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
  31. package/lib/types/adapter/kernel/runtime.js +2 -0
  32. package/lib/types/adapter/ports/channel-catalog.d.ts +5 -1
  33. package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
  34. package/lib/types/adapter/ports/channel-settings.d.ts +14 -3
  35. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  36. package/lib/types/adapter/ports/channel-ui.d.ts +56 -12
  37. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  38. package/lib/types/adapter/ports/channel-view.d.ts +68 -0
  39. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  40. package/lib/types/adapter/ports/channel.d.ts +2 -0
  41. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  42. package/lib/types/adapter/spec/backend-capabilities.d.ts +22 -0
  43. package/lib/types/adapter/spec/backend-capabilities.d.ts.map +1 -0
  44. package/lib/types/adapter/spec/backend-capabilities.js +49 -0
  45. package/lib/types/adapter/spec/protocol-constants.d.ts.map +1 -1
  46. package/lib/types/adapter/spec/protocol-constants.js +10 -3
  47. package/lib/types/adapter/spec/tui-contributions.d.ts +3 -0
  48. package/lib/types/adapter/spec/tui-contributions.d.ts.map +1 -1
  49. package/lib/types/adapter/spec/tui-contributions.js +7 -0
  50. package/lib/types/adapter/standard/registry.d.ts +6 -0
  51. package/lib/types/adapter/standard/registry.d.ts.map +1 -1
  52. package/lib/types/adapter/standard/registry.js +65 -15
  53. package/lib/types/adapter/standard/tui-extension.d.ts.map +1 -1
  54. package/lib/types/adapter/standard/tui-extension.js +7 -1
  55. package/lib/types/adapter/standard/types.d.ts +10 -1
  56. package/lib/types/adapter/standard/types.d.ts.map +1 -1
  57. package/lib/types/adapter/upstream/host-descriptor-driver.d.ts.map +1 -1
  58. package/lib/types/adapter/upstream/host-descriptor-driver.js +52 -0
  59. package/lib/types/agent/backend-manifest.d.ts +152 -0
  60. package/lib/types/agent/backend-manifest.d.ts.map +1 -0
  61. package/lib/types/agent/backend-manifest.js +14 -0
  62. package/lib/types/agent/backend.d.ts +71 -5
  63. package/lib/types/agent/backend.d.ts.map +1 -1
  64. package/lib/types/agent/capabilities.d.ts +6 -0
  65. package/lib/types/agent/capabilities.d.ts.map +1 -1
  66. package/lib/types/agent/events.d.ts +3 -2
  67. package/lib/types/agent/events.d.ts.map +1 -1
  68. package/lib/types/agent/index.d.ts +2 -0
  69. package/lib/types/agent/index.d.ts.map +1 -1
  70. package/lib/types/agent/refs.d.ts +11 -1
  71. package/lib/types/agent/refs.d.ts.map +1 -1
  72. package/lib/types/agent/starting-session.d.ts +4 -0
  73. package/lib/types/agent/starting-session.d.ts.map +1 -0
  74. package/lib/types/agent/starting-session.js +19 -0
  75. package/lib/types/backends/claude/activity.d.ts +1 -1
  76. package/lib/types/backends/claude/activity.d.ts.map +1 -1
  77. package/lib/types/backends/claude/activity.js +5 -5
  78. package/lib/types/backends/claude/auth.d.ts.map +1 -1
  79. package/lib/types/backends/claude/auth.js +10 -3
  80. package/lib/types/backends/claude/backend.d.ts.map +1 -1
  81. package/lib/types/backends/claude/backend.js +103 -29
  82. package/lib/types/backends/claude/catalog.d.ts +2 -1
  83. package/lib/types/backends/claude/catalog.d.ts.map +1 -1
  84. package/lib/types/backends/claude/catalog.js +15 -5
  85. package/lib/types/backends/claude/channels.d.ts +5 -3
  86. package/lib/types/backends/claude/channels.d.ts.map +1 -1
  87. package/lib/types/backends/claude/channels.js +5 -4
  88. package/lib/types/backends/claude/contract.d.ts +4 -0
  89. package/lib/types/backends/claude/contract.d.ts.map +1 -1
  90. package/lib/types/backends/claude/contract.js +4 -0
  91. package/lib/types/backends/claude/controls.d.ts +4 -0
  92. package/lib/types/backends/claude/controls.d.ts.map +1 -1
  93. package/lib/types/backends/claude/controls.js +34 -42
  94. package/lib/types/backends/claude/dialogs.d.ts +8 -2
  95. package/lib/types/backends/claude/dialogs.d.ts.map +1 -1
  96. package/lib/types/backends/claude/dialogs.js +24 -16
  97. package/lib/types/backends/claude/images.d.ts +1 -1
  98. package/lib/types/backends/claude/images.d.ts.map +1 -1
  99. package/lib/types/backends/claude/images.js +7 -7
  100. package/lib/types/backends/claude/manifest.d.ts +21 -0
  101. package/lib/types/backends/claude/manifest.d.ts.map +1 -0
  102. package/lib/types/backends/claude/manifest.js +29 -0
  103. package/lib/types/backends/claude/older-history.js +2 -2
  104. package/lib/types/backends/claude/permissions.js +11 -11
  105. package/lib/types/backends/claude/prefs.d.ts +4 -2
  106. package/lib/types/backends/claude/prefs.d.ts.map +1 -1
  107. package/lib/types/backends/claude/prefs.js +4 -3
  108. package/lib/types/backends/claude/process.d.ts +16 -4
  109. package/lib/types/backends/claude/process.d.ts.map +1 -1
  110. package/lib/types/backends/claude/process.js +100 -37
  111. package/lib/types/backends/claude/send-message.d.ts +1 -1
  112. package/lib/types/backends/claude/send-message.d.ts.map +1 -1
  113. package/lib/types/backends/claude/session/auth.js +22 -22
  114. package/lib/types/backends/claude/session/channels.d.ts +4 -0
  115. package/lib/types/backends/claude/session/channels.d.ts.map +1 -1
  116. package/lib/types/backends/claude/session/channels.js +5 -3
  117. package/lib/types/backends/claude/session/lifecycle.d.ts.map +1 -1
  118. package/lib/types/backends/claude/session/lifecycle.js +31 -23
  119. package/lib/types/backends/claude/session/store.js +8 -8
  120. package/lib/types/backends/claude/session/subagents.js +2 -2
  121. package/lib/types/backends/claude/session/types.d.ts +7 -0
  122. package/lib/types/backends/claude/session/types.d.ts.map +1 -1
  123. package/lib/types/backends/claude/side-query.js +3 -3
  124. package/lib/types/backends/claude/task-output.js +5 -5
  125. package/lib/types/backends/claude/text.d.ts +778 -0
  126. package/lib/types/backends/claude/text.d.ts.map +1 -0
  127. package/lib/types/backends/claude/text.js +298 -0
  128. package/lib/types/backends/claude/transcript-file.d.ts +1 -1
  129. package/lib/types/backends/claude/transcript-file.d.ts.map +1 -1
  130. package/lib/types/backends/claude/transcript-file.js +4 -4
  131. package/lib/types/backends/claude/translate/attempts.js +2 -2
  132. package/lib/types/backends/claude/translate/core.js +3 -3
  133. package/lib/types/backends/claude/translate/messages.js +4 -4
  134. package/lib/types/backends/claude/translate/system.js +14 -14
  135. package/lib/types/backends/claude/translate/tasks.js +2 -2
  136. package/lib/types/backends/claude/translate/types.d.ts +1 -1
  137. package/lib/types/backends/claude/translate/types.d.ts.map +1 -1
  138. package/lib/types/backends/codex/auth/external-tokens.js +16 -16
  139. package/lib/types/backends/codex/auth/status.js +14 -14
  140. package/lib/types/backends/codex/backend.d.ts +4 -19
  141. package/lib/types/backends/codex/backend.d.ts.map +1 -1
  142. package/lib/types/backends/codex/backend.js +118 -25
  143. package/lib/types/backends/codex/catalog.d.ts +2 -1
  144. package/lib/types/backends/codex/catalog.d.ts.map +1 -1
  145. package/lib/types/backends/codex/catalog.js +63 -18
  146. package/lib/types/backends/codex/channels.d.ts +6 -3
  147. package/lib/types/backends/codex/channels.d.ts.map +1 -1
  148. package/lib/types/backends/codex/channels.js +15 -13
  149. package/lib/types/backends/codex/contract.d.ts +3 -0
  150. package/lib/types/backends/codex/contract.d.ts.map +1 -1
  151. package/lib/types/backends/codex/contract.js +3 -0
  152. package/lib/types/backends/codex/detect.d.ts.map +1 -1
  153. package/lib/types/backends/codex/detect.js +9 -6
  154. package/lib/types/backends/codex/manifest.d.ts +30 -0
  155. package/lib/types/backends/codex/manifest.d.ts.map +1 -0
  156. package/lib/types/backends/codex/manifest.js +23 -0
  157. package/lib/types/backends/codex/prefs.d.ts +4 -2
  158. package/lib/types/backends/codex/prefs.d.ts.map +1 -1
  159. package/lib/types/backends/codex/prefs.js +4 -3
  160. package/lib/types/backends/codex/rpc/hub.js +2 -2
  161. package/lib/types/backends/codex/session/activity.d.ts +1 -1
  162. package/lib/types/backends/codex/session/activity.d.ts.map +1 -1
  163. package/lib/types/backends/codex/session/activity.js +13 -13
  164. package/lib/types/backends/codex/session/approvals.js +30 -30
  165. package/lib/types/backends/codex/session/async-questions.d.ts +17 -0
  166. package/lib/types/backends/codex/session/async-questions.d.ts.map +1 -0
  167. package/lib/types/backends/codex/session/async-questions.js +89 -0
  168. package/lib/types/backends/codex/session/commands.d.ts +8 -2
  169. package/lib/types/backends/codex/session/commands.d.ts.map +1 -1
  170. package/lib/types/backends/codex/session/commands.js +71 -23
  171. package/lib/types/backends/codex/session/controls.d.ts +1 -1
  172. package/lib/types/backends/codex/session/controls.d.ts.map +1 -1
  173. package/lib/types/backends/codex/session/controls.js +21 -16
  174. package/lib/types/backends/codex/session/goals.d.ts.map +1 -1
  175. package/lib/types/backends/codex/session/goals.js +3 -3
  176. package/lib/types/backends/codex/session/history.js +2 -2
  177. package/lib/types/backends/codex/session/images.js +8 -8
  178. package/lib/types/backends/codex/session/input.d.ts +6 -2
  179. package/lib/types/backends/codex/session/input.d.ts.map +1 -1
  180. package/lib/types/backends/codex/session/input.js +55 -13
  181. package/lib/types/backends/codex/session/plan-review.js +6 -6
  182. package/lib/types/backends/codex/session/session.d.ts.map +1 -1
  183. package/lib/types/backends/codex/session/session.js +100 -42
  184. package/lib/types/backends/codex/session/side-query.d.ts.map +1 -1
  185. package/lib/types/backends/codex/session/side-query.js +27 -9
  186. package/lib/types/backends/codex/session/state.d.ts +6 -1
  187. package/lib/types/backends/codex/session/state.d.ts.map +1 -1
  188. package/lib/types/backends/codex/session/subagents.js +5 -5
  189. package/lib/types/backends/codex/session/tasks.js +4 -4
  190. package/lib/types/backends/codex/text.d.ts +933 -0
  191. package/lib/types/backends/codex/text.d.ts.map +1 -0
  192. package/lib/types/backends/codex/text.js +313 -0
  193. package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
  194. package/lib/types/backends/codex/translate/items.js +7 -5
  195. package/lib/types/backends/codex/translate/live.d.ts.map +1 -1
  196. package/lib/types/backends/codex/translate/live.js +11 -8
  197. package/lib/types/backends/codex/translate/notices.js +10 -10
  198. package/lib/types/backends/codex/translate/question-reply.d.ts +11 -0
  199. package/lib/types/backends/codex/translate/question-reply.d.ts.map +1 -0
  200. package/lib/types/backends/codex/translate/question-reply.js +53 -0
  201. package/lib/types/backends/shared/channel-slug.d.ts +4 -0
  202. package/lib/types/backends/shared/channel-slug.d.ts.map +1 -0
  203. package/lib/types/backends/shared/channel-slug.js +25 -0
  204. package/lib/types/backends/shared/channel-tokens.d.ts.map +1 -1
  205. package/lib/types/backends/shared/channel-tokens.js +30 -23
  206. package/lib/types/{channel → backends/shared}/elicitation.d.ts +78 -21
  207. package/lib/types/backends/shared/elicitation.d.ts.map +1 -0
  208. package/lib/types/{channel → backends/shared}/elicitation.js +64 -66
  209. package/lib/types/backends/shared/image-size.d.ts +33 -0
  210. package/lib/types/backends/shared/image-size.d.ts.map +1 -0
  211. package/lib/types/backends/shared/image-size.js +134 -0
  212. package/lib/types/{utils → backends/shared}/jsonl.d.ts +5 -1
  213. package/lib/types/backends/shared/jsonl.d.ts.map +1 -0
  214. package/lib/types/{utils → backends/shared}/jsonl.js +5 -1
  215. package/lib/types/backends/shared/localized-text.d.ts +30 -0
  216. package/lib/types/backends/shared/localized-text.d.ts.map +1 -0
  217. package/lib/types/backends/shared/localized-text.js +24 -0
  218. package/lib/types/backends/shared/platform-text.d.ts +88 -0
  219. package/lib/types/backends/shared/platform-text.d.ts.map +1 -0
  220. package/lib/types/backends/shared/platform-text.js +33 -0
  221. package/lib/types/branding.d.ts +13 -0
  222. package/lib/types/branding.d.ts.map +1 -1
  223. package/lib/types/branding.js +18 -0
  224. package/lib/types/channel/channel-slug.d.ts +3 -1
  225. package/lib/types/channel/channel-slug.d.ts.map +1 -1
  226. package/lib/types/channel/channel-slug.js +3 -1
  227. package/lib/types/channel/projection.d.ts.map +1 -1
  228. package/lib/types/channel/projection.js +10 -0
  229. package/lib/types/channel/sanitize.d.ts +7 -0
  230. package/lib/types/channel/sanitize.d.ts.map +1 -1
  231. package/lib/types/channel/sanitize.js +9 -0
  232. package/lib/types/channel/usage.d.ts.map +1 -1
  233. package/lib/types/channel/usage.js +5 -0
  234. package/lib/types/commands.d.ts +15 -0
  235. package/lib/types/commands.d.ts.map +1 -1
  236. package/lib/types/commands.js +58 -10
  237. package/lib/types/components/AgentMessageComposer.d.ts.map +1 -1
  238. package/lib/types/components/AgentMessageComposer.js +3 -2
  239. package/lib/types/components/BtwPanel.d.ts.map +1 -1
  240. package/lib/types/components/BtwPanel.js +4 -2
  241. package/lib/types/components/Chat/JobCard.js +3 -3
  242. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  243. package/lib/types/components/CommandSuggestions.js +24 -7
  244. package/lib/types/components/ContextBarView.d.ts +5 -1
  245. package/lib/types/components/ContextBarView.d.ts.map +1 -1
  246. package/lib/types/components/ContextBarView.js +6 -3
  247. package/lib/types/components/ExtensionDialog.d.ts.map +1 -1
  248. package/lib/types/components/ExtensionDialog.js +2 -3
  249. package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
  250. package/lib/types/components/GoalTodoPanel.js +14 -3
  251. package/lib/types/components/InlineMathParagraph.js +1 -1
  252. package/lib/types/components/KernelPicker.d.ts.map +1 -1
  253. package/lib/types/components/KernelPicker.js +1 -1
  254. package/lib/types/components/LogoV2.d.ts +4 -1
  255. package/lib/types/components/LogoV2.d.ts.map +1 -1
  256. package/lib/types/components/LogoV2.js +14 -9
  257. package/lib/types/components/MarkdownTable.d.ts.map +1 -1
  258. package/lib/types/components/MarkdownTable.js +4 -3
  259. package/lib/types/components/MessageList.d.ts.map +1 -1
  260. package/lib/types/components/MessageList.js +109 -15
  261. package/lib/types/components/ModelPicker.d.ts +24 -31
  262. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  263. package/lib/types/components/ModelPicker.js +115 -40
  264. package/lib/types/components/PermissionsPicker.d.ts +10 -1
  265. package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
  266. package/lib/types/components/PermissionsPicker.js +24 -16
  267. package/lib/types/components/PluginInstallPane.d.ts +21 -0
  268. package/lib/types/components/PluginInstallPane.d.ts.map +1 -0
  269. package/lib/types/components/PluginInstallPane.js +84 -0
  270. package/lib/types/components/PluginManagePane.d.ts +21 -0
  271. package/lib/types/components/PluginManagePane.d.ts.map +1 -0
  272. package/lib/types/components/PluginManagePane.js +69 -0
  273. package/lib/types/components/PromptEditor.d.ts +3 -3
  274. package/lib/types/components/PromptInput.d.ts +21 -3
  275. package/lib/types/components/PromptInput.d.ts.map +1 -1
  276. package/lib/types/components/PromptInput.js +65 -121
  277. package/lib/types/components/SdkInstallWizard.d.ts +3 -1
  278. package/lib/types/components/SdkInstallWizard.d.ts.map +1 -1
  279. package/lib/types/components/SdkInstallWizard.js +8 -1
  280. package/lib/types/components/SearchBox.d.ts +13 -15
  281. package/lib/types/components/SearchBox.d.ts.map +1 -1
  282. package/lib/types/components/SearchBox.js +58 -27
  283. package/lib/types/components/SubagentCard.d.ts +13 -1
  284. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  285. package/lib/types/components/SubagentCard.js +27 -12
  286. package/lib/types/components/SubagentDashboard.d.ts +8 -1
  287. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  288. package/lib/types/components/SubagentDashboard.js +58 -16
  289. package/lib/types/components/ThemePicker.d.ts +1 -1
  290. package/lib/types/components/ThemePicker.d.ts.map +1 -1
  291. package/lib/types/components/ThemePicker.js +14 -11
  292. package/lib/types/components/Tooltip.js +1 -1
  293. package/lib/types/components/WorkingSpinner.js +1 -1
  294. package/lib/types/components/WorkspaceFlowPicker.d.ts.map +1 -1
  295. package/lib/types/components/WorkspaceFlowPicker.js +4 -3
  296. package/lib/types/components/composerImageTokens.d.ts +24 -0
  297. package/lib/types/components/composerImageTokens.d.ts.map +1 -0
  298. package/lib/types/components/composerImageTokens.js +37 -0
  299. package/lib/types/components/design-system/InputCaret.d.ts +7 -0
  300. package/lib/types/components/design-system/InputCaret.d.ts.map +1 -0
  301. package/lib/types/components/design-system/InputCaret.js +9 -0
  302. package/lib/types/components/design-system/ListItem.d.ts +13 -2
  303. package/lib/types/components/design-system/ListItem.d.ts.map +1 -1
  304. package/lib/types/components/design-system/ListItem.js +11 -5
  305. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  306. package/lib/types/components/design-system/ThemeProvider.js +6 -8
  307. package/lib/types/components/kernelCatalog.d.ts +55 -11
  308. package/lib/types/components/kernelCatalog.d.ts.map +1 -1
  309. package/lib/types/components/kernelCatalog.js +42 -23
  310. package/lib/types/components/launchpadActions.d.ts +4 -0
  311. package/lib/types/components/launchpadActions.d.ts.map +1 -1
  312. package/lib/types/components/launchpadActions.js +5 -4
  313. package/lib/types/components/launchpadLayout.d.ts +14 -1
  314. package/lib/types/components/launchpadLayout.d.ts.map +1 -1
  315. package/lib/types/components/launchpadLayout.js +38 -19
  316. package/lib/types/components/messages/TeamMessageBubble.d.ts +20 -0
  317. package/lib/types/components/messages/TeamMessageBubble.d.ts.map +1 -0
  318. package/lib/types/components/messages/TeamMessageBubble.js +15 -0
  319. package/lib/types/components/messages/UserPromptMessage.d.ts +4 -3
  320. package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
  321. package/lib/types/components/messages/UserPromptMessage.js +4 -3
  322. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  323. package/lib/types/components/questions/AskUserQuestionPanel.js +8 -3
  324. package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
  325. package/lib/types/components/questions/PlanReviewPanel.js +4 -3
  326. package/lib/types/components/questions/ProviderModelEditor.d.ts.map +1 -1
  327. package/lib/types/components/questions/ProviderModelEditor.js +3 -13
  328. package/lib/types/components/sessions/ForeignSessionRow.d.ts +3 -1
  329. package/lib/types/components/sessions/ForeignSessionRow.d.ts.map +1 -1
  330. package/lib/types/components/sessions/ForeignSessionRow.js +5 -2
  331. package/lib/types/components/sessions/SessionListRow.d.ts +3 -1
  332. package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
  333. package/lib/types/components/sessions/SessionListRow.js +5 -2
  334. package/lib/types/components/sidePanel/PanelBar.d.ts +1 -0
  335. package/lib/types/components/sidePanel/PanelBar.d.ts.map +1 -1
  336. package/lib/types/components/sidePanel/PanelBar.js +21 -17
  337. package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -1
  338. package/lib/types/components/sidePanel/PanelHost.js +5 -1
  339. package/lib/types/components/sidePanel/PanelStore.d.ts +8 -0
  340. package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
  341. package/lib/types/components/sidePanel/PanelStore.js +11 -0
  342. package/lib/types/components/sidePanel/SidePanelColumn.d.ts +1 -1
  343. package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
  344. package/lib/types/components/sidePanel/SidePanelColumn.js +15 -2
  345. package/lib/types/components/sidePanel/SidePanelLayout.d.ts +6 -4
  346. package/lib/types/components/sidePanel/SidePanelLayout.d.ts.map +1 -1
  347. package/lib/types/components/sidePanel/SidePanelLayout.js +33 -7
  348. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +7 -0
  349. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -1
  350. package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +4 -0
  351. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +7 -2
  352. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
  353. package/lib/types/components/sidePanel/btw/BtwComposer.js +28 -8
  354. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +2 -1
  355. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -1
  356. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +156 -21
  357. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +6 -2
  358. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -1
  359. package/lib/types/components/sidePanel/btw/BtwThreadScene.js +64 -16
  360. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +15 -5
  361. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
  362. package/lib/types/components/sidePanel/btw/BtwThreadView.js +101 -10
  363. package/lib/types/components/sidePanel/btw/threads.d.ts +18 -0
  364. package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -1
  365. package/lib/types/components/sidePanel/btw/threads.js +51 -0
  366. package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
  367. package/lib/types/components/sidePanel/builtinPanels.js +5 -1
  368. package/lib/types/components/sidePanel/companion/CompanionPanel.js +2 -2
  369. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +5 -1
  370. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -1
  371. package/lib/types/components/sidePanel/companion/SplashMascot.js +19 -4
  372. package/lib/types/components/sidePanel/companion/skins.d.ts +8 -0
  373. package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
  374. package/lib/types/components/sidePanel/companion/skins.js +57 -12
  375. package/lib/types/components/sidePanel/types.d.ts +7 -1
  376. package/lib/types/components/sidePanel/types.d.ts.map +1 -1
  377. package/lib/types/components/sidePanel/useSidePanel.d.ts +2 -0
  378. package/lib/types/components/sidePanel/useSidePanel.d.ts.map +1 -1
  379. package/lib/types/components/sidePanel/useSidePanel.js +11 -1
  380. package/lib/types/components/splashArtRows.d.ts +29 -0
  381. package/lib/types/components/splashArtRows.d.ts.map +1 -0
  382. package/lib/types/components/splashArtRows.js +31 -0
  383. package/lib/types/components/splashFonts.d.ts +24 -1
  384. package/lib/types/components/splashFonts.d.ts.map +1 -1
  385. package/lib/types/components/splashFonts.js +40 -5
  386. package/lib/types/components/teamRoster.d.ts +70 -0
  387. package/lib/types/components/teamRoster.d.ts.map +1 -0
  388. package/lib/types/components/teamRoster.js +78 -0
  389. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +3 -1
  390. package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -1
  391. package/lib/types/components/workspaces/HomeWorkspaceRow.js +5 -2
  392. package/lib/types/dsh-adapter/admission-loader.d.ts +102 -0
  393. package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -0
  394. package/lib/types/dsh-adapter/admission-loader.js +301 -0
  395. package/lib/types/dsh-adapter/agent-view.d.ts.map +1 -1
  396. package/lib/types/dsh-adapter/agent-view.js +3 -1
  397. package/lib/types/dsh-adapter/approvals.d.ts +7 -0
  398. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  399. package/lib/types/dsh-adapter/approvals.js +45 -1
  400. package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -1
  401. package/lib/types/dsh-adapter/backend/translate.js +71 -8
  402. package/lib/types/dsh-adapter/backend-admission.d.ts +64 -0
  403. package/lib/types/dsh-adapter/backend-admission.d.ts.map +1 -0
  404. package/lib/types/dsh-adapter/backend-admission.js +34 -0
  405. package/lib/types/dsh-adapter/backend-assembly.d.ts +31 -0
  406. package/lib/types/dsh-adapter/backend-assembly.d.ts.map +1 -0
  407. package/lib/types/dsh-adapter/backend-assembly.js +225 -0
  408. package/lib/types/dsh-adapter/backend-contribution.d.ts +62 -0
  409. package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -0
  410. package/lib/types/dsh-adapter/backend-contribution.js +78 -0
  411. package/lib/types/dsh-adapter/backend-registry.d.ts +136 -0
  412. package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -0
  413. package/lib/types/dsh-adapter/backend-registry.js +304 -0
  414. package/lib/types/dsh-adapter/backends.d.ts +67 -24
  415. package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
  416. package/lib/types/dsh-adapter/backends.generated.d.ts +12 -0
  417. package/lib/types/dsh-adapter/backends.generated.d.ts.map +1 -0
  418. package/lib/types/dsh-adapter/backends.generated.js +6 -0
  419. package/lib/types/dsh-adapter/backends.js +91 -46
  420. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  421. package/lib/types/dsh-adapter/bundled-presets.js +60 -3
  422. package/lib/types/dsh-adapter/channel/action-readiness.d.ts +2 -0
  423. package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
  424. package/lib/types/dsh-adapter/channel/action-readiness.js +9 -3
  425. package/lib/types/dsh-adapter/channel/agent-view-projection.js +2 -2
  426. package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
  427. package/lib/types/dsh-adapter/channel/background-action.js +8 -3
  428. package/lib/types/dsh-adapter/channel/binding-events.d.ts +17 -3
  429. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  430. package/lib/types/dsh-adapter/channel/binding-events.js +19 -46
  431. package/lib/types/dsh-adapter/channel/channel-host.d.ts +45 -0
  432. package/lib/types/dsh-adapter/channel/channel-host.d.ts.map +1 -0
  433. package/lib/types/dsh-adapter/channel/channel-host.js +1 -0
  434. package/lib/types/dsh-adapter/channel/command-completions.d.ts +5 -0
  435. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  436. package/lib/types/dsh-adapter/channel/command-completions.js +79 -6
  437. package/lib/types/dsh-adapter/channel/compaction.d.ts +7 -2
  438. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  439. package/lib/types/dsh-adapter/channel/compaction.js +100 -26
  440. package/lib/types/dsh-adapter/channel/composer-images.d.ts +4 -2
  441. package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
  442. package/lib/types/dsh-adapter/channel/composer-images.js +36 -5
  443. package/lib/types/dsh-adapter/channel/cordis-host.d.ts +14 -0
  444. package/lib/types/dsh-adapter/channel/cordis-host.d.ts.map +1 -0
  445. package/lib/types/dsh-adapter/channel/cordis-host.js +35 -0
  446. package/lib/types/dsh-adapter/channel/core/actions.d.ts +3 -3
  447. package/lib/types/dsh-adapter/channel/core/actions.d.ts.map +1 -1
  448. package/lib/types/dsh-adapter/channel/core/actions.js +15 -6
  449. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +10 -3
  450. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
  451. package/lib/types/dsh-adapter/channel/core/binding-feed.js +5 -1
  452. package/lib/types/dsh-adapter/channel/core/compose.d.ts +12 -28
  453. package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
  454. package/lib/types/dsh-adapter/channel/core/compose.js +330 -117
  455. package/lib/types/dsh-adapter/channel/core/files.d.ts +7 -2
  456. package/lib/types/dsh-adapter/channel/core/files.d.ts.map +1 -1
  457. package/lib/types/dsh-adapter/channel/core/files.js +1 -0
  458. package/lib/types/dsh-adapter/channel/core/host.d.ts +12 -6
  459. package/lib/types/dsh-adapter/channel/core/host.d.ts.map +1 -1
  460. package/lib/types/dsh-adapter/channel/core/host.js +69 -35
  461. package/lib/types/dsh-adapter/channel/core/local-actions.d.ts +5 -3
  462. package/lib/types/dsh-adapter/channel/core/local-actions.d.ts.map +1 -1
  463. package/lib/types/dsh-adapter/channel/core/local-actions.js +5 -2
  464. package/lib/types/dsh-adapter/channel/core/session-controls.js +2 -2
  465. package/lib/types/dsh-adapter/channel/core/session-switch.d.ts +7 -4
  466. package/lib/types/dsh-adapter/channel/core/session-switch.d.ts.map +1 -1
  467. package/lib/types/dsh-adapter/channel/core/session-switch.js +8 -4
  468. package/lib/types/dsh-adapter/channel/core/sessions.d.ts +1 -1
  469. package/lib/types/dsh-adapter/channel/core/sessions.d.ts.map +1 -1
  470. package/lib/types/dsh-adapter/channel/core/sessions.js +75 -16
  471. package/lib/types/dsh-adapter/channel/extensions.d.ts +4 -3
  472. package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
  473. package/lib/types/dsh-adapter/channel/extensions.js +109 -30
  474. package/lib/types/dsh-adapter/channel/input-delivery.d.ts +2 -2
  475. package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
  476. package/lib/types/dsh-adapter/channel/input-delivery.js +14 -5
  477. package/lib/types/dsh-adapter/channel/job-projection.d.ts +4 -0
  478. package/lib/types/dsh-adapter/channel/job-projection.d.ts.map +1 -1
  479. package/lib/types/dsh-adapter/channel/job-projection.js +205 -24
  480. package/lib/types/dsh-adapter/channel/mentions.d.ts +3 -3
  481. package/lib/types/dsh-adapter/channel/mentions.d.ts.map +1 -1
  482. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +7 -0
  483. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  484. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +235 -13
  485. package/lib/types/dsh-adapter/channel/model-actions.d.ts +5 -1
  486. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  487. package/lib/types/dsh-adapter/channel/model-actions.js +48 -29
  488. package/lib/types/dsh-adapter/channel/model-selection.d.ts +17 -0
  489. package/lib/types/dsh-adapter/channel/model-selection.d.ts.map +1 -0
  490. package/lib/types/dsh-adapter/channel/model-selection.js +109 -0
  491. package/lib/types/dsh-adapter/channel/model-switch.d.ts +12 -21
  492. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  493. package/lib/types/dsh-adapter/channel/model-switch.js +39 -102
  494. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  495. package/lib/types/dsh-adapter/channel/permissions.js +4 -1
  496. package/lib/types/dsh-adapter/channel/projection-helpers.d.ts.map +1 -1
  497. package/lib/types/dsh-adapter/channel/projection-helpers.js +2 -0
  498. package/lib/types/dsh-adapter/channel/projection.js +1 -1
  499. package/lib/types/dsh-adapter/channel/reports.d.ts +1 -1
  500. package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
  501. package/lib/types/dsh-adapter/channel/reports.js +11 -3
  502. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  503. package/lib/types/dsh-adapter/channel/session-fork.js +33 -20
  504. package/lib/types/dsh-adapter/channel/session-listing.d.ts +20 -0
  505. package/lib/types/dsh-adapter/channel/session-listing.d.ts.map +1 -0
  506. package/lib/types/dsh-adapter/channel/session-listing.js +51 -0
  507. package/lib/types/dsh-adapter/channel/session-metadata.d.ts +3 -1
  508. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  509. package/lib/types/dsh-adapter/channel/session-metadata.js +60 -30
  510. package/lib/types/dsh-adapter/channel/session-reset.js +2 -2
  511. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  512. package/lib/types/dsh-adapter/channel/session-resume.js +22 -8
  513. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  514. package/lib/types/dsh-adapter/channel/session-rewind.js +38 -24
  515. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  516. package/lib/types/dsh-adapter/channel/session-tree-actions.js +38 -24
  517. package/lib/types/dsh-adapter/channel/settings-host.d.ts +5 -2
  518. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  519. package/lib/types/dsh-adapter/channel/settings-host.js +136 -5
  520. package/lib/types/dsh-adapter/channel/state.d.ts +43 -1
  521. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  522. package/lib/types/dsh-adapter/channel/state.js +14 -1
  523. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  524. package/lib/types/dsh-adapter/channel/subagent-projection.js +84 -12
  525. package/lib/types/dsh-adapter/channel/task-completion.d.ts +6 -0
  526. package/lib/types/dsh-adapter/channel/task-completion.d.ts.map +1 -0
  527. package/lib/types/dsh-adapter/channel/task-completion.js +114 -0
  528. package/lib/types/dsh-adapter/channel/transcript.d.ts +8 -1
  529. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  530. package/lib/types/dsh-adapter/channel/transcript.js +20 -3
  531. package/lib/types/dsh-adapter/channel/upstream-retry.d.ts +81 -0
  532. package/lib/types/dsh-adapter/channel/upstream-retry.d.ts.map +1 -0
  533. package/lib/types/dsh-adapter/channel/upstream-retry.js +138 -0
  534. package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
  535. package/lib/types/dsh-adapter/channel/workspace-actions.js +9 -8
  536. package/lib/types/dsh-adapter/channel-ui.d.ts +3 -1
  537. package/lib/types/dsh-adapter/channel-ui.d.ts.map +1 -1
  538. package/lib/types/dsh-adapter/channel-ui.js +4 -2
  539. package/lib/types/dsh-adapter/channel.d.ts +2 -2
  540. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  541. package/lib/types/dsh-adapter/channel.js +19 -5
  542. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts +55 -0
  543. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts.map +1 -0
  544. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.js +96 -0
  545. package/lib/types/dsh-adapter/context-occupancy.d.ts +81 -4
  546. package/lib/types/dsh-adapter/context-occupancy.d.ts.map +1 -1
  547. package/lib/types/dsh-adapter/context-occupancy.js +108 -17
  548. package/lib/types/dsh-adapter/contract.d.ts +4 -4
  549. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  550. package/lib/types/dsh-adapter/contract.js +20 -5
  551. package/lib/types/dsh-adapter/effect-ledger.d.ts +7 -0
  552. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  553. package/lib/types/dsh-adapter/effect-ledger.js +8 -1
  554. package/lib/types/dsh-adapter/entry-slot.d.ts +38 -0
  555. package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -0
  556. package/lib/types/dsh-adapter/entry-slot.js +28 -0
  557. package/lib/types/dsh-adapter/fresh-agent.d.ts +22 -0
  558. package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -0
  559. package/lib/types/dsh-adapter/fresh-agent.js +226 -0
  560. package/lib/types/dsh-adapter/host-access.d.ts +16 -1
  561. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
  562. package/lib/types/dsh-adapter/host-access.js +148 -2
  563. package/lib/types/dsh-adapter/host-contract.d.ts +103 -0
  564. package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -0
  565. package/lib/types/dsh-adapter/host-contract.js +77 -0
  566. package/lib/types/dsh-adapter/host-dsh.d.ts +112 -0
  567. package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -0
  568. package/lib/types/dsh-adapter/host-dsh.js +481 -0
  569. package/lib/types/dsh-adapter/host-entry.d.ts +9 -0
  570. package/lib/types/dsh-adapter/host-entry.d.ts.map +1 -0
  571. package/lib/types/dsh-adapter/host-entry.js +253 -0
  572. package/lib/types/dsh-adapter/index.d.ts +53 -17
  573. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  574. package/lib/types/dsh-adapter/index.js +63 -9
  575. package/lib/types/dsh-adapter/install/executors.d.ts +44 -0
  576. package/lib/types/dsh-adapter/install/executors.d.ts.map +1 -0
  577. package/lib/types/dsh-adapter/install/executors.js +15 -0
  578. package/lib/types/dsh-adapter/install/pnpm-profile-add.d.ts +3 -0
  579. package/lib/types/dsh-adapter/install/pnpm-profile-add.d.ts.map +1 -0
  580. package/lib/types/dsh-adapter/install/pnpm-profile-add.js +150 -0
  581. package/lib/types/dsh-adapter/invariant.d.ts +7 -2
  582. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -1
  583. package/lib/types/dsh-adapter/invariant.js +6 -3
  584. package/lib/types/dsh-adapter/jobs.d.ts +7 -0
  585. package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
  586. package/lib/types/dsh-adapter/jobs.js +13 -0
  587. package/lib/types/dsh-adapter/lite-profile.d.ts +50 -0
  588. package/lib/types/dsh-adapter/lite-profile.d.ts.map +1 -0
  589. package/lib/types/dsh-adapter/lite-profile.js +49 -0
  590. package/lib/types/dsh-adapter/migrate/index.js +2 -2
  591. package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts +1 -1
  592. package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts.map +1 -1
  593. package/lib/types/dsh-adapter/migrate/parse/jsonl.js +4 -3
  594. package/lib/types/dsh-adapter/oauth/profiles.d.ts.map +1 -1
  595. package/lib/types/dsh-adapter/oauth/profiles.js +5 -1
  596. package/lib/types/dsh-adapter/panels.d.ts +7 -0
  597. package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
  598. package/lib/types/dsh-adapter/panels.js +41 -2
  599. package/lib/types/dsh-adapter/plugin-completions.d.ts +32 -0
  600. package/lib/types/dsh-adapter/plugin-completions.d.ts.map +1 -0
  601. package/lib/types/dsh-adapter/plugin-completions.js +80 -0
  602. package/lib/types/dsh-adapter/plugin-declaration.d.ts +119 -0
  603. package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -0
  604. package/lib/types/dsh-adapter/plugin-declaration.js +183 -0
  605. package/lib/types/dsh-adapter/plugin-feed.d.ts +94 -0
  606. package/lib/types/dsh-adapter/plugin-feed.d.ts.map +1 -0
  607. package/lib/types/dsh-adapter/plugin-feed.js +135 -0
  608. package/lib/types/dsh-adapter/plugin-guard.d.ts +115 -0
  609. package/lib/types/dsh-adapter/plugin-guard.d.ts.map +1 -0
  610. package/lib/types/dsh-adapter/plugin-guard.js +108 -0
  611. package/lib/types/dsh-adapter/plugin-host.d.ts +13 -2
  612. package/lib/types/dsh-adapter/plugin-host.d.ts.map +1 -1
  613. package/lib/types/dsh-adapter/plugin-host.js +34 -8
  614. package/lib/types/dsh-adapter/plugin-install.d.ts +160 -0
  615. package/lib/types/dsh-adapter/plugin-install.d.ts.map +1 -0
  616. package/lib/types/dsh-adapter/plugin-install.js +545 -0
  617. package/lib/types/dsh-adapter/plugin-manage.d.ts +178 -0
  618. package/lib/types/dsh-adapter/plugin-manage.d.ts.map +1 -0
  619. package/lib/types/dsh-adapter/plugin-manage.js +468 -0
  620. package/lib/types/dsh-adapter/plugin-manager.d.ts +144 -0
  621. package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -0
  622. package/lib/types/dsh-adapter/plugin-manager.js +83 -0
  623. package/lib/types/dsh-adapter/plugin.d.ts +50 -1
  624. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  625. package/lib/types/dsh-adapter/plugin.js +918 -234
  626. package/lib/types/dsh-adapter/plugins-info.d.ts +130 -8
  627. package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
  628. package/lib/types/dsh-adapter/plugins-info.js +469 -44
  629. package/lib/types/dsh-adapter/process-exit.d.ts +43 -0
  630. package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -0
  631. package/lib/types/dsh-adapter/process-exit.js +60 -0
  632. package/lib/types/dsh-adapter/root-dispose.d.ts +18 -0
  633. package/lib/types/dsh-adapter/root-dispose.d.ts.map +1 -0
  634. package/lib/types/dsh-adapter/root-dispose.js +28 -0
  635. package/lib/types/dsh-adapter/session-list-metadata.d.ts +20 -0
  636. package/lib/types/dsh-adapter/session-list-metadata.d.ts.map +1 -0
  637. package/lib/types/dsh-adapter/session-list-metadata.js +56 -0
  638. package/lib/types/dsh-adapter/session-projection-store.d.ts +66 -0
  639. package/lib/types/dsh-adapter/session-projection-store.d.ts.map +1 -0
  640. package/lib/types/dsh-adapter/session-projection-store.js +149 -0
  641. package/lib/types/dsh-adapter/session-seed.d.ts +11 -0
  642. package/lib/types/dsh-adapter/session-seed.d.ts.map +1 -0
  643. package/lib/types/dsh-adapter/session-seed.js +47 -0
  644. package/lib/types/dsh-adapter/sessions/list.d.ts +3 -1
  645. package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
  646. package/lib/types/dsh-adapter/sessions/list.js +11 -5
  647. package/lib/types/dsh-adapter/sessions/snapshot.d.ts +0 -2
  648. package/lib/types/dsh-adapter/sessions/snapshot.d.ts.map +1 -1
  649. package/lib/types/dsh-adapter/sessions/snapshot.js +7 -70
  650. package/lib/types/dsh-adapter/settingsEditor.js +2 -2
  651. package/lib/types/dsh-adapter/sideQuestion.d.ts +21 -0
  652. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  653. package/lib/types/dsh-adapter/sideQuestion.js +53 -0
  654. package/lib/types/dsh-adapter/startup-args.d.ts +2 -0
  655. package/lib/types/dsh-adapter/startup-args.d.ts.map +1 -1
  656. package/lib/types/dsh-adapter/startup-args.js +5 -0
  657. package/lib/types/dsh-adapter/subagents.d.ts +33 -1
  658. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  659. package/lib/types/dsh-adapter/subagents.js +112 -9
  660. package/lib/types/dsh-adapter/team-mode.d.ts +74 -0
  661. package/lib/types/dsh-adapter/team-mode.d.ts.map +1 -0
  662. package/lib/types/dsh-adapter/team-mode.js +188 -0
  663. package/lib/types/dsh-adapter/team-roster.d.ts +67 -0
  664. package/lib/types/dsh-adapter/team-roster.d.ts.map +1 -0
  665. package/lib/types/dsh-adapter/team-roster.js +136 -0
  666. package/lib/types/dsh-adapter/team-tools.d.ts +58 -0
  667. package/lib/types/dsh-adapter/team-tools.d.ts.map +1 -0
  668. package/lib/types/dsh-adapter/team-tools.js +208 -0
  669. package/lib/types/dsh-adapter/tui-settings.d.ts +57 -0
  670. package/lib/types/dsh-adapter/tui-settings.d.ts.map +1 -0
  671. package/lib/types/dsh-adapter/tui-settings.js +199 -0
  672. package/lib/types/dsh-adapter/types.d.ts +1 -1
  673. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  674. package/lib/types/effortPrefs.d.ts +6 -3
  675. package/lib/types/effortPrefs.d.ts.map +1 -1
  676. package/lib/types/effortPrefs.js +7 -4
  677. package/lib/types/hostEntryRoute.d.ts +18 -0
  678. package/lib/types/hostEntryRoute.d.ts.map +1 -0
  679. package/lib/types/hostEntryRoute.js +57 -0
  680. package/lib/types/i18n.d.ts +961 -1439
  681. package/lib/types/i18n.d.ts.map +1 -1
  682. package/lib/types/i18n.js +443 -387
  683. package/lib/types/ink/components/AlternateScreen.js +2 -2
  684. package/lib/types/ink/components/App.d.ts +1 -0
  685. package/lib/types/ink/components/App.d.ts.map +1 -1
  686. package/lib/types/ink/components/App.js +16 -4
  687. package/lib/types/ink/components/CursorDeclarationContext.d.ts +9 -0
  688. package/lib/types/ink/components/CursorDeclarationContext.d.ts.map +1 -1
  689. package/lib/types/ink/components/CursorDeclarationContext.js +2 -0
  690. package/lib/types/ink/components/ScrollBox.d.ts +9 -0
  691. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  692. package/lib/types/ink/components/ScrollBox.js +23 -0
  693. package/lib/types/ink/dom.d.ts.map +1 -1
  694. package/lib/types/ink/hooks/use-copy-on-select.d.ts +2 -2
  695. package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
  696. package/lib/types/ink/hooks/use-copy-on-select.js +13 -7
  697. package/lib/types/ink/hooks/use-declared-cursor.d.ts +11 -3
  698. package/lib/types/ink/hooks/use-declared-cursor.d.ts.map +1 -1
  699. package/lib/types/ink/hooks/use-declared-cursor.js +30 -10
  700. package/lib/types/ink/ink.d.ts +22 -17
  701. package/lib/types/ink/ink.d.ts.map +1 -1
  702. package/lib/types/ink/ink.js +151 -40
  703. package/lib/types/ink/kitty-graphics.d.ts +2 -0
  704. package/lib/types/ink/kitty-graphics.d.ts.map +1 -1
  705. package/lib/types/ink/kitty-graphics.js +6 -1
  706. package/lib/types/ink/node-cache.d.ts +2 -1
  707. package/lib/types/ink/node-cache.d.ts.map +1 -1
  708. package/lib/types/ink/output.d.ts +10 -4
  709. package/lib/types/ink/output.d.ts.map +1 -1
  710. package/lib/types/ink/output.js +14 -10
  711. package/lib/types/ink/render-node-to-output.d.ts +5 -2
  712. package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
  713. package/lib/types/ink/render-node-to-output.js +27 -9
  714. package/lib/types/ink/renderer.d.ts +1 -0
  715. package/lib/types/ink/renderer.d.ts.map +1 -1
  716. package/lib/types/ink/renderer.js +4 -3
  717. package/lib/types/ink/root.d.ts +4 -1
  718. package/lib/types/ink/root.d.ts.map +1 -1
  719. package/lib/types/ink/screen.d.ts +4 -2
  720. package/lib/types/ink/screen.d.ts.map +1 -1
  721. package/lib/types/ink/selection.d.ts +10 -1
  722. package/lib/types/ink/selection.d.ts.map +1 -1
  723. package/lib/types/ink/selection.js +94 -25
  724. package/lib/types/ink/stdin-handoff.d.ts +11 -0
  725. package/lib/types/ink/stdin-handoff.d.ts.map +1 -0
  726. package/lib/types/ink/stdin-handoff.js +20 -0
  727. package/lib/types/ink/styles.d.ts +2 -1
  728. package/lib/types/ink/styles.d.ts.map +1 -1
  729. package/lib/types/ink/terminal-image.d.ts +6 -4
  730. package/lib/types/ink/terminal-image.d.ts.map +1 -1
  731. package/lib/types/ink/terminal-image.js +16 -39
  732. package/lib/types/ink/terminal-notification.d.ts +8 -0
  733. package/lib/types/ink/terminal-notification.d.ts.map +1 -0
  734. package/lib/types/ink/terminal-notification.js +83 -0
  735. package/lib/types/ink/terminal.d.ts +9 -0
  736. package/lib/types/ink/terminal.d.ts.map +1 -1
  737. package/lib/types/ink/terminal.js +34 -1
  738. package/lib/types/ink/termio/csi.d.ts +11 -0
  739. package/lib/types/ink/termio/csi.d.ts.map +1 -1
  740. package/lib/types/ink/termio/csi.js +13 -0
  741. package/lib/types/ink/update-overflow-guard.d.ts +6 -0
  742. package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
  743. package/lib/types/ink/update-overflow-guard.js +17 -0
  744. package/lib/types/ink/wrap-text.d.ts +6 -0
  745. package/lib/types/ink/wrap-text.d.ts.map +1 -1
  746. package/lib/types/ink/wrap-text.js +17 -0
  747. package/lib/types/kernelPrefs.d.ts +130 -17
  748. package/lib/types/kernelPrefs.d.ts.map +1 -1
  749. package/lib/types/kernelPrefs.js +98 -35
  750. package/lib/types/math/inline-layout.d.ts +2 -0
  751. package/lib/types/math/inline-layout.d.ts.map +1 -1
  752. package/lib/types/math/inline-layout.js +5 -27
  753. package/lib/types/modelGroups.d.ts +15 -27
  754. package/lib/types/modelGroups.d.ts.map +1 -1
  755. package/lib/types/modelGroups.js +17 -31
  756. package/lib/types/modelPrefs.d.ts +5 -4
  757. package/lib/types/modelPrefs.d.ts.map +1 -1
  758. package/lib/types/modelPrefs.js +5 -4
  759. package/lib/types/modelRoute.d.ts +23 -9
  760. package/lib/types/modelRoute.d.ts.map +1 -1
  761. package/lib/types/modelRoute.js +25 -11
  762. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  763. package/lib/types/native-ts/yoga-layout/index.js +8 -1
  764. package/lib/types/permissionPrefs.d.ts +34 -0
  765. package/lib/types/permissionPrefs.d.ts.map +1 -0
  766. package/lib/types/permissionPrefs.js +61 -0
  767. package/lib/types/permissionPresetLabels.d.ts +25 -0
  768. package/lib/types/permissionPresetLabels.d.ts.map +1 -0
  769. package/lib/types/permissionPresetLabels.js +33 -0
  770. package/lib/types/plugin-host.d.ts +1 -0
  771. package/lib/types/plugin-host.d.ts.map +1 -1
  772. package/lib/types/preset-patch.d.ts +22 -0
  773. package/lib/types/preset-patch.d.ts.map +1 -0
  774. package/lib/types/preset-patch.js +14 -0
  775. package/lib/types/presetPrefs.d.ts +17 -3
  776. package/lib/types/presetPrefs.d.ts.map +1 -1
  777. package/lib/types/presetPrefs.js +20 -3
  778. package/lib/types/reload.d.ts +6 -10
  779. package/lib/types/reload.d.ts.map +1 -1
  780. package/lib/types/reload.js +14 -14
  781. package/lib/types/screens/Chat.d.ts +55 -16
  782. package/lib/types/screens/Chat.d.ts.map +1 -1
  783. package/lib/types/screens/Chat.js +742 -280
  784. package/lib/types/screens/Launchpad.d.ts +33 -17
  785. package/lib/types/screens/Launchpad.d.ts.map +1 -1
  786. package/lib/types/screens/Launchpad.js +256 -78
  787. package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
  788. package/lib/types/screens/SessionSupervisor.js +53 -12
  789. package/lib/types/screens/Settings.d.ts.map +1 -1
  790. package/lib/types/screens/Settings.js +7 -0
  791. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  792. package/lib/types/screens/StatusLine.js +24 -7
  793. package/lib/types/screens/StatusMetrics.d.ts +46 -1
  794. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  795. package/lib/types/screens/StatusMetrics.js +72 -0
  796. package/lib/types/screens/chat/useKernelPicker.d.ts +8 -4
  797. package/lib/types/screens/chat/useKernelPicker.d.ts.map +1 -1
  798. package/lib/types/screens/chat/useKernelPicker.js +61 -21
  799. package/lib/types/screens/chat/useModelPicker.d.ts +42 -0
  800. package/lib/types/screens/chat/useModelPicker.d.ts.map +1 -0
  801. package/lib/types/screens/chat/useModelPicker.js +182 -0
  802. package/lib/types/screens/chat/usePluginWriteFlow.d.ts +68 -0
  803. package/lib/types/screens/chat/usePluginWriteFlow.d.ts.map +1 -0
  804. package/lib/types/screens/chat/usePluginWriteFlow.js +92 -0
  805. package/lib/types/screens/chatOverlay.d.ts +30 -5
  806. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  807. package/lib/types/screens/chatOverlay.js +0 -1
  808. package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.d.ts +4 -1
  809. package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.d.ts.map +1 -1
  810. package/lib/types/screens/sessionSupervisor/ForeignSessionPanes.js +26 -5
  811. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +1 -1
  812. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
  813. package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +51 -29
  814. package/lib/types/sessionHistory.d.ts +5 -0
  815. package/lib/types/sessionHistory.d.ts.map +1 -1
  816. package/lib/types/sessionHistory.js +5 -0
  817. package/lib/types/sessionModes.d.ts +5 -3
  818. package/lib/types/sessionModes.d.ts.map +1 -1
  819. package/lib/types/sessionModes.js +9 -3
  820. package/lib/types/sessions/listSnapshot.d.ts +6 -0
  821. package/lib/types/sessions/listSnapshot.d.ts.map +1 -0
  822. package/lib/types/sessions/listSnapshot.js +67 -0
  823. package/lib/types/settings/definitions.d.ts +50 -0
  824. package/lib/types/settings/definitions.d.ts.map +1 -1
  825. package/lib/types/settings/definitions.js +42 -8
  826. package/lib/types/terminal-utils/cjk-emphasis.d.ts +28 -0
  827. package/lib/types/terminal-utils/cjk-emphasis.d.ts.map +1 -0
  828. package/lib/types/terminal-utils/cjk-emphasis.js +31 -0
  829. package/lib/types/terminal-utils/markdown.d.ts +3 -1
  830. package/lib/types/terminal-utils/markdown.d.ts.map +1 -1
  831. package/lib/types/terminal-utils/markdown.js +7 -2
  832. package/lib/types/theme.d.ts +29 -12
  833. package/lib/types/theme.d.ts.map +1 -1
  834. package/lib/types/theme.js +310 -23
  835. package/lib/types/themeCatalog.d.ts.map +1 -1
  836. package/lib/types/themeCatalog.js +21 -2
  837. package/lib/types/tips.js +4 -4
  838. package/lib/types/tuiSettingsFile.d.ts +56 -0
  839. package/lib/types/tuiSettingsFile.d.ts.map +1 -0
  840. package/lib/types/tuiSettingsFile.js +206 -0
  841. package/lib/types/ui.d.ts +2 -0
  842. package/lib/types/ui.d.ts.map +1 -1
  843. package/lib/types/ui.js +2 -0
  844. package/lib/types/update.d.ts +72 -26
  845. package/lib/types/update.d.ts.map +1 -1
  846. package/lib/types/update.js +131 -43
  847. package/lib/types/utils/bmp.d.ts +7 -0
  848. package/lib/types/utils/bmp.d.ts.map +1 -1
  849. package/lib/types/utils/bmp.js +27 -0
  850. package/lib/types/utils/bootTrace.d.ts +2 -0
  851. package/lib/types/utils/bootTrace.d.ts.map +1 -0
  852. package/lib/types/utils/bootTrace.js +20 -0
  853. package/lib/types/utils/clipboard.d.ts.map +1 -1
  854. package/lib/types/utils/clipboard.js +11 -3
  855. package/lib/types/utils/credentials.d.ts +14 -2
  856. package/lib/types/utils/credentials.d.ts.map +1 -1
  857. package/lib/types/utils/credentials.js +34 -11
  858. package/lib/types/utils/imageResize.d.ts +10 -20
  859. package/lib/types/utils/imageResize.d.ts.map +1 -1
  860. package/lib/types/utils/imageResize.js +61 -134
  861. package/lib/types/utils/inputPaste.d.ts +2 -2
  862. package/lib/types/utils/inputPaste.js +2 -2
  863. package/lib/types/utils/pastedImagePath.d.ts +5 -0
  864. package/lib/types/utils/pastedImagePath.d.ts.map +1 -1
  865. package/lib/types/utils/pastedImagePath.js +33 -0
  866. package/lib/types/utils/paths.d.ts +11 -0
  867. package/lib/types/utils/paths.d.ts.map +1 -1
  868. package/lib/types/utils/paths.js +13 -0
  869. package/package.json +150 -114
  870. package/presets/winbash.mjs +716 -0
  871. package/tui-profile/feed/README.md +63 -0
  872. package/tui-profile/feed/first-party.json +10 -0
  873. package/tui-profile/protocols/profile-definitions.d.ts +1 -0
  874. package/tui-profile/protocols/profile-definitions.js +14 -0
  875. package/tui-profile/protocols/tui-contributions.d.ts +55 -0
  876. package/tui-profile/protocols/tui-contributions.js +141 -0
  877. package/tui-profile/registry/contracts/backend-v1alpha1.json +13 -0
  878. package/tui-profile/registry/registry-0.15.json +12 -0
  879. package/lib/types/backends/claude/install.d.ts +0 -15
  880. package/lib/types/backends/claude/install.d.ts.map +0 -1
  881. package/lib/types/backends/claude/install.js +0 -91
  882. package/lib/types/channel/elicitation.d.ts.map +0 -1
  883. package/lib/types/dsh-adapter/channel/session-lineage.d.ts +0 -42
  884. package/lib/types/dsh-adapter/channel/session-lineage.d.ts.map +0 -1
  885. package/lib/types/dsh-adapter/channel/session-lineage.js +0 -51
  886. package/lib/types/utils/jsonl.d.ts.map +0 -1
@@ -4,24 +4,24 @@ import { t, getLang, setLang, isLang, writeLangPref, readLangPref, subscribeLang
4
4
  import { checkForTuiUpdate, installedTuiVersion } from '../update.js';
5
5
  import { installedKernelVersion } from '../dsh-adapter/contract.js';
6
6
  import { readThemePref } from '../themePrefs.js';
7
- import { readPresetPref } from '../presetPrefs.js';
7
+ import { presetOverrideFromEnv, readPresetPref } from '../presetPrefs.js';
8
8
  import { readModelPref } from '../modelPrefs.js';
9
9
  import { readActivityFrames } from '../activityPrefs.js';
10
10
  import { envThemeOverride } from '../components/design-system/ThemeProvider.js';
11
11
  import { resolveBrand, setActiveBrand } from '../branding.js';
12
12
  import { hasPath } from '../dsh-adapter/settingsEditor.js';
13
13
  import { planReload } from '../reload.js';
14
- import { AlternateScreen, Box, Image, Text, useInput, ScrollBox, useTheme, useTerminalSize } from '../ui.js';
14
+ import { AlternateScreen, Box, Image, Text, InputCaret, useInput, ScrollBox, useTheme, useTerminalSize } from '../ui.js';
15
15
  import { usePageInset } from '../components/PageMargin.js';
16
16
  import { POINTER } from '../terminal-utils/figures.js';
17
+ import { previousCodePoint } from '../components/AgentMessageComposer.js';
17
18
  import { isPlainReturnInput } from '../utils/modifiers.js';
18
19
  import { actionMatches, effectiveComboDisplay, primaryComboString } from '../utils/keymap.js';
19
20
  import { formatTokens } from '../terminal-utils/format.js';
20
21
  import { formatClock } from '../trajectory/format.js';
21
22
  import { homeDir } from '../utils/paths.js';
22
23
  import { execFileNoThrow } from '../utils/execFileNoThrow.js';
23
- import { cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
24
- import { deriveModelGroups, modelPickerLanding, recentCatalogModels, RECENTS_GROUP_PROVIDER, } from '../modelGroups.js';
24
+ import { cleanBlockLines, cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
25
25
  import { readModelRecents, recordModelUse } from '../modelRecents.js';
26
26
  import { WORKING_GATE_NOTICES } from '../commands.js';
27
27
  import { TuiDialogStore } from '../dsh-adapter/dialogs.js';
@@ -37,6 +37,7 @@ const MATH_PREVIEW_MAX_COLUMNS = 480;
37
37
  const MATH_PREVIEW_MAX_ROWS = 64;
38
38
  import { runOAuthLogin, runProviderWizard } from '../dsh-adapter/providerWizard.js';
39
39
  import { useKernelPicker } from './chat/useKernelPicker.js';
40
+ import { useModelPicker } from './chat/useModelPicker.js';
40
41
  import { useBackendChannels } from './chat/useBackendChannels.js';
41
42
  import { backendModeStatus as modeStatus, backendPermissionCommand, parseMcpCommand } from './chat/backendCommands.js';
42
43
  import { PermissionStore } from '../channel/permissions.js';
@@ -60,11 +61,12 @@ import { ScrollbarGutter } from '../components/ScrollbarGutter.js';
60
61
  import { normalizeScrollGutter } from '../tuiDisplayPrefs.js';
61
62
  import { OverlayAbove } from '../components/OverlayAbove.js';
62
63
  import { TooltipLayer } from '../components/Tooltip.js';
63
- import { PromptInput } from '../components/PromptInput.js';
64
+ import { PromptInput, composerImageRefsForText } from '../components/PromptInput.js';
64
65
  import { turnUsageParts } from '../components/TurnUsageRow.js';
65
66
  import { AgentTranscriptScene } from './AgentTranscriptScene.js';
66
67
  import { agentViewStore } from '../components/sidePanel/agentViewStore.js';
67
68
  import { agentComposeTargetOf } from '../components/messages/agentTeam.js';
69
+ import { resolveBindingGeneration } from '../components/promptDraftCache.js';
68
70
  import { PromptEditorLayer, usePromptEditorOpen } from '../components/PromptEditor.js';
69
71
  import { GoalTodoPanel } from '../components/GoalTodoPanel.js';
70
72
  import { useSidePanel } from '../components/sidePanel/useSidePanel.js';
@@ -105,8 +107,13 @@ import { PermissionsPicker } from '../components/PermissionsPicker.js';
105
107
  import { ModePicker } from '../components/ModePicker.js';
106
108
  import { KernelPicker } from '../components/KernelPicker.js';
107
109
  import { SdkInstallWizard } from '../components/SdkInstallWizard.js';
110
+ import { PluginInstallPane } from '../components/PluginInstallPane.js';
111
+ import { PluginManagePane } from '../components/PluginManagePane.js';
112
+ import { teamMemberCounts } from '../components/teamRoster.js';
113
+ import { usePluginWriteFlow } from './chat/usePluginWriteFlow.js';
108
114
  import { ChannelPicker } from '../components/ChannelPicker.js';
109
115
  import { modeDisplayName } from '../sessionModes.js';
116
+ import { PERMISSION_PRESET_AUTO, permissionPresetLabel } from '../permissionPresetLabels.js';
110
117
  import { PlanPicker } from '../components/PlanPicker.js';
111
118
  import { LangPicker } from '../components/LangPicker.js';
112
119
  import { ThemePicker, getThemeOptions } from '../components/ThemePicker.js';
@@ -142,12 +149,10 @@ import { Launchpad, launchpadVisible } from './Launchpad.js';
142
149
  import { resolveLaunchpadActions } from '../components/launchpadActions.js';
143
150
  import { Onboarding } from './Onboarding.js';
144
151
  import { appendHistory } from '../history.js';
145
- import { isHiddenCommandName, isLocalCommandName, parseCommandName } from '../commands.js';
152
+ import { isBootSafeCommand, isHiddenCommandName, isLocalCommandName, isUnavailableLocalCommand, parseCommandName } from '../commands.js';
146
153
  import { extendTrajectory, projectWave } from '../dsh-adapter/trajectory/index.js';
147
154
  import { miniWakeWidth } from '../components/trajectory/MiniWake.js';
148
155
  import { readTrajectorySeen, writeTrajectorySeen } from '../trajectoryPrefs.js';
149
- import { LoadingState } from '../components/design-system/LoadingState.js';
150
- import { Pane } from '../components/design-system/Pane.js';
151
156
  import { loadHistory } from '../history.js';
152
157
  import { formatLoadedContextReport } from '../utils/loaded-context.js';
153
158
  import { NO_OVERLAY, chatOverlayReducer, dialogOverlayVisible, wrapIndex, } from './chatOverlay.js';
@@ -171,6 +176,10 @@ const STATUS_VIEW_UI = Object.freeze({
171
176
  /** Shared empty snapshot for hosts whose channel has no event log. */
172
177
  const NO_EVENTS = [];
173
178
  const COMMAND_RESULT_CELLS = 200;
179
+ /** Per-line width budget for a transcript block (`/plugins`, `/goal`): much
180
+ * wider than COMMAND_RESULT_CELLS, whose 200-cell single-line rule cannot
181
+ * carry a full goal objective. Still a bound, not "no limit". */
182
+ const LOCAL_BLOCK_CELLS = 4000;
174
183
  /** Ceiling for one `dsh-tui migrate` child run. Discovery parses every source
175
184
  * file, but a healthy import of thousands of conversations finishes well
176
185
  * inside this; without a cap a wedged child would hang the loop forever. */
@@ -209,11 +218,24 @@ function cleanCommandError(error) {
209
218
  return '';
210
219
  }
211
220
  }
221
+ /** Picking the experimental `auto` preset from the picker asks first, unless
222
+ * the session already sits on it. A typed `/permission auto` does not. */
223
+ function needsAutoConfirm(snapshot, value) {
224
+ return value === PERMISSION_PRESET_AUTO && snapshot.autoConfirmed !== true;
225
+ }
226
+ /** The current identity's display name, localized like the picker rows. */
227
+ function currentPermissionName(snapshot) {
228
+ const current = snapshot.current;
229
+ if (current === undefined)
230
+ return undefined;
231
+ return current.kind === 'preset' ? permissionPresetLabel(current) : current.name;
232
+ }
212
233
  function clonePermissionPresetSnapshot(snapshot) {
213
234
  return {
214
235
  availability: snapshot.availability,
215
236
  options: snapshot.options.map(option => ({ ...option })),
216
237
  ...(snapshot.current === undefined ? {} : { current: { ...snapshot.current } }),
238
+ ...(snapshot.autoConfirmed === true ? { autoConfirmed: true } : {}),
217
239
  };
218
240
  }
219
241
  /** Row kinds the message-selection cursor can land on. */
@@ -302,12 +324,14 @@ let fallbackStatusStore;
302
324
  let fallbackActivityStore;
303
325
  const noCouponSubscription = () => () => undefined;
304
326
  const noCouponSnapshot = () => null;
327
+ /** Stable identity for hosts that supply no kernel entries (bare embeds, tests). */
328
+ const EMPTY_KERNEL_ENTRIES = [];
305
329
  /** Identity of one caret-preview dismissal: the token (its title) on the
306
330
  * image, so the same image staged twice is dismissed per token. */
307
331
  function peekKey(image, title) {
308
332
  return `${title ?? ''} ${image.id}`;
309
333
  }
310
- export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, onSwitchBackend, onRestartFreshSession, onProbeKernels, onResolveSdkInstallTarget, onStartSdkInstall, onCheckPnpm, sdkInstallPinned, kernelPinned, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, launchpadOnBoot, onboardingOnBoot, starPrompt, }) {
334
+ export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, onSwitchBackend, onRestartFreshSession, onProbeKernels, kernelEntries = EMPTY_KERNEL_ENTRIES, onResolveSdkInstall, onPluginInstall, onPluginManage, onTeamCommand, kernelPinned, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, launchpadOnBoot, onboardingOnBoot, starPrompt, }) {
311
335
  const writeRaw = React.useContext(TerminalWriteContext);
312
336
  // Re-render whenever the channel mutates; rows/status are read fresh below.
313
337
  // DEFAULT lane on purpose (useExternalVersion): the channel version bumps
@@ -423,35 +447,72 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
423
447
  permissionOverlayFocusRef.current = null;
424
448
  }
425
449
  }, [overlay]);
450
+ // The preset registry and the session's current preset can change while
451
+ // the picker is open (the experimental `auto` preset registers or leaves
452
+ // live; another surface switches the preset; a session adopt moves to a
453
+ // fresh log). Reopen on the live snapshot, keeping the focused preset; a
454
+ // confirmation whose preset left drops back to the list. The channel
455
+ // memoizes the snapshot, so an unchanged roster, current identity and
456
+ // `autoConfirmed` flag are the same object and the resync stops there.
457
+ const permissionResyncRef = React.useRef(null);
458
+ React.useEffect(() => {
459
+ if (overlay.kind !== 'permission') {
460
+ permissionResyncRef.current = null;
461
+ return;
462
+ }
463
+ let live;
464
+ try {
465
+ live = channel.permissionPresets();
466
+ }
467
+ catch {
468
+ return;
469
+ }
470
+ const seen = permissionResyncRef.current;
471
+ if (seen?.overlay === overlay && seen.live === live)
472
+ return;
473
+ permissionResyncRef.current = { overlay, live };
474
+ const values = (snapshot) => snapshot.options.map(option => option.value).join('\n');
475
+ // A roster value change is the obvious case; the current identity and the
476
+ // session-scoped `autoConfirmed` flag can also move without changing the
477
+ // option values (another surface switches the preset, a session adopt
478
+ // lands, the auto preset leaves after a confirmation). Refresh on either,
479
+ // so `needsAutoConfirm` never reads a stale flag from another session.
480
+ if (values(live) === values(overlay.snapshot)
481
+ && live.availability === overlay.snapshot.availability
482
+ && live.current?.value === overlay.snapshot.current?.value
483
+ && live.current?.kind === overlay.snapshot.current?.kind
484
+ && live.autoConfirmed === overlay.snapshot.autoConfirmed)
485
+ return;
486
+ if (live.availability === 'unavailable' || live.options.length === 0) {
487
+ dispatchOverlay({ type: 'close-if', kind: 'permission' });
488
+ return;
489
+ }
490
+ const focusIndex = permissionOverlayFocusRef.current?.overlay === overlay
491
+ ? permissionOverlayFocusRef.current.index
492
+ : overlay.index;
493
+ const focused = overlay.confirm === true ? PERMISSION_PRESET_AUTO : overlay.snapshot.options[focusIndex]?.value;
494
+ const liveCurrent = live.current?.kind === 'preset' ? live.current.value : undefined;
495
+ const index = [focused, liveCurrent]
496
+ .map(value => live.options.findIndex(option => option.value === value))
497
+ .find(found => found >= 0) ?? Math.min(1, live.options.length - 1);
498
+ const confirm = overlay.confirm === true && live.options.some(option => option.value === PERMISSION_PRESET_AUTO);
499
+ if (overlay.confirm === true && !confirm)
500
+ channel.notify(t('permission-auto-unavailable'), { color: 'warning' });
501
+ dispatchOverlay({
502
+ type: 'open-if',
503
+ overlay: { kind: 'permission', index, snapshot: clonePermissionPresetSnapshot(live), ...(confirm ? { confirm } : {}) },
504
+ when: ['permission'],
505
+ });
506
+ });
426
507
  const [models, setModels] = React.useState([]);
427
- /** Provider display identities for the /model group level; refreshed alongside `models`. */
508
+ const [modelsLoading, setModelsLoading] = React.useState(false);
509
+ const modelCatalogGeneration = React.useRef(0);
510
+ /** Provider display identities for the /model tabs; refreshed alongside `models`. */
428
511
  const [providerInfos, setProviderInfos] = React.useState([]);
429
512
  /** /model 最近使用分组:成功切换即记录(去重置顶,上限 10),重启保留。 */
430
- // Recents are per backend: a Claude session's picks never evict the DSH list.
513
+ const modelProviderTabs = channel.backendCapabilities?.modelRoutes !== 'backend';
431
514
  const recentsBackend = channel.backendCapabilities?.backendId;
432
- const [modelRecents, setModelRecents] = React.useState(() => readModelRecents(undefined, recentsBackend));
433
- /** Two-level /model: the drilled-in provider route; undefined = group level.
434
- * Reset on open; stale ids resolve back to the group level via `activeModelGroup`. */
435
- const [modelGroup, setModelGroup] = React.useState(undefined);
436
- /** True while the picker sits in the single-provider fast path (drilled in
437
- * at open, the group level never shown): Esc closes directly and no back
438
- * hint renders — a pinned recents pseudo-group must not fake a two-level
439
- * walk the user never saw (issue #527 regression: repro-picker-windowing). */
440
- const [modelPickerDirect, setModelPickerDirect] = React.useState(false);
441
- /** Group rows over the current catalog, first-appearance (registry) order,
442
- * with the pinned recents pseudo-group first when any entry is catalogued. */
443
- const modelGroups = React.useMemo(() => deriveModelGroups(models, providerInfos, modelRecents), [models, providerInfos, modelRecents]);
444
- /** The drilled-in group, but only while it still exists in the catalog. */
445
- const activeModelGroup = modelGroup !== undefined && modelGroups.some(group => group.provider === modelGroup)
446
- ? modelGroup
447
- : undefined;
448
- const groupModels = React.useMemo(() => {
449
- if (activeModelGroup === undefined)
450
- return [];
451
- if (activeModelGroup === RECENTS_GROUP_PROVIDER)
452
- return recentCatalogModels(modelRecents, models);
453
- return models.filter(model => model.provider === activeModelGroup);
454
- }, [models, modelRecents, activeModelGroup]);
515
+ const [modelRecents, setModelRecents] = React.useState(() => modelProviderTabs ? readModelRecents(undefined, recentsBackend) : []);
455
516
  /** Switch + record: every successful switch feeds the /model recents group
456
517
  * (picker Enter/click, `/model provider/id`, the wizard's live switch,
457
518
  * and /reload's applied model all ride this one path). */
@@ -463,10 +524,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
463
524
  return ok;
464
525
  if (name !== undefined)
465
526
  channel.notify(t('model-switched', { name }));
466
- setModelRecents(recordModelUse({ provider, id }, undefined, recentsBackend));
527
+ if (modelProviderTabs)
528
+ setModelRecents(recordModelUse({ provider, id }, undefined, recentsBackend));
467
529
  return ok;
468
530
  });
469
531
  };
532
+ const modelPicker = useModelPicker({
533
+ channel, models, providers: providerInfos, recents: modelProviderTabs ? modelRecents : undefined, open: overlay.kind === 'model',
534
+ onCancel: () => dispatchOverlay({ type: 'close-if', kind: 'model' }),
535
+ onPick: (model, effort) => {
536
+ dispatchOverlay({ type: 'close-if', kind: 'model' });
537
+ void switchModelRecorded(model.provider, model.id, model.name).then(ok => {
538
+ // Validate/apply on the adopted route; a refused switch leaves both
539
+ // the live effort and its persisted preference untouched.
540
+ if (ok && effort !== undefined)
541
+ return channel.setEffort(effort);
542
+ });
543
+ },
544
+ });
470
545
  /** `/skills` 技能目录(issue #204):null = 注册表快照在途。 */
471
546
  const [skillsList, setSkillsList] = React.useState(null);
472
547
  /**
@@ -496,7 +571,13 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
496
571
  // 整屏」,浏览器必须提前藏在下面;现在整屏(会话/设置/任务面板)盖在
497
572
  // 落地页**之上**、Esc 退回落地页,按需打开即可——boot 时同时为真反而会
498
573
  // 让浏览器盖住落地页(渲染顺序见各 early-return)。恢复重挂同样不开它。
499
- const [supervisorOpen, setSupervisorOpen] = React.useState(openHomeOnBoot === true && launchpadOnBoot !== true && !recoveryRemountOnBoot);
574
+ // A channel still starting its session (in-process DSH kernel) holds the two
575
+ // DSH boot screens (home, guide) until `ready`; the effect after
576
+ // `settingsOpen` opens them then.
577
+ const heldBootScreensRef = React.useRef(channel.ready === false && !recoveryRemountOnBoot
578
+ ? { home: openHomeOnBoot === true && launchpadOnBoot !== true, onboarding: onboardingOnBoot === true }
579
+ : undefined);
580
+ const [supervisorOpen, setSupervisorOpen] = React.useState(openHomeOnBoot === true && launchpadOnBoot !== true && !recoveryRemountOnBoot && channel.ready !== false);
500
581
  /**
501
582
  * The launchpad: the landing page every ordinary launch starts on.
502
583
  *
@@ -514,6 +595,40 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
514
595
  const [launchpadDraft, setLaunchpadDraft] = React.useState('');
515
596
  const [launchpadCaret, setLaunchpadCaret] = React.useState(0);
516
597
  const [launchpadFocus, setLaunchpadFocus] = React.useState(-1);
598
+ const launchpadImagesRef = React.useRef(new Map());
599
+ const changeLaunchpadDraft = (text, cursor) => {
600
+ const live = new Set(composerImageRefsForText(text, launchpadImagesRef.current).map(image => image.token));
601
+ for (const [token, stageId] of launchpadImagesRef.current) {
602
+ if (live.has(token))
603
+ continue;
604
+ launchpadImagesRef.current.delete(token);
605
+ channel.discardStagedImage(stageId);
606
+ }
607
+ setLaunchpadDraft(text);
608
+ setLaunchpadCaret(cursor);
609
+ };
610
+ const launchpadBindingGeneration = resolveBindingGeneration(channel);
611
+ // Capture the image epoch with each session binding. Automatic startup keeps
612
+ // it; explicit replacement revokes it before publishing the new binding.
613
+ const composerImageGeneration = channel.stagedImageGeneration?.() ?? 0;
614
+ const launchpadSessionRef = React.useRef({ id: channel.agentId, imageGeneration: composerImageGeneration });
615
+ const discardLaunchpadImages = () => {
616
+ for (const stageId of launchpadImagesRef.current.values())
617
+ channel.discardStagedImage(stageId);
618
+ launchpadImagesRef.current.clear();
619
+ };
620
+ // Lifetime cleanup is separate from binding changes: startup adoption keeps
621
+ // the same draft, including the capabilities behind its image tokens.
622
+ React.useEffect(() => discardLaunchpadImages, [channel]);
623
+ React.useEffect(() => {
624
+ const previous = launchpadSessionRef.current;
625
+ launchpadSessionRef.current = { id: channel.agentId, imageGeneration: composerImageGeneration };
626
+ if (previous.id === '' && channel.agentId !== '' && previous.imageGeneration === composerImageGeneration)
627
+ return;
628
+ setLaunchpadDraft('');
629
+ setLaunchpadCaret(0);
630
+ discardLaunchpadImages();
631
+ }, [channel, channel.agentId, launchpadBindingGeneration]);
517
632
  /**
518
633
  * 「整屏盖启动页」的显式授权(第七版防御位,用户实测回归:启动页一闪而过
519
634
  * 被顶掉)。整屏分支排在落地页**之前**,任何一处状态在开机后被异步置真
@@ -555,7 +670,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
555
670
  * settings / help 的 early-return 排在两个界面**之后**:不收掉当前界面就是
556
671
  * "点了没反应",状态还滞留着、等界面关掉才突然弹出来。默认收,白名单只留给覆盖层。
557
672
  */
558
- const overlayCommandNames = React.useMemo(() => new Set(['model', 'effort', 'plan', 'preset', 'permission', 'kernel']), []);
673
+ const overlayCommandNames = React.useMemo(() => new Set(['model', 'effort', 'plan', 'preset', 'permission', 'kernel', 'dsh', 'codex', 'claude']), []);
559
674
  /**
560
675
  * 打开**整屏界面**的命令(第七版):从落地页触发这些命令时**不收掉落地页**
561
676
  * ——整屏盖在落地页之上渲染(它们的 early-return 排在落地页分支之前),
@@ -580,59 +695,80 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
580
695
  setLaunchpadUpdateAvailable(update !== undefined);
581
696
  }).catch(() => undefined);
582
697
  }, [launchpadShown]);
583
- const canInstallSdk = onResolveSdkInstallTarget !== undefined && onStartSdkInstall !== undefined
584
- && onCheckPnpm !== undefined && sdkInstallPinned !== undefined;
585
- const { currentId: kernelCurrentId, options: kernelOptions, open: openKernelPicker, pick: pickKernel, reprobe: reprobeKernels } = useKernelPicker({
586
- channel, kernelVersion, launchpadShown, onProbeKernels, onSwitchBackend, canInstallSdk, dispatchOverlay,
698
+ const canInstallSdk = onResolveSdkInstall !== undefined;
699
+ const { currentId: kernelCurrentId, options: kernelOptions, open: openKernelPicker, pick: pickKernel, pickById: pickKernelById, reprobe: reprobeKernels } = useKernelPicker({
700
+ channel, kernelVersion, kernelEntries, launchpadShown, onProbeKernels, onSwitchBackend, canInstallSdk, dispatchOverlay,
587
701
  });
702
+ /** 当前内核那一行:短名给落地页入口、PromptInput 的不可用提示等消费(同源,
703
+ * 不按 id 查表;目录里没有(宿主未接线/未知后端)就没有名字)。 */
704
+ const kernelCurrentOption = kernelOptions.find(option => option.current);
588
705
  /**
589
706
  * SDK 安装向导的步骤态(异步进程状态,按 chatOverlay 的分工留在 Chat,
590
- * 不进 overlay union)。生命周期约定:向导打开时从 idle 初始化,安装
591
- * (checking/running)期间面板保持打开——所有异步落地都发生在面板还在
592
- * 的窗口内;关闭路径(Esc/Enter 离开)一律重置回 idle,下一次打开重新
593
- * 解析安装目标。
707
+ * 不进 overlay union)。每次打开独占安装面与进程句柄;浮层关闭或替换时
708
+ * 取消安装并重置步骤,旧预检/安装结果不能落进下一次打开的向导。
594
709
  */
595
710
  const [sdkPhase, setSdkPhase] = React.useState({ kind: 'idle' });
596
- const sdkInstallerRef = React.useRef(undefined);
597
- // 打开即解析安装目标(同步、只读 argv + 文件系统):profile → 确认面板;
598
- // standalone / 无 profile → 直接给手动指引面板。
711
+ const sdkInstallRef = React.useRef(undefined);
712
+ const sdkOverlay = overlay.kind === 'sdk-install' ? overlay : undefined;
713
+ // 安装面在这次打开时快照;宿主回调更新不重启正在进行的安装。
599
714
  React.useEffect(() => {
600
- if (overlay.kind !== 'sdk-install' || sdkPhase.kind !== 'idle' || onResolveSdkInstallTarget === undefined)
715
+ if (sdkOverlay === undefined)
716
+ return;
717
+ const surface = onResolveSdkInstall?.(sdkOverlay.backendId);
718
+ if (surface === undefined) {
719
+ dispatchOverlay({ type: 'close' });
601
720
  return;
602
- const target = onResolveSdkInstallTarget();
603
- if (target.kind === 'profile' && sdkInstallPinned !== undefined) {
604
- setSdkPhase({ kind: 'confirm', dir: target.dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
721
+ }
722
+ const installation = { surface };
723
+ sdkInstallRef.current = installation;
724
+ const target = surface.resolveTarget();
725
+ if (target.kind === 'profile') {
726
+ setSdkPhase({
727
+ kind: 'confirm',
728
+ dir: target.dir,
729
+ version: surface.version,
730
+ specifier: surface.specifier,
731
+ ...(sdkOverlay.foundCli === undefined ? {} : { foundCli: sdkOverlay.foundCli }),
732
+ });
605
733
  }
606
734
  else {
607
735
  setSdkPhase({ kind: 'no-target', reason: target.kind === 'standalone' ? 'standalone' : 'no-profile' });
608
736
  }
609
- }, [overlay.kind, sdkPhase.kind, onResolveSdkInstallTarget, sdkInstallPinned]);
737
+ return () => {
738
+ sdkInstallRef.current = undefined;
739
+ installation.installer?.cancel();
740
+ setSdkPhase({ kind: 'idle' });
741
+ };
742
+ }, [sdkOverlay]);
610
743
  const closeSdkInstallToKernelPicker = () => {
611
- setSdkPhase({ kind: 'idle' });
612
744
  dispatchOverlay({ type: 'close' });
613
745
  openKernelPicker();
614
746
  };
615
747
  const closeSdkInstall = () => {
616
- setSdkPhase({ kind: 'idle' });
617
748
  dispatchOverlay({ type: 'close' });
618
749
  };
619
750
  const runSdkInstall = (dir) => {
620
- if (onStartSdkInstall === undefined || sdkInstallPinned === undefined)
751
+ const installation = sdkInstallRef.current;
752
+ if (installation === undefined)
621
753
  return;
622
- const installer = onStartSdkInstall(dir);
623
- sdkInstallerRef.current = installer;
754
+ const { surface } = installation;
755
+ const installer = surface.start(dir);
756
+ installation.installer = installer;
624
757
  setSdkPhase({ kind: 'running' });
625
758
  void installer.result.then(result => {
759
+ if (sdkInstallRef.current !== installation)
760
+ return;
761
+ installation.installer = undefined;
626
762
  if (result.kind === 'ok') {
627
763
  // 装好了:重探内核(灰行变亮,无需重启进程),停在完成面板。
628
764
  reprobeKernels();
629
- setSdkPhase({ kind: 'done' });
765
+ setSdkPhase({ kind: 'done', rebuiltStore: result.rebuiltStore === true });
630
766
  }
631
767
  else if (result.kind === 'failed') {
632
- setSdkPhase({ kind: 'failed', exitCode: result.exitCode, tail: result.tail, dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
768
+ setSdkPhase({ kind: 'failed', exitCode: result.exitCode, tail: result.tail, dir, version: surface.version, specifier: surface.specifier });
633
769
  }
634
770
  else if (result.kind === 'pnpm-missing') {
635
- setSdkPhase({ kind: 'pnpm-missing', dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
771
+ setSdkPhase({ kind: 'pnpm-missing', dir, version: surface.version, specifier: surface.specifier });
636
772
  }
637
773
  else {
638
774
  setSdkPhase({ kind: 'cancelled' });
@@ -640,17 +776,93 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
640
776
  });
641
777
  };
642
778
  const confirmSdkInstall = (dir) => {
643
- if (onCheckPnpm === undefined)
779
+ const installation = sdkInstallRef.current;
780
+ if (installation === undefined)
644
781
  return;
782
+ const { surface } = installation;
645
783
  setSdkPhase({ kind: 'checking' });
646
- void onCheckPnpm().then(ok => {
647
- if (!ok && sdkInstallPinned !== undefined) {
648
- setSdkPhase({ kind: 'pnpm-missing', dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
784
+ void surface.preflight().then(ok => {
785
+ if (sdkInstallRef.current !== installation)
786
+ return;
787
+ if (!ok) {
788
+ setSdkPhase({ kind: 'pnpm-missing', dir, version: surface.version, specifier: surface.specifier });
649
789
  return;
650
790
  }
651
791
  runSdkInstall(dir);
652
792
  });
653
793
  };
794
+ /**
795
+ * `/plugin install <spec>` 的步骤态(C-4)。六件套(ref / state / 收尾 / 结算 /
796
+ * 栅栏 / 起步)与 manage 侧共用 `usePluginWriteFlow`,两处的差异只有「关浮层
797
+ * 要不要取消」与「Enter 调哪个方法」。
798
+ */
799
+ const pluginInstall = usePluginWriteFlow({
800
+ overlayKind: 'plugin-install',
801
+ overlay,
802
+ dispatchOverlay,
803
+ pushLocal: lines => channel.pushLocal('/plugin', lines),
804
+ initialStep: { kind: 'done' },
805
+ // 装了半截就关浮层会把 profile 留在半装状态:取消由服务自己结算(回滚)。
806
+ cancelOnClose: flow => flow.cancel(),
807
+ failureLine: error => t('plugins-install-failed', { reason: cleanScalarText(error, COMMAND_RESULT_CELLS) }),
808
+ });
809
+ /** 开始一次安装;`false` 表示这段输入不是 install 形式(或本启动没有服务)。 */
810
+ const startPluginInstall = (rawArgs) => {
811
+ const flow = onPluginInstall?.(rawArgs, {
812
+ binding: () => channel.agentBindingGeneration,
813
+ // 回合运行中改 profile 会触发应用/HMR:门禁在流程里(inspect 之前与写入之前各查一次)。
814
+ busy: () => channel.working,
815
+ onLines: lines => channel.pushLocal('/plugin', lines),
816
+ });
817
+ if (flow === undefined)
818
+ return false;
819
+ pluginInstall.start(flow, flow.begin());
820
+ return true;
821
+ };
822
+ /**
823
+ * 取消在途安装。取消由服务自己结算(回滚 profile),浮层等它回答。
824
+ * 「还没开始装」(confirm 步)时不该走这里:服务那边没有可取消的请求,
825
+ * 只会打出一行「没有在跑的安装」——那条路径直接 `pluginInstall.close()`。
826
+ */
827
+ const cancelPluginInstall = () => {
828
+ const view = pluginInstall.view;
829
+ if (view === undefined)
830
+ return;
831
+ pluginInstall.run(view.flow.cancel());
832
+ };
833
+ /**
834
+ * `/plugin remove|enable|disable <target>` 的步骤态(C-5):与装链路同一副骨架,
835
+ * 只有两条差异——没有 `cancelOnClose`(这三个动作服务不给取消面,写也是一次就
836
+ * 结算的 profile 操作,关掉浮层它照旧跑完并把结果写进转录),以及 Enter 只有
837
+ * 「确认」一种答案。
838
+ */
839
+ const pluginManage = usePluginWriteFlow({
840
+ overlayKind: 'plugin-manage',
841
+ overlay,
842
+ dispatchOverlay,
843
+ pushLocal: lines => channel.pushLocal('/plugin', lines),
844
+ initialStep: { kind: 'done' },
845
+ failureLine: error => t('plugins-manage-failed', { reason: cleanScalarText(error, COMMAND_RESULT_CELLS) }),
846
+ });
847
+ /** 绑定会话的 teammate 数、其中运行中/准备中的数与可能在运行的数(关闭团队前的确认用)。 */
848
+ const teamMembers = () => {
849
+ const team = channel.team;
850
+ return team === undefined ? { total: 0, active: 0, unseen: 0 } : teamMemberCounts(team, [...channel.subagents], channel.sessionId);
851
+ };
852
+ /** 开始一次生命周期动作;`false` 表示这段输入不是那三种形式(或本启动没有服务)。 */
853
+ const startPluginManage = (rawArgs) => {
854
+ const flow = onPluginManage?.(rawArgs, {
855
+ binding: () => channel.agentBindingGeneration,
856
+ // 回合运行中改 profile 会触发应用/HMR:门禁在流程里(解析之前与写入之前各查一次)。
857
+ busy: () => channel.working,
858
+ onLines: lines => channel.pushLocal('/plugin', lines),
859
+ teamActiveMembers: teamMembers,
860
+ });
861
+ if (flow === undefined)
862
+ return false;
863
+ pluginManage.start(flow, flow.begin());
864
+ return true;
865
+ };
654
866
  const host = channel.backendChannels?.();
655
867
  const { rows: channelRows, open: openChannelPicker, pick: pickChannel, setMode: runBackendModeCommand, login: runBackendLogin } = useBackendChannels({
656
868
  channel, host, questionStore, dispatchOverlay, onRestartFreshSession, runOAuthLogin,
@@ -665,7 +877,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
665
877
  * The first-run guide. Renders above the launchpad (see the prop docs): a
666
878
  * launch that needs setup has not answered the launchpad's question yet.
667
879
  */
668
- const [onboardingOpen, setOnboardingOpen] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot);
880
+ const [onboardingOpen, setOnboardingOpen] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot && channel.ready !== false);
669
881
  /**
670
882
  * 落地页那条"第一次用?跑一遍引导"的横幅认的是**还欠一次引导**,而不是启动快照:
671
883
  * 完成(写进 onboarding.json)之后立刻收掉;跳过刻意保留——没记账,下次启动还会问,
@@ -724,6 +936,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
724
936
  * browser, a screen rather than a panel: it owns its own focus, staged
725
937
  * drafts and keyboard; Chat only opens it. */
726
938
  const [settingsOpen, setSettingsOpen] = React.useState(false);
939
+ // The held boot screens open once the session is adopted, unless the user
940
+ // went to another screen; a failed startup never opens them.
941
+ const channelReady = channel.ready;
942
+ const channelStartupFailed = channel.startupFailure !== undefined;
943
+ React.useEffect(() => {
944
+ const held = heldBootScreensRef.current;
945
+ if (held === undefined)
946
+ return;
947
+ // A later `/new` that adopts a session must not open them over the chat.
948
+ if (channelStartupFailed) {
949
+ heldBootScreensRef.current = undefined;
950
+ return;
951
+ }
952
+ if (channelReady === false)
953
+ return;
954
+ heldBootScreensRef.current = undefined;
955
+ if (settingsOpen || treeOpen)
956
+ return;
957
+ if (held.onboarding)
958
+ setOnboardingOpen(true);
959
+ if (held.home)
960
+ setSupervisorOpen(true);
961
+ }, [channelReady, channelStartupFailed, settingsOpen, treeOpen]);
727
962
  /** 99h / 999 次的"求 star"开屏弹窗(`usageStats` 记账,一档只弹一次):
728
963
  * 只在启动时判定一次——回合进行中、或已有整屏界面在开(如开机首页),
729
964
  * 这一轮不弹也**不记账**,留给下一次启动。`starPrompt` 是测试缝:传
@@ -760,7 +995,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
760
995
  // 让开屏先画半秒:弹窗压在介绍动画之上,而不是同抢第一帧。
761
996
  const timer = setTimeout(() => {
762
997
  // 到点时回合已经开始的仍不弹(channel 是活对象,读到的是当前值)。
763
- if (channel.working)
998
+ // /restart、/kernel 的旧进程不卸这棵树,channel 生命周期结束后读它会抛:读不到就不弹。
999
+ let working;
1000
+ try {
1001
+ working = channel.working;
1002
+ }
1003
+ catch {
1004
+ return;
1005
+ }
1006
+ if (working)
764
1007
  return;
765
1008
  if (starModalPreview) {
766
1009
  const preview = STAR_MILESTONES.findIndex(milestone => milestone.hours === 99);
@@ -890,8 +1133,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
890
1133
  * (Standard/PTC/极简…),名册是异步的——落地页出来时顺手预热一次
891
1134
  * (空名册不写;失败静默,段缺省不画)。/preset 自己的加载路径不动。
892
1135
  */
1136
+ // No roster to ask on a placeholder still starting, nor on a kernel without
1137
+ // /preset (the refusal would land as a "not supported" notice).
1138
+ const presetsReady = channel.ready !== false;
1139
+ const presetsServed = !isUnavailableLocalCommand('preset', channel.backendCapabilities);
893
1140
  React.useEffect(() => {
894
- if (!launchpadShown || presetOptions.length > 0)
1141
+ if (!launchpadShown || presetOptions.length > 0 || !presetsReady || !presetsServed)
895
1142
  return;
896
1143
  let cancelled = false;
897
1144
  channel.listPresets()
@@ -899,7 +1146,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
899
1146
  setPresetOptions(list); })
900
1147
  .catch(() => { });
901
1148
  return () => { cancelled = true; };
902
- }, [launchpadShown, presetOptions.length, channel]);
1149
+ }, [launchpadShown, presetOptions.length, channel, presetsReady, presetsServed]);
903
1150
  /** `/effort` adapter levels: load async before the slider opens. */
904
1151
  const [effortOptions, setEffortOptions] = React.useState([]);
905
1152
  /** True when those levels are the CLI-standard compatibility ladder (the
@@ -1036,8 +1283,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1036
1283
  }, [autoRecapSessionId]);
1037
1284
  // The user starts a new message → the auto recap has served its purpose
1038
1285
  // (catching them up) and bows out. A newer user row is the signal; the
1039
- // assistant's own streamed rows don't count.
1040
- const lastUserRowId = channel.rows.filter(row => row.kind === 'user').at(-1)?.id ?? -1;
1286
+ // assistant's own streamed rows (and a teammate's message) don't count.
1287
+ const lastUserRowId = channel.rows.filter(row => row.kind === 'user' && row.label !== 'team-message').at(-1)?.id ?? -1;
1041
1288
  React.useEffect(() => {
1042
1289
  if (recap !== null &&
1043
1290
  recap.auto &&
@@ -1240,7 +1487,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1240
1487
  }, [launchpadCoverScreenUp]);
1241
1488
  /**
1242
1489
  * 从落地页出发的交互要开整屏前先授权(配合 `launchpadGate`):调用点只在
1243
- * 落地页自己的回调里(onAction / onCommandPick / onEscape 的会话浏览路)。
1490
+ * 落地页自己的回调里(onAction / onSubmit / onCommandPick / onEscape)。
1244
1491
  * 异步误置真的整屏状态没有这道授权 → 闸门挡下,落地页留在最上层。
1245
1492
  */
1246
1493
  const authorizeLaunchpadCover = () => { launchpadCoverRef.current = true; };
@@ -1667,8 +1914,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1667
1914
  };
1668
1915
  }, []);
1669
1916
  const draftSessionId = channel.agentId;
1670
- /** Session the effect below last reconciled against; a change is a switch. */
1671
- const draftSessionRef = React.useRef(draftSessionId);
1917
+ const draftBindingGeneration = resolveBindingGeneration(channel);
1918
+ /** Last reconciled binding; its image epoch distinguishes adoption from replacement. */
1919
+ const draftSessionRef = React.useRef({ id: draftSessionId, generation: draftBindingGeneration, imageGeneration: composerImageGeneration });
1672
1920
  /**
1673
1921
  * The session a fill Chat itself requested belongs to, if one is in flight.
1674
1922
  *
@@ -1694,9 +1942,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1694
1942
  * answered by the snapshot's owner fields.
1695
1943
  */
1696
1944
  React.useLayoutEffect(() => {
1697
- if (draftSessionRef.current === draftSessionId)
1945
+ const previous = draftSessionRef.current;
1946
+ draftSessionRef.current = { id: draftSessionId, generation: draftBindingGeneration, imageGeneration: composerImageGeneration };
1947
+ if (previous.id === draftSessionId)
1698
1948
  return;
1699
- draftSessionRef.current = draftSessionId;
1949
+ if (previous.id === '' && previous.imageGeneration === composerImageGeneration) {
1950
+ // Startup adoption gives the existing draft its first conversation.
1951
+ // A covered composer has parked that draft in the owner slot instead.
1952
+ const snapshot = promptDraftRef.current.current;
1953
+ if (snapshot?.ownerAgentId === '' && snapshot.bindingGeneration === previous.generation) {
1954
+ promptDraftRef.current.current = {
1955
+ ...snapshot,
1956
+ ownerAgentId: String(draftSessionId),
1957
+ bindingGeneration: draftBindingGeneration,
1958
+ };
1959
+ }
1960
+ return;
1961
+ }
1700
1962
  // A stored draft can only belong to the conversation being replaced: the
1701
1963
  // composer is the one that writes it, and it writes it on the way out.
1702
1964
  promptDraftRef.current.current = null;
@@ -1705,7 +1967,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1705
1967
  return;
1706
1968
  }
1707
1969
  promptControllerRef.current?.clear();
1708
- }, [draftSessionId]);
1970
+ }, [draftSessionId, draftBindingGeneration]);
1709
1971
  const previewGallery = activePreview === null ? [] : activePreview.peek
1710
1972
  ? promptControllerRef.current?.previewImages?.() ?? [activePreview]
1711
1973
  : overlay.kind === 'image-preview' ? overlay.gallery ?? [activePreview] : [];
@@ -1744,7 +2006,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1744
2006
  if (!controller)
1745
2007
  return;
1746
2008
  const text = controller.append('').trim();
1747
- if (text === '')
2009
+ if (text === '' || refusedAtStartup(undefined))
1748
2010
  return;
1749
2011
  channel.submit(text);
1750
2012
  controller.clear();
@@ -1798,7 +2060,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1798
2060
  // Mouse text selection auto-copy: active only in
1799
2061
  // fullscreen (<AlternateScreen> supplies mouse tracking); a no-op
1800
2062
  // subscription in inline mode, where selection belongs to the terminal.
1801
- // The copy clears the highlight and posts a transient notification.
2063
+ // The copy retains the highlight and posts a transient notification.
1802
2064
  // Smart migration hint (product ask): ~12s after mount, one background
1803
2065
  // pass over the foreign-agent stores; when a source was active inside the
1804
2066
  // 20-minute window, surface the user's own wording once per session. The
@@ -1806,14 +2068,20 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1806
2068
  // off the render path; failures read as "no data" and stay silent.
1807
2069
  const migrateHintShownRef = React.useRef(false);
1808
2070
  React.useEffect(() => {
2071
+ // A replaced Channel must not retain the old hint's Enter shortcut.
2072
+ setMigrateHintAgent(null);
1809
2073
  if (migrateHintShownRef.current)
1810
2074
  return;
2075
+ let disposed = false;
2076
+ let hintTimer;
1811
2077
  const timer = setTimeout(() => {
1812
2078
  migrateHintShownRef.current = true;
1813
2079
  void (async () => {
1814
2080
  const newest = await new Promise(resolve => {
1815
2081
  setImmediate(() => resolve(collectActivitySamples(MIGRATION_ADAPTERS, adapter => MIGRATE_SCAN_SPECS[adapter.id])));
1816
2082
  });
2083
+ if (disposed)
2084
+ return;
1817
2085
  const top = recentAgentsFrom(newest, Date.now())[0];
1818
2086
  if (top !== undefined) {
1819
2087
  channel.notify(t('migrate-hint-notify', { agent: top.label }), { timeoutMs: 10000 });
@@ -1821,18 +2089,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1821
2089
  // overlay) jumps into the picker with this source pre-checked;
1822
2090
  // the global key layer below consumes it, anything else disarms.
1823
2091
  setMigrateHintAgent(top.agentId);
1824
- setTimeout(() => setMigrateHintAgent(current => current === top.agentId ? null : current), 10_000);
2092
+ hintTimer = setTimeout(() => setMigrateHintAgent(current => current === top.agentId ? null : current), 10_000);
1825
2093
  }
1826
2094
  })();
1827
2095
  }, 12_000);
1828
- return () => clearTimeout(timer);
2096
+ return () => {
2097
+ disposed = true;
2098
+ clearTimeout(timer);
2099
+ if (hintTimer !== undefined)
2100
+ clearTimeout(hintTimer);
2101
+ };
1829
2102
  }, [channel]);
1830
2103
  useCopyOnSelect(text => channel.notify(t('copied-chars', { n: text.length }), { timeoutMs: 1500 }),
1831
2104
  // Stale-selection refusal: the highlighted rows were replaced in place
1832
2105
  // (streaming overwrite), so nothing was copied — say why instead of
1833
2106
  // letting the highlight vanish silently.
1834
2107
  () => channel.notify(t('copy-refused-stale'), { timeoutMs: 2500 }));
1835
- const { clearSelection: clearMouseSelection, hasSelection: hasMouseSelection } = useSelection();
2108
+ const { clearSelection: clearMouseSelection, hasSelection: hasMouseSelection, getState: getMouseSelectionState, } = useSelection();
1836
2109
  React.useEffect(() => {
1837
2110
  if (!channel.working || !terminalFocused)
1838
2111
  return;
@@ -1963,8 +2236,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1963
2236
  * plugin (plan/goal/…) dispatches through the command registry, whose
1964
2237
  * result text lands as a notification. `rawInput` carries the text after
1965
2238
  * the command name (`/plan off` → ` off`).
2239
+ *
2240
+ * `render.block` prints a multi-line report the way `/plugins` prints one:
2241
+ * a `local` echo row plus one wrapped `local-output` row per line, in the
2242
+ * transcript (native scrollback in inline mode). A single truncated toast
2243
+ * row cannot carry a full goal objective, so the bare `/goal` status query
2244
+ * asks for the block; errors always notify — they want the color and the
2245
+ * transient read.
1966
2246
  */
1967
- const runExternalCommand = (name, rawInput, images = []) => {
2247
+ const runExternalCommand = (name, rawInput, images = [], render) => {
1968
2248
  const originAgentBinding = channel.agentBindingGeneration;
1969
2249
  return channel.runExternalCommandOutcome(name, rawInput, images).then((outcome) => {
1970
2250
  if (channel.agentBindingGeneration !== originAgentBinding)
@@ -1973,9 +2253,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
1973
2253
  channel.notify(t('command-not-found', { name }), { color: 'error' });
1974
2254
  return false;
1975
2255
  }
1976
- const cleaned = cleanRenderText(outcome.text, COMMAND_RESULT_CELLS);
1977
- if (cleaned !== '') {
1978
- channel.notify(cleaned, outcome.kind === 'error' ? { color: 'error' } : undefined);
2256
+ if (render?.block === true && outcome.kind !== 'error') {
2257
+ // Per-line sanitize: the newlines here are the report's structure.
2258
+ const lines = cleanBlockLines(outcome.text, LOCAL_BLOCK_CELLS);
2259
+ if (lines.length > 0)
2260
+ channel.pushLocal(`/${name}`, lines, { lineLimit: LOCAL_BLOCK_CELLS });
2261
+ }
2262
+ else {
2263
+ const cleaned = cleanRenderText(outcome.text, COMMAND_RESULT_CELLS);
2264
+ if (cleaned !== '') {
2265
+ channel.notify(cleaned, outcome.kind === 'error' ? { color: 'error' } : undefined);
2266
+ }
1979
2267
  }
1980
2268
  return outcome.consumeDraft;
1981
2269
  }).catch((error) => {
@@ -2123,18 +2411,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2123
2411
  : t('migrate-failed', { n: failures }), failures === 0 ? { timeoutMs: 6000 } : { color: 'error', timeoutMs: 10000 });
2124
2412
  })();
2125
2413
  };
2414
+ /** Not-ready refusal (`ChannelUi.ready`) for paths that bypass the composer:
2415
+ * true, after a notice, when `name` (undefined: plain text) must wait. */
2416
+ const refusedAtStartup = (name) => {
2417
+ if (channel.ready !== false || (name !== undefined && isBootSafeCommand(name)))
2418
+ return false;
2419
+ channel.notify(t('startup-not-ready', { backend: kernelCurrentOption?.shortLabel ?? channel.backendCapabilities.backendId }), { color: 'warning', timeoutMs: 2500 });
2420
+ return true;
2421
+ };
2126
2422
  /**
2127
- * Close the launchpad and hand the draft to the chat screen.
2423
+ * Submit launchpad input or a selected command through the chat routes.
2128
2424
  *
2129
2425
  * THREE cases, and they are genuinely different:
2130
2426
  *
2131
2427
  * - a slash command → `runCommand`, the same dispatch a typed command
2132
- * takes in the composer. The line is NOT submitted to the model.
2428
+ * takes in the composer. Completion-only filesystem skills keep
2429
+ * the composer's model route.
2133
2430
  * Recognition is the composer's OWN rule (第六版 BUG 1 修复): the merged
2134
2431
  * command list (locals + plugin/registry commands via channel.commandList)
2135
2432
  * decides whether the line is a command — isLocalCommandName alone missed
2136
2433
  * registry-only names (e.g. /plan, /goal), which then fell through to
2137
2434
  * channel.submit and went to the model as a user message.
2435
+ * Picker and full-screen commands keep the launchpad mounted underneath;
2436
+ * the consumed command is cleared before either surface opens.
2138
2437
  * - ordinary text → SENT DIRECTLY (fifth revision, user-reported bug:
2139
2438
  * "按了回车就直接进入流式输出"). The line rides the composer's own
2140
2439
  * submit path (`channel.submit`, which queues through the DSH inbox
@@ -2145,9 +2444,26 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2145
2444
  * History is appended for the two non-empty cases (matching what PromptInput
2146
2445
  * does on submit) so the launchpad's first line is reachable with ↑ later.
2147
2446
  */
2148
- const closeLaunchpad = React.useCallback((submit) => {
2447
+ const submitLaunchpad = (submit) => {
2149
2448
  const text = submit.trim();
2150
- setLaunchpadOpen(false);
2449
+ const parsed = text.startsWith('/') ? parseCommandName(text) : undefined;
2450
+ // Refused BEFORE the page closes, so the draft stays on it.
2451
+ if (text !== '' && refusedAtStartup(parsed?.name))
2452
+ return;
2453
+ const images = composerImageRefsForText(text, launchpadImagesRef.current);
2454
+ const command = parsed === undefined ? undefined : channel.commandList.find(entry => entry.name === parsed.name);
2455
+ const knownCommand = parsed !== undefined && (isLocalCommandName(parsed.name) || isHiddenCommandName(parsed.name) || command !== undefined);
2456
+ const modelRoutedSkill = command?.skill === true && command.external !== true;
2457
+ // Match the composer's image admission before consuming the draft.
2458
+ if (knownCommand && images.length > 0 && !modelRoutedSkill && command?.acceptsImages !== true) {
2459
+ return t('command-images-unsupported', { name: parsed.name });
2460
+ }
2461
+ const submitted = new Set(images.map(image => image.stageId));
2462
+ for (const stageId of launchpadImagesRef.current.values()) {
2463
+ if (!submitted.has(stageId))
2464
+ channel.discardStagedImage(stageId);
2465
+ }
2466
+ launchpadImagesRef.current.clear();
2151
2467
  // 首启时 openHomeOnBoot 与落地页同时为真:会话浏览器已经开着、只是被落地页盖住。
2152
2468
  // 提交首句后必须把它收掉,否则用户落到浏览器而不是"草稿就在眼前的对话",
2153
2469
  // 与本函数 doc 承诺的落点直接矛盾。
@@ -2155,10 +2471,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2155
2471
  setLaunchpadFocus(-1);
2156
2472
  setLaunchpadDraft('');
2157
2473
  setLaunchpadCaret(0);
2158
- if (text === '')
2474
+ if (text === '') {
2475
+ setLaunchpadOpen(false);
2159
2476
  return;
2477
+ }
2160
2478
  void appendHistory(text);
2161
- const parsed = text.startsWith('/') ? parseCommandName(text) : undefined;
2162
2479
  // 第八版:/help 在落地页上也是盖屏浮层(补全面板被 Esc 收掉后直接
2163
2480
  // Enter 的那条路)——不收落地页、不进对话页。聊天页里 /help 的行为
2164
2481
  // 不变(那边不走这个回调)。
@@ -2168,18 +2485,51 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2168
2485
  }
2169
2486
  // 与 composer 的 tryRunCommand 同一条判定:合并命令表(LOCAL_COMMANDS +
2170
2487
  // channel.commandList 的插件/registry 命令)里有名字才是命令;hidden
2171
- // 命令照旧认。判定之外的 / 开头行才走 submit(与聊天页 Enter 行为一致)。
2172
- if (parsed !== undefined && (isLocalCommandName(parsed.name)
2173
- || isHiddenCommandName(parsed.name)
2174
- || channel.commandList.some(entry => entry.name === parsed.name))) {
2175
- void runCommand(parsed.name, parsed.rawInput);
2488
+ // 命令照旧认。模型路由技能与判定之外的 / 开头行走 submit,与聊天页一致。
2489
+ if (parsed !== undefined && knownCommand && !modelRoutedSkill) {
2490
+ if (launchpadScreenCommands.has(parsed.name)) {
2491
+ authorizeLaunchpadCover();
2492
+ }
2493
+ else if (!overlayCommandNames.has(parsed.name)) {
2494
+ setLaunchpadOpen(false);
2495
+ }
2496
+ void runCommand(parsed.name, parsed.rawInput, images);
2176
2497
  return;
2177
2498
  }
2178
2499
  // 直接发送:与 composer 回车同一条提交路径。发出去之后输入框是空的
2179
2500
  // (内容已作为首轮发出,绝不"既发了又留在框里"),也没有交接提示——
2180
2501
  // 没有草稿要交,一句"已放进输入框"的 toast 反而是假的。
2181
- channel.submit(text);
2182
- }, [channel, launchpadOpen]);
2502
+ setLaunchpadOpen(false);
2503
+ channel.submit(text, images);
2504
+ };
2505
+ /**
2506
+ * A failed startup open closes the landing page, uncovering the failure row
2507
+ * and its `/new` hint; the draft moves to the composer once it mounts.
2508
+ */
2509
+ const launchpadDraftHandoffRef = React.useRef(undefined);
2510
+ const startupFailure = channel.startupFailure;
2511
+ React.useEffect(() => {
2512
+ if (!launchpadOpen || startupFailure === undefined)
2513
+ return;
2514
+ launchpadDraftHandoffRef.current = launchpadDraft;
2515
+ setLaunchpadOpen(false);
2516
+ setSupervisorOpen(false);
2517
+ setLaunchpadFocus(-1);
2518
+ setLaunchpadDraft('');
2519
+ setLaunchpadCaret(0);
2520
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- the draft is read at the moment of the failure, not tracked
2521
+ }, [launchpadOpen, startupFailure]);
2522
+ React.useEffect(() => {
2523
+ const draft = launchpadDraftHandoffRef.current;
2524
+ if (launchpadOpen || draft === undefined)
2525
+ return;
2526
+ const controller = promptControllerRef.current;
2527
+ if (controller === null)
2528
+ return;
2529
+ launchpadDraftHandoffRef.current = undefined;
2530
+ if (draft.trim() !== '')
2531
+ controller.append(draft);
2532
+ });
2183
2533
  /**
2184
2534
  * The screen's command dispatcher. Every entry point reaches this one
2185
2535
  * closure — PromptInput's `onRunCommand`, the completion menu, this screen's
@@ -2187,6 +2537,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2187
2537
  * second dispatcher for the landing page.
2188
2538
  */
2189
2539
  const runCommand = (name, rawInput = '', images = []) => {
2540
+ if (refusedAtStartup(name))
2541
+ return true;
2190
2542
  switch (name) {
2191
2543
  case 'activity': {
2192
2544
  // Ported from the pi working-activity extension: bare `/activity`
@@ -2507,8 +2859,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2507
2859
  setHelpOpen(true);
2508
2860
  return true;
2509
2861
  case 'model': {
2510
- // `/model <provider/model>` switches directly (same live-fork path
2511
- // as the picker's Enter), bare `/model` opens the picker.
2862
+ // `/model <provider/model>` switches directly (same in-session route
2863
+ // switch as the picker's Enter), bare `/model` opens the picker.
2512
2864
  const parts = rawInput.trim().split(/\s+/).filter(Boolean);
2513
2865
  if (parts.length > 0) {
2514
2866
  setHelpOpen(false);
@@ -2533,37 +2885,37 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
2533
2885
  return true;
2534
2886
  }
2535
2887
  setHelpOpen(false);
2536
- // Opens over the cached catalog (empty cache shows the loading
2537
- // pane); the fresh list lands with the authoritative focus, and the
2538
- // kind-guarded set-index cannot re-focus a picker the user left.
2539
- // Seed-on-open: the model in use IS a use — recording it here means
2540
- // the recents group exists before the first post-update switch, and
2541
- // switching A→B keeps A in the list (the file records what was
2542
- // used, not only switches made after the file appeared).
2543
- let recentsNow = modelRecents;
2544
- if (channel.provider !== '' && channel.model !== ''
2545
- && !recentsNow.some(ref => ref.provider === channel.provider && ref.id === channel.model)) {
2546
- recentsNow = recordModelUse({ provider: channel.provider, id: channel.model }, undefined, recentsBackend);
2547
- setModelRecents(recentsNow);
2548
- }
2549
- // Two-level landing: recents (when catalogued) focus their pinned
2550
- // row; else multi-provider catalogs focus the current provider's
2551
- // group row; a single-provider catalog without a meaningful recents
2552
- // list drills straight into its model list (pre-grouping UX).
2553
- {
2554
- const landing = modelPickerLanding(models, channel.provider, channel.model, recentsNow);
2555
- setModelGroup(landing.group);
2556
- setModelPickerDirect(landing.group !== undefined);
2557
- dispatchOverlay({ type: 'open', overlay: { kind: 'model', index: landing.index } });
2888
+ // Opening counts the live route as the latest use, including when
2889
+ // restoring a session whose model already exists later in recents.
2890
+ // Refresh the catalog without overriding navigation made meanwhile.
2891
+ const latestRecent = modelRecents[0];
2892
+ if (modelProviderTabs && channel.provider !== '' && channel.model !== ''
2893
+ && (latestRecent?.provider !== channel.provider || latestRecent?.id !== channel.model)) {
2894
+ setModelRecents(recordModelUse({ provider: channel.provider, id: channel.model }, undefined, recentsBackend));
2558
2895
  }
2896
+ modelPicker.reset();
2897
+ dispatchOverlay({ type: 'open', overlay: { kind: 'model' } });
2898
+ setModelsLoading(true);
2899
+ const generation = ++modelCatalogGeneration.current;
2559
2900
  void channel.listModels().then((list) => {
2901
+ if (generation !== modelCatalogGeneration.current)
2902
+ return;
2560
2903
  setModels(list);
2561
- const landing = modelPickerLanding(list, channel.provider, channel.model, recentsNow);
2562
- setModelGroup(landing.group);
2563
- setModelPickerDirect(landing.group !== undefined);
2564
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
2904
+ setModelsLoading(false);
2905
+ }).catch(() => {
2906
+ if (generation !== modelCatalogGeneration.current)
2907
+ return;
2908
+ setModelsLoading(false);
2909
+ channel.notify(t('model-load-failed'), { color: 'error' });
2565
2910
  });
2566
- void channel.listProviders().then(setProviderInfos).catch(() => setProviderInfos([]));
2911
+ if (modelProviderTabs)
2912
+ void channel.listProviders().then(list => {
2913
+ if (generation === modelCatalogGeneration.current)
2914
+ setProviderInfos(list);
2915
+ }).catch(() => {
2916
+ if (generation === modelCatalogGeneration.current)
2917
+ setProviderInfos([]);
2918
+ });
2567
2919
  return true;
2568
2920
  }
2569
2921
  case 'skills': {
@@ -3032,13 +3384,66 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3032
3384
  void collectMigrateRows().then(setMigrateRows);
3033
3385
  return true;
3034
3386
  }
3035
- case 'plugins':
3387
+ case 'plugin': {
3036
3388
  // Plugin diagnostics (C-070): trust banner first, then descriptor /
3037
3389
  // grant matrix / ledger tail — or validate+negotiate for
3038
- // `/plugins check <path>` (rawInput carries the subcommand).
3390
+ // `/plugin check <path>` (rawInput carries the subcommand).
3391
+ setHelpOpen(false);
3392
+ // `/plugin install <spec>` is the one form that needs a flow of its own
3393
+ // (C-4). Anything else — and any launch whose entry has no service to
3394
+ // install through — falls through to the read-only report below.
3395
+ // The three lifecycle forms (C-5) and the install form each need a flow
3396
+ // of their own. They are mutually exclusive by their subcommand, so
3397
+ // trying one and then the other cannot take the wrong path; anything
3398
+ // else — and any launch whose entry has no service — falls through to
3399
+ // the read-only report below.
3400
+ if (startPluginManage(rawInput))
3401
+ return true;
3402
+ if (startPluginInstall(rawInput))
3403
+ return true;
3404
+ // The bundle/row half comes from the host plugin service, so the
3405
+ // report is async (the `/agents` case reads the same way). `pushLocal`
3406
+ // writes the CURRENTLY bound session, and a resume or `/new` can land
3407
+ // while the service is still answering: fence the report to the
3408
+ // binding that asked for it, or it appears in the new transcript.
3409
+ const originAgentBinding = channel.agentBindingGeneration;
3410
+ void channel.pluginsInfo(rawInput).then((lines) => {
3411
+ if (channel.agentBindingGeneration !== originAgentBinding)
3412
+ return;
3413
+ channel.pushLocal('/plugin', lines);
3414
+ });
3415
+ return true;
3416
+ }
3417
+ case 'team': {
3418
+ // `/team` 是团队 bundle 的启停(team-mode.ts):on/off 走与 /plugin 同一个
3419
+ // 生命周期流程与确认浮层,status 是一段报告;都按发起时的绑定落行。
3039
3420
  setHelpOpen(false);
3040
- channel.pushLocal('/plugins', channel.pluginsInfo(rawInput));
3421
+ if (onTeamCommand === undefined) {
3422
+ channel.pushLocal('/team', [t('team-cmd-unavailable')]);
3423
+ return true;
3424
+ }
3425
+ const originAgentBinding = channel.agentBindingGeneration;
3426
+ const outcome = onTeamCommand(rawInput, {
3427
+ binding: () => channel.agentBindingGeneration,
3428
+ busy: () => channel.working,
3429
+ onLines: lines => channel.pushLocal('/team', lines),
3430
+ members: teamMembers,
3431
+ });
3432
+ if (outcome.kind === 'flow') {
3433
+ pluginManage.start(outcome.flow, outcome.flow.begin());
3434
+ return true;
3435
+ }
3436
+ void outcome.lines.then((lines) => {
3437
+ if (channel.agentBindingGeneration !== originAgentBinding)
3438
+ return;
3439
+ channel.pushLocal('/team', [...lines]);
3440
+ }, (error) => {
3441
+ if (channel.agentBindingGeneration !== originAgentBinding)
3442
+ return;
3443
+ channel.pushLocal('/team', [t('plugins-manage-failed', { reason: cleanCommandError(error) })]);
3444
+ });
3041
3445
  return true;
3446
+ }
3042
3447
  case 'export': {
3043
3448
  const target = channel.exportSession();
3044
3449
  channel.notify(target === null
@@ -3107,12 +3512,23 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3107
3512
  }
3108
3513
  return false;
3109
3514
  }
3110
- case 'agents':
3515
+ case 'agents': {
3111
3516
  setHelpOpen(false);
3517
+ // The roster comes from the host subagents service, so the report is
3518
+ // async. Two fences, each for a window of its own: the generation guard
3519
+ // drops an answer that raced a session switch (`pushLocal` writes the
3520
+ // CURRENT binding), and the catch takes the rejection `listSubagents`
3521
+ // raises on purpose when the capture it read for has ended — an
3522
+ // unhandledRejection there is fatal to the process guard, and there is
3523
+ // nothing left to report to.
3524
+ const originAgentBinding = channel.agentBindingGeneration;
3112
3525
  void channel.listSubagents().then((lines) => {
3526
+ if (channel.agentBindingGeneration !== originAgentBinding)
3527
+ return;
3113
3528
  channel.pushLocal('/agents', lines);
3114
- });
3529
+ }).catch(() => undefined);
3115
3530
  return true;
3531
+ }
3116
3532
  case 'login': {
3117
3533
  setHelpOpen(false);
3118
3534
  if (runBackendLogin())
@@ -3195,7 +3611,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3195
3611
  }
3196
3612
  const currentName = snapshot.availability === 'unavailable'
3197
3613
  ? t('permission-roster-unavailable')
3198
- : snapshot.current?.name ?? '—';
3614
+ : currentPermissionName(snapshot) ?? '—';
3199
3615
  channel.pushLocal('/permission', [
3200
3616
  t('permission-current', { name: currentName }),
3201
3617
  t('permission-policy-hint'),
@@ -3250,15 +3666,21 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3250
3666
  }
3251
3667
  case 'plan': {
3252
3668
  // Registered by dsh-plan-mode: bare `/plan` opens an on/off picker
3253
- // marked with the current state instead of toggling blindly; Enter
3254
- // dispatches `/plan` or `/plan off`. Arguments pass through verbatim
3255
- // (`/plan off`). Availability comes from the shared capability facts
3256
- // (the same read Shift+Tab uses), not from a second command-list
3257
- // scan; with no registry command the line falls through to the model,
3258
- // exactly as before.
3669
+ // marked with the current state instead of toggling blindly; the
3670
+ // picker's own rows dispatch the bare command and ` off`, never the
3671
+ // catalog token. The catalog's `on` child (the only producer of that
3672
+ // literal argument) is normalized back to the bare command:
3673
+ // upstream's grammar is `/plan [off|message]`, so a verbatim `on`
3674
+ // would enter plan mode AND steer the word "on" into the next step as
3675
+ // a user message. Every other argument — `/plan off` and
3676
+ // `/plan <message>` — passes through verbatim. Availability comes from
3677
+ // the shared capability facts (the same read Shift+Tab uses), not from
3678
+ // a second command-list scan; with no registry command the line falls
3679
+ // through to the model, exactly as before.
3259
3680
  const plan = channel.capabilities().plan;
3260
3681
  const mounted = plan.route !== 'none';
3261
3682
  const parts = rawInput.trim().split(/\s+/).filter(Boolean);
3683
+ const argument = parts.length === 1 && parts[0] === 'on' ? '' : rawInput;
3262
3684
  if (mounted && parts.length === 0) {
3263
3685
  setHelpOpen(false);
3264
3686
  dispatchOverlay({
@@ -3269,7 +3691,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3269
3691
  }
3270
3692
  if (mounted) {
3271
3693
  setHelpOpen(false);
3272
- return runExternalCommand('plan', rawInput, images);
3694
+ return runExternalCommand('plan', argument, images);
3273
3695
  }
3274
3696
  return false;
3275
3697
  }
@@ -3338,13 +3760,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3338
3760
  currentLang: getLang(),
3339
3761
  langOverriddenBySettings: tuiNamespace !== undefined && hasPath(tuiNamespace.user, ['lang']),
3340
3762
  configuredLang: channel.configuredLang,
3341
- configuredPreset: channel.configuredPreset,
3763
+ envPreset: presetOverrideFromEnv(),
3342
3764
  presetPref: readPresetPref(),
3343
3765
  currentPreset: channel.agentPreset,
3344
- configuredModel: {
3345
- provider: channel.configuredProvider,
3346
- model: channel.configuredModel,
3347
- },
3348
3766
  modelPref: readModelPref(),
3349
3767
  currentModel: { provider: channel.provider, model: channel.model },
3350
3768
  configuredActivity: channel.configuredActivityFrames,
@@ -3398,7 +3816,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3398
3816
  // default branch below would dispatch it.
3399
3817
  if (channel.commandList.some(command => command.external && command.name === 'goal')) {
3400
3818
  setHelpOpen(false);
3401
- return runExternalCommand(name, rawInput, images);
3819
+ // Bare `/goal` is DSH's status query. Print it as a transcript
3820
+ // block: inline mode sees no pointer events, so the hover tooltip
3821
+ // cannot carry the objective there, and the toast truncates it to
3822
+ // one row.
3823
+ return runExternalCommand(name, rawInput, images, { block: rawInput.trim() === '' });
3402
3824
  }
3403
3825
  // Another backend: the channel core's host over its typed `goals`
3404
3826
  // capability. None (DSH without the row, or a backend's own `goal`
@@ -3416,7 +3838,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3416
3838
  const command = parseGoalCommand(rawInput);
3417
3839
  switch (command.kind) {
3418
3840
  case 'status':
3419
- channel.pushLocal('/goal', goalStatusLines(channel.goal));
3841
+ channel.pushLocal('/goal', goalStatusLines(channel.goal), { lineLimit: LOCAL_BLOCK_CELLS });
3420
3842
  return true;
3421
3843
  case 'invalid':
3422
3844
  channel.notify(command.reason, { color: 'error' });
@@ -3442,7 +3864,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3442
3864
  return true;
3443
3865
  }
3444
3866
  case 'kernel':
3445
- // 内核选择器,每个内核下都可用(在对话页里切回 DSH 只有这一条路)。
3867
+ // 内核选择器,每个内核下都可用。
3446
3868
  // 确认后由组合根的 onSwitchBackend 记住选择并以新内核重启。与 /help、
3447
3869
  // 参数行一致:选择器已开着就收起,没开才打开。
3448
3870
  setHelpOpen(false);
@@ -3451,6 +3873,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3451
3873
  else
3452
3874
  openKernelPicker();
3453
3875
  return true;
3876
+ case 'dsh':
3877
+ case 'codex':
3878
+ case 'claude':
3879
+ setHelpOpen(false);
3880
+ return pickKernelById(name).then(() => true);
3454
3881
  case 'restart':
3455
3882
  // pi-style reload tail: /reload cannot re-read boot-time-only state
3456
3883
  // (cordis.yml root config, frozen fullscreen layout, newly built
@@ -3679,10 +4106,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3679
4106
  const pageInsetX = usePageInset().x;
3680
4107
  // 侧栏控制器:几何(chatColumns/panelColumns)、焦点与键盘分发都在
3681
4108
  // 这个 hook 里(设计文档 §16.5——Chat 只多一次调用、一处键盘让位、
3682
- // 一条 runCommand case)。编辑器展开时几何强制 collapsed。
4109
+ // 一条 runCommand case)。启动页没有侧栏,命令走整屏回退;编辑器
4110
+ // 展开时几何同样强制 collapsed。
3683
4111
  const sidePanel = useSidePanel({
3684
4112
  columns: terminalColumns,
3685
- fullscreen,
4113
+ fullscreen: fullscreen && !launchpadShown,
3686
4114
  editorOpen: promptEditorOpen,
3687
4115
  });
3688
4116
  /**
@@ -3935,7 +4363,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
3935
4363
  // The launchpad owns the whole terminal while it is up — including the
3936
4364
  // plain letters that would otherwise reach the composer, which is exactly
3937
4365
  // the point: it IS the composer on this screen, and its draft is submitted
3938
- // directly (see closeLaunchpad). ONE exception (fifth revision): a picker
4366
+ // directly (see submitLaunchpad). ONE exception (fifth revision): a picker
3939
4367
  // opened from the param row renders ABOVE the launchpad and therefore owns
3940
4368
  // the keyboard — fall through to the overlay branches below (Esc closes the
3941
4369
  // picker back onto the launchpad). The launchpad's own useInput is paused
@@ -4078,6 +4506,21 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4078
4506
  }
4079
4507
  return;
4080
4508
  }
4509
+ if (overlay.kind === 'model') {
4510
+ if (actionMatches('sidePanel', input, key) || actionMatches('sidePanelZoom', input, key)) {
4511
+ if (sidePanel.handleKey(input, key, event))
4512
+ return;
4513
+ }
4514
+ // The model picker owns both navigation axes, including when a side
4515
+ // panel or transcript selection held focus before it opened.
4516
+ const now = Date.now();
4517
+ const confirm = isPlainReturnInput(input, key) && now - lastModalEnterAtRef.current >= 80;
4518
+ if (confirm)
4519
+ lastModalEnterAtRef.current = now;
4520
+ modelPicker.handleKey(input, key, confirm);
4521
+ event.stopImmediatePropagation();
4522
+ return;
4523
+ }
4081
4524
  // 侧栏键盘分发(v2.1 优先级):上面的审批 / 问卷 / 对话框守卫仍然
4082
4525
  // 最先,其次是侧栏全局快捷键(Ctrl+B / Alt+Z,两种焦点都生效),
4083
4526
  // 然后焦点在右栏时一切按键归侧栏——活动面板的业务键优先,宿主
@@ -4111,11 +4554,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4111
4554
  event.stopImmediatePropagation();
4112
4555
  return;
4113
4556
  }
4114
- // Esc clears a settled mouse selection before the ordinary chat meanings
4115
- // below, but never before a top-level modal. Otherwise a preview opened
4116
- // over selected transcript text needed two Esc presses to close.
4117
- // hasSelection() is an imperative read — no subscription needed.
4118
- if (key.escape && hasMouseSelection()) {
4557
+ // With no overlay open, Esc cancels an active mouse drag or retained
4558
+ // selection before ordinary chat meanings. Open overlays own Esc.
4559
+ // Selection queries are imperative reads — no subscription needed.
4560
+ if (overlay.kind === 'none' && key.escape && (hasMouseSelection() || getMouseSelectionState()?.isDragging)) {
4119
4561
  clearMouseSelection();
4120
4562
  event.stopImmediatePropagation();
4121
4563
  return;
@@ -4336,59 +4778,6 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4336
4778
  }
4337
4779
  return;
4338
4780
  }
4339
- if (overlay.kind === 'model') {
4340
- // Two-level picker: group rows at the top (Enter drills in), one
4341
- // provider's models below (Enter switches, the same live-fork path as
4342
- // the flat picker always had). Esc/⌫ climbs one level and only closes
4343
- // at the top; a single-group catalog never shows the group level, so
4344
- // Esc there closes directly.
4345
- const rowCount = activeModelGroup === undefined ? modelGroups.length : groupModels.length;
4346
- if (key.upArrow || key.downArrow) {
4347
- dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: rowCount });
4348
- }
4349
- else if (plainReturn) {
4350
- if (activeModelGroup === undefined) {
4351
- const group = modelGroups[overlay.index];
4352
- if (!group) {
4353
- dispatchOverlay({ type: 'close' });
4354
- return;
4355
- }
4356
- setModelGroup(group.provider);
4357
- // The recents group opens on its most-recent entry; a provider
4358
- // group on its current model when it owns one, else its first row.
4359
- if (group.provider === RECENTS_GROUP_PROVIDER) {
4360
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
4361
- return;
4362
- }
4363
- const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
4364
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
4365
- return;
4366
- }
4367
- const model = groupModels[overlay.index];
4368
- // oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: out-of-range index on an empty list
4369
- if (model) {
4370
- // Enter switches the live model right away: the conversation is
4371
- // forked at its end and continued with an agent routed to the new
4372
- // model (history replays unchanged) — and feeds the recents group.
4373
- dispatchOverlay({ type: 'close' });
4374
- void switchModelRecorded(model.provider, model.id, model.name);
4375
- }
4376
- else {
4377
- dispatchOverlay({ type: 'close' });
4378
- }
4379
- }
4380
- else if (key.escape || key.backspace) {
4381
- if (activeModelGroup !== undefined && modelGroups.length > 1 && !modelPickerDirect) {
4382
- setModelGroup(undefined);
4383
- const groupIndex = Math.max(0, modelGroups.findIndex(group => group.provider === activeModelGroup));
4384
- dispatchOverlay({ type: 'set-index', kind: 'model', index: groupIndex });
4385
- }
4386
- else {
4387
- dispatchOverlay({ type: 'close' });
4388
- }
4389
- }
4390
- return;
4391
- }
4392
4781
  if (overlay.kind === 'skills') {
4393
4782
  const list = skillsList ?? [];
4394
4783
  if (key.upArrow || key.downArrow) {
@@ -4548,6 +4937,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4548
4937
  }
4549
4938
  return;
4550
4939
  }
4940
+ if (overlay.kind === 'permission' && overlay.confirm === true) {
4941
+ if (plainReturn) {
4942
+ permissionOverlayFocusRef.current = null;
4943
+ dispatchOverlay({ type: 'close' });
4944
+ void runPermissionCommand(` ${PERMISSION_PRESET_AUTO}`);
4945
+ }
4946
+ else if (key.escape) {
4947
+ dispatchOverlay({ type: 'open', overlay: { ...overlay, confirm: false } });
4948
+ }
4949
+ return;
4950
+ }
4551
4951
  if (overlay.kind === 'permission') {
4552
4952
  if (key.upArrow || key.downArrow) {
4553
4953
  const currentIndex = permissionOverlayFocusRef.current?.overlay === overlay
@@ -4563,6 +4963,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4563
4963
  : overlay.index;
4564
4964
  const option = overlay.snapshot.options[currentIndex];
4565
4965
  permissionOverlayFocusRef.current = null;
4966
+ if (needsAutoConfirm(overlay.snapshot, option?.value)) {
4967
+ dispatchOverlay({ type: 'open', overlay: { ...overlay, index: currentIndex, confirm: true } });
4968
+ return;
4969
+ }
4566
4970
  dispatchOverlay({ type: 'close' });
4567
4971
  if (option !== undefined)
4568
4972
  void runPermissionCommand(` ${option.value}`);
@@ -4604,7 +5008,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4604
5008
  }
4605
5009
  if (overlay.kind === 'sdk-install') {
4606
5010
  // 向导按键按步骤态分派;checking/running 期间除 Esc(取消安装)外
4607
- // 全部吞掉——异步落地只发生在面板还在的窗口内(见 sdkPhase 注释)。
5011
+ // 全部吞掉;鼠标关闭/替换浮层由向导的 effect 取消并隔离迟到结果。
4608
5012
  if (sdkPhase.kind === 'confirm') {
4609
5013
  if (plainReturn)
4610
5014
  confirmSdkInstall(sdkPhase.dir);
@@ -4616,7 +5020,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4616
5020
  }
4617
5021
  else if (sdkPhase.kind === 'running') {
4618
5022
  if (key.escape)
4619
- sdkInstallerRef.current?.cancel();
5023
+ sdkInstallRef.current?.installer?.cancel();
4620
5024
  }
4621
5025
  else if (sdkPhase.kind === 'done') {
4622
5026
  if (plainReturn)
@@ -4637,6 +5041,77 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
4637
5041
  }
4638
5042
  return;
4639
5043
  }
5044
+ if (overlay.kind === 'plugin-install') {
5045
+ // 装链路浮层(C-4):一次安装的每一步都是显式的——确认、批准构建脚本、
5046
+ // 接受版本风险;取消由服务自己结算(回滚 profile),期间除 Esc 外不接键。
5047
+ const view = pluginInstall.view;
5048
+ if (view === undefined || view.busy) {
5049
+ if (key.escape) {
5050
+ cancelPluginInstall();
5051
+ event.stopImmediatePropagation();
5052
+ }
5053
+ return;
5054
+ }
5055
+ if (view.step.kind === 'confirm') {
5056
+ if (plainReturn) {
5057
+ pluginInstall.run(view.flow.confirm());
5058
+ event.stopImmediatePropagation();
5059
+ }
5060
+ else if (key.escape) {
5061
+ // 还没开始装:收起浮层即可,不去服务那边取消一个不存在的安装。
5062
+ pluginInstall.close();
5063
+ event.stopImmediatePropagation();
5064
+ }
5065
+ }
5066
+ else if (view.step.kind === 'build-blocked') {
5067
+ if (plainReturn) {
5068
+ pluginInstall.run(view.flow.approve(view.step.builds));
5069
+ event.stopImmediatePropagation();
5070
+ }
5071
+ else if (key.escape) {
5072
+ pluginInstall.close();
5073
+ event.stopImmediatePropagation();
5074
+ }
5075
+ }
5076
+ else if (view.step.kind === 'incompatible') {
5077
+ if (plainReturn) {
5078
+ pluginInstall.run(view.flow.acceptRisk());
5079
+ event.stopImmediatePropagation();
5080
+ }
5081
+ else if (key.escape) {
5082
+ pluginInstall.close();
5083
+ event.stopImmediatePropagation();
5084
+ }
5085
+ }
5086
+ else if (key.escape) {
5087
+ pluginInstall.close();
5088
+ event.stopImmediatePropagation();
5089
+ }
5090
+ return;
5091
+ }
5092
+ if (overlay.kind === 'plugin-manage') {
5093
+ // 生命周期浮层(C-5):只有「确认」一种答案,写入中除 Esc 外不接键。
5094
+ // 与装链路的关键差异是**没有取消**:这三个动作服务不提供取消面,写也是一次
5095
+ // 就结算的 profile 操作,所以 Esc 只关面板,流程照旧跑完并把结果(仍按发起时
5096
+ // 的 binding 加栅栏)写进转录;浮层没了就不再更新步骤态。
5097
+ const view = pluginManage.view;
5098
+ if (view === undefined || view.busy) {
5099
+ if (key.escape) {
5100
+ pluginManage.close();
5101
+ event.stopImmediatePropagation();
5102
+ }
5103
+ return;
5104
+ }
5105
+ if (plainReturn) {
5106
+ pluginManage.run(view.flow.confirm());
5107
+ event.stopImmediatePropagation();
5108
+ }
5109
+ else if (key.escape) {
5110
+ pluginManage.close();
5111
+ event.stopImmediatePropagation();
5112
+ }
5113
+ return;
5114
+ }
4640
5115
  if (overlay.kind === 'channel') {
4641
5116
  // 名册不冻在 overlay 里(channelRows 是渲染期派生值):切换/导入后
4642
5117
  // 选择器自己就刷新成新状态,不需要重开。
@@ -5169,8 +5644,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5169
5644
  // 鼠标等价),浮层收起、人还在启动页(第八版:不许进对话页)。
5170
5645
  dispatchOverlay({ type: 'close' });
5171
5646
  const filled = '/' + name + ' ';
5172
- setLaunchpadDraft(filled);
5173
- setLaunchpadCaret(filled.length);
5647
+ changeLaunchpadDraft(filled, filled.length);
5174
5648
  setLaunchpadFocus(-1);
5175
5649
  } }) })), overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
5176
5650
  // 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
@@ -5195,28 +5669,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5195
5669
  return;
5196
5670
  dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
5197
5671
  runWorkspaceFlowAction(signal => choice.choose(signal));
5198
- } }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: models.length === 0 ? (_jsx(ModelPickerLoading, {})) : activeModelGroup === undefined ? (_jsx(ModelPicker, { groups: modelGroups, focusIndex: overlay.index, currentProvider: channel.provider, onPick: (index) => {
5199
- // 点击分组行 = 进入该组(与 Enter 同一条路径)
5200
- const group = modelGroups[index];
5201
- if (!group)
5202
- return;
5203
- setModelGroup(group.provider);
5204
- if (group.provider === RECENTS_GROUP_PROVIDER) {
5205
- dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
5206
- return;
5207
- }
5208
- const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
5209
- dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
5210
- } })) : (_jsx(ModelPicker, { models: groupModels, groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
5211
- ? t('picker-group-recent')
5212
- : modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: modelGroups.length > 1 && !modelPickerDirect, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER, focusIndex: overlay.index, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
5213
- // 点击行 = 应用该行模型(与 Enter 同一条路径)
5214
- const model = groupModels[index];
5215
- if (!model)
5216
- return;
5217
- dispatchOverlay({ type: 'close' });
5218
- void switchModelRecorded(model.provider, model.id, model.name);
5219
- } })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
5672
+ } }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ModelPicker, { groups: modelPicker.groups, provider: modelPicker.provider, models: modelPicker.models, focusIndex: modelPicker.index, currentModel: `${channel.provider}/${channel.model}`, loading: modelsLoading, efforts: modelPicker.efforts, effortId: modelPicker.effortId, effortsLoading: modelPicker.effortsLoading, effortError: modelPicker.effortError, levelsFallback: modelPicker.levelsFallback, cursorZone: modelPicker.cursorZone, onProvider: modelPicker.focusProvider, onFocus: modelPicker.focusModel, onEffort: modelPicker.pickEffort, onMove: modelPicker.moveModel, onConfirm: modelPicker.confirm, onCancel: modelPicker.cancel }) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
5220
5673
  const row = (migrateRows ?? [])[index];
5221
5674
  if (!row)
5222
5675
  return;
@@ -5264,10 +5717,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5264
5717
  const option = presetOptions[index];
5265
5718
  if (option)
5266
5719
  void channel.switchPreset(option.id);
5267
- } }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, onPick: (index) => {
5720
+ } }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, confirming: overlay.confirm === true, onConfirm: () => {
5721
+ if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5722
+ return;
5723
+ permissionOverlayFocusRef.current = null;
5724
+ dispatchOverlay({ type: 'close' });
5725
+ void runPermissionCommand(` ${PERMISSION_PRESET_AUTO}`);
5726
+ }, onCancelConfirm: () => {
5727
+ if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5728
+ return;
5729
+ dispatchOverlay({ type: 'open', overlay: { ...overlay, confirm: false } });
5730
+ }, onPick: (index) => {
5268
5731
  if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5269
5732
  return;
5270
5733
  const option = overlay.snapshot.options[index];
5734
+ if (needsAutoConfirm(overlay.snapshot, option?.value)) {
5735
+ dispatchOverlay({ type: 'open', overlay: { ...overlay, index, confirm: true } });
5736
+ return;
5737
+ }
5271
5738
  dispatchOverlay({ type: 'close' });
5272
5739
  if (option !== undefined)
5273
5740
  void runPermissionCommand(` ${option.value}`);
@@ -5282,7 +5749,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5282
5749
  if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5283
5750
  return;
5284
5751
  pickKernel(index);
5285
- } }) })), overlay.kind === 'sdk-install' && sdkPhase.kind !== 'idle' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(SdkInstallWizard, { phase: sdkPhase }) })), overlay.kind === 'channel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ChannelPicker, { rows: channelRows, focusIndex: overlay.index, onPick: (index) => {
5752
+ } }) })), overlay.kind === 'sdk-install' && sdkPhase.kind !== 'idle' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(SdkInstallWizard, { phase: sdkPhase }) })), overlay.kind === 'plugin-install' && pluginInstall.view !== undefined && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PluginInstallPane, { step: pluginInstall.view.step, busy: pluginInstall.view.busy }) })), overlay.kind === 'plugin-manage' && pluginManage.view !== undefined && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PluginManagePane, { step: pluginManage.view.step, busy: pluginManage.view.busy }) })), overlay.kind === 'channel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ChannelPicker, { rows: channelRows, focusIndex: overlay.index, onPick: (index) => {
5286
5753
  if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
5287
5754
  return;
5288
5755
  pickChannel(index);
@@ -5424,12 +5891,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5424
5891
  // 第七版:明确选中一个会话 = 有意导航(与 Esc「退出」相对)——浏览页
5425
5892
  // 与盖在它底下的落地页**一起收**,人落在那个会话的聊天页。只收浏览页
5426
5893
  // 会露出启动页,正是用户实测的「选完会话还是回到启动页」。落地页的
5427
- // 草稿/焦点也按 closeLaunchpad 同一口径清掉(进入的是别的会话,旧草稿
5894
+ // 草稿/焦点也按 submitLaunchpad 同一口径清掉(进入的是别的会话,旧草稿
5428
5895
  // 不该跟过去)。
5429
5896
  setLaunchpadOpen(false);
5430
5897
  setLaunchpadFocus(-1);
5431
- setLaunchpadDraft('');
5432
- setLaunchpadCaret(0);
5898
+ changeLaunchpadDraft('', 0);
5433
5899
  repaintTranscript();
5434
5900
  return result;
5435
5901
  }, onNewSession: async (target) => {
@@ -5441,8 +5907,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5441
5907
  // 同 onOpenSession:新建/切工作区会话也是有意导航,落地页一并收。
5442
5908
  setLaunchpadOpen(false);
5443
5909
  setLaunchpadFocus(-1);
5444
- setLaunchpadDraft('');
5445
- setLaunchpadCaret(0);
5910
+ changeLaunchpadDraft('', 0);
5446
5911
  repaintTranscript();
5447
5912
  }
5448
5913
  return ok;
@@ -5540,7 +6005,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5540
6005
  // of the sidebar panel. Esc returns to the sidebar exactly as it was — the
5541
6006
  // thread and the composer draft live in btwThreads, nothing is cleared.
5542
6007
  if (btwSceneOpen && launchpadGate()) {
5543
- const scene = (_jsx(BtwThreadScene, { channel: channel, onClose: () => setBtwSceneOpen(false) }));
6008
+ const scene = (_jsx(BtwThreadScene, { channel: channel, onClose: () => setBtwSceneOpen(false),
6009
+ // 送聊天之后整屏场景让位:关场景 + 焦点回主输入框——与侧栏形态里
6010
+ // 「面板留着、焦点回输入框」的落点一致(见 BtwThreadScene.sendToChat)。
6011
+ onFocusChat: sidePanel.focusChat }));
5544
6012
  return fullscreen ? scene : _jsx(AlternateScreen, { children: scene });
5545
6013
  }
5546
6014
  // Subagent dashboard: displays all active and completed subagents.
@@ -5548,7 +6016,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5548
6016
  if (subagentDashboardOpen && launchpadGate()) {
5549
6017
  // No kernel serves agents from other sessions yet, so the dashboard gets
5550
6018
  // no `peers`; once one does, pass them here.
5551
- const dashboard = (_jsx(SubagentDashboard, { subagents: [...channel.subagents], onSelect: (id) => {
6019
+ const dashboard = (_jsx(SubagentDashboard, { subagents: [...channel.subagents], team: channel.team, sessionId: channel.sessionId, onSelect: (id) => {
5552
6020
  setSubagentDashboardOpen(false);
5553
6021
  setSubagentDetailId(id);
5554
6022
  }, onOpenView: (id) => openAgentView(id, { kind: 'agents-dashboard' }), messages: channel.subagentControl?.message?.messages(), onClose: () => setSubagentDashboardOpen(false) }));
@@ -5598,7 +6066,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5598
6066
  let launchpadPermission;
5599
6067
  try {
5600
6068
  const snapshot = channel.permissionPresets();
5601
- launchpadPermission = snapshot.availability === 'runtime' ? snapshot.current?.name : undefined;
6069
+ launchpadPermission = snapshot.availability === 'runtime' ? currentPermissionName(snapshot) : undefined;
5602
6070
  }
5603
6071
  catch {
5604
6072
  launchpadPermission = undefined;
@@ -5618,10 +6086,22 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5618
6086
  jobsRunning: (channel.backgroundJobs ?? []).some(job => job.status === 'running' || job.status === 'stopping'),
5619
6087
  updateAvailable: launchpadUpdateAvailable,
5620
6088
  starDue: launchpadStarDue,
5621
- // 内核入口带名(「内核 · Claude」):backendId 是内核身份的唯一来源。
6089
+ // 内核入口带名(「内核 · Claude」):backendId 是内核身份的唯一来源,
6090
+ // 名字取同一份选择器目录里的短品牌名(manifest 的 shortLabel)。
5622
6091
  backendId: kernelCurrentId,
6092
+ backendLabel: kernelCurrentOption?.shortLabel,
5623
6093
  });
5624
- const launchpad = (_jsx(Launchpad, { query: launchpadDraft, cursorOffset: launchpadCaret, focusIndex: launchpadFocus, isTerminalFocused: terminalFocused, whale: channel.whale, whaleIdle: channel.whaleIdle, whaleGirl: channel.whaleGirl, fontId: splashFontIdOf(channel.splashFont), brand: brand, starred: starred, onStarClick: runStarAction, firstRun: onboardingPending, actions: launchpadActions,
6094
+ const lastNotification = channel.notifications.at(-1);
6095
+ // While the session's backend is still starting (the status line's
6096
+ // `status-starting` segment), the Tips row says so — below any notice.
6097
+ const launchpadNotice = lastNotification === undefined
6098
+ ? channel.ready === false && channel.startupFailure === undefined
6099
+ ? { text: t('status-starting', { backend: channel.backendCapabilities?.backendLabel ?? 'DSH' }), color: 'warning' }
6100
+ : undefined
6101
+ : { text: lastNotification.text, ...(lastNotification.color === undefined ? {} : { color: lastNotification.color }) };
6102
+ const launchpad = (_jsx(Launchpad, { query: launchpadDraft, imageComposer: { channel, bindings: launchpadImagesRef.current }, cursorOffset: launchpadCaret, focusIndex: launchpadFocus, isTerminalFocused: terminalFocused, whale: channel.whale, whaleIdle: channel.whaleIdle, whaleGirl: channel.whaleGirl, fontId: splashFontIdOf(channel.splashFont), brand: brand, starred: starred, onStarClick: runStarAction, firstRun: onboardingPending, actions: launchpadActions,
6103
+ // 落地页没有 toast 区:最近一条 channel 通知借 Tips 行显示。
6104
+ notice: launchpadNotice,
5625
6105
  // 参数行四段点开的既有选择器(第五版):pickerPanels 与聊天页共用
5626
6106
  // 同一份 JSX,盖在落地页之上;选择器开着时落地页键盘让位(inputPaused)。
5627
6107
  overlayPanel: launchpadOverlayUp ? pickerPanels : undefined, inputPaused: launchpadOverlayUp, onParamPick: (segment) => {
@@ -5642,10 +6122,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5642
6122
  dispatchOverlay({ type: 'close' });
5643
6123
  }
5644
6124
  void runCommand(segment, '');
5645
- }, onQueryChange: (text, cursor) => {
5646
- setLaunchpadDraft(text);
5647
- setLaunchpadCaret(cursor);
5648
- }, onSubmit: closeLaunchpad, onFocusChange: setLaunchpadFocus, onAction: (action) => {
6125
+ }, onQueryChange: changeLaunchpadDraft, onSubmit: submitLaunchpad, onFocusChange: setLaunchpadFocus, onAction: (action) => {
5649
6126
  // 第八版(用户实测:「刚点帮助,不知道为什么直接进入聊天页面了」):
5650
6127
  // 帮助**不属于**离开启动页的两条路(Enter 发非命令消息 / 会话浏览
5651
6128
  // 里选中会话)——它盖在落地页之上(overlay kind 'help'),再点同一
@@ -5663,6 +6140,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5663
6140
  // launchpadGate 的授权位(防御:异步误置的整屏状态盖不走启动页)。
5664
6141
  // 其余命令(star / update——反馈在对话页的转录/通知)仍收掉落地页
5665
6142
  // 再执行,这是用户主动执行命令,不是「返回」。
6143
+ if (refusedAtStartup(action.command))
6144
+ return;
5666
6145
  if (launchpadScreenCommands.has(action.command)) {
5667
6146
  authorizeLaunchpadCover();
5668
6147
  }
@@ -5693,26 +6172,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5693
6172
  ? undefined
5694
6173
  : presetOptions.find(option => option.id === channel.agentPreset)?.name ?? channel.agentPreset, permission: launchpadPermission, commands: launchpadOverlayUp || !launchpadDraft.startsWith('/')
5695
6174
  ? undefined
5696
- : channel.commandCompletions(launchpadDraft), onCommandPick: (commandLine) => {
5697
- // 补全面板选中(Enter/Tab/点击):走 runCommand,与快捷入口同一条
5698
- // 白名单口径——覆盖层与整屏命令(第七版 launchpadScreenCommands)
5699
- // 不收落地页(盖在它之上),其余收掉再执行。/help 与快捷入口同一条
5700
- // 拦截:盖屏浮层,不进对话页(第八版)。
5701
- const parsed = parseCommandName(commandLine);
5702
- if (parsed === undefined)
5703
- return;
5704
- if (parsed.name === 'help') {
5705
- dispatchOverlay({ type: 'open', overlay: { kind: 'help' } });
5706
- return;
5707
- }
5708
- if (launchpadScreenCommands.has(parsed.name)) {
5709
- authorizeLaunchpadCover();
5710
- }
5711
- else if (!overlayCommandNames.has(parsed.name)) {
5712
- setLaunchpadOpen(false);
5713
- }
5714
- void runCommand(parsed.name, parsed.rawInput);
5715
- }, cwd: channel.displayCwd, branch: channel.gitBranch, tuiVersion: tuiVersion,
6175
+ : channel.commandCompletions(launchpadDraft), onCommandPick: submitLaunchpad, cwd: channel.displayCwd, branch: channel.gitBranch, tuiVersion: tuiVersion,
5716
6176
  // 右下角的内核行:与选择器同一份目录,标出当前内核,点它打开选择器。
5717
6177
  kernels: kernelOptions, onKernelPick: () => openKernelPicker(),
5718
6178
  // 左下角工作目录铭牌(第七版):点开/回车开既有 /workspace 菜单——
@@ -5772,7 +6232,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5772
6232
  ? () => setPeekSuppressed(peekKey(activePreview.image, activePreview.title))
5773
6233
  : () => dispatchOverlay({ type: 'close-if', kind: 'image-preview' }), region: imagePreviewRegion }))
5774
6234
  : null;
5775
- return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [_jsxs(SidePanelLayout, { geometry: sidePanel.geometry, focus: sidePanel.focus, onActivateChat: sidePanel.focusChat, onActivatePanel: sidePanel.focusPanel, side: _jsx(SidePanelColumn, { width: sidePanel.panelColumns, controller: sidePanel, channel: channel, activity: workingActivity, attention: {
6235
+ return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [_jsxs(SidePanelLayout, { geometry: sidePanel.geometry, focus: sidePanel.focus, onActivateChat: sidePanel.focusChat, onActivatePanel: sidePanel.focusPanel, onResize: sidePanel.resize, side: _jsx(SidePanelColumn, { width: sidePanel.panelColumns, controller: sidePanel, channel: channel, activity: workingActivity, attention: {
5776
6236
  approvals: approvalSnapshot !== null ? 1 : 0,
5777
6237
  questions: questionSnapshot !== null ? 1 : 0,
5778
6238
  }, trajectory: trajectory, onExpand: openPanelFullscreen }), children: [!isSticky && timeline.activeId !== null && (_jsx(PinnedTurnHeader, { text: anchorUserText || null, onClick: () => {
@@ -5852,6 +6312,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5852
6312
  writeRaw?.(raw); });
5853
6313
  channel.notify(t('copied-chars', { n: answer.length }), { timeoutMs: 1500 });
5854
6314
  } }) })) : questionPanelNode !== null ? (questionPanelNode) : null, _jsx(PromptInput, { channel: channel, suspended: promptReplacementOpen,
6315
+ // 选择器、搜索框或侧栏持有键盘焦点时,让对应输入框接管原生
6316
+ // 光标与 IME 锚点,避免主输入框在后续提交中抢回声明。
6317
+ cursorParking: overlay.kind === 'none' && sidePanel.focus !== 'panel',
5855
6318
  // 宠物面板是活动面板时,通知由它的头顶气泡「说出来」,输入框上方
5856
6319
  // 不再重复弹同一条(error 色除外——可能要行动的信号永远走 toast)。
5857
6320
  // 渲染期判定(split + activePanelId),与气泡同一次提交切换,不会
@@ -5865,7 +6328,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
5865
6328
  onOpenSessions: () => {
5866
6329
  agentViewOpenSessionRef.current = channel.agentId;
5867
6330
  setSupervisorOpen(true);
5868
- }, backgroundAgentsNeedingInput:
6331
+ },
6332
+ // 当前内核的短品牌名:与选择器、落地页铭牌同一份 manifest 数据(P0 D2)。
6333
+ backendLabel: kernelCurrentOption?.shortLabel, backgroundAgentsNeedingInput:
5869
6334
  // Only the real channel supplies the seam; pre-agent-view test
5870
6335
  // stubs must not grow the footer row (layout-dependent
5871
6336
  // regressions pin the visible row count). The footer only
@@ -5920,15 +6385,12 @@ function NewMessagesPill({ count, onClick, }) {
5920
6385
  ? t(count === 1 ? 'new-message' : 'new-messages', { n: count })
5921
6386
  : t('back-to-bottom'), ' '] }) }) }));
5922
6387
  }
5923
- /** /model while the provider catalog is still loading. */
5924
- function ModelPickerLoading() {
5925
- return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Text, { bold: true, color: "permission", children: t('picker-title-model') }), _jsx(LoadingState, { message: t('model-loading'), bold: true, subtitle: t('model-loading-subtitle') })] }) }));
5926
- }
5927
6388
  /**
5928
6389
  * The `/` incsearch bar: a
5929
6390
  * single row above the prompt input with the query, a block cursor, and the
5930
6391
  * match counter (`current/count`) or a red `no matches` when nothing hits.
5931
6392
  */ function TranscriptSearch({ query, cursorOffset, count, current, }) {
5932
- const cursorChar = cursorOffset < query.length ? query[cursorOffset] : ' ';
5933
- return (_jsxs(NoSelect, { borderTopDimColor: true, borderBottom: false, borderLeft: false, borderRight: false, borderStyle: "single", marginTop: 1, paddingLeft: 2, width: "100%", children: [_jsx(Text, { children: "/" }), _jsx(Text, { children: query.slice(0, cursorOffset) }), _jsx(Text, { inverse: true, children: cursorChar }), cursorOffset < query.length && _jsx(Text, { children: query.slice(cursorOffset + 1) }), _jsx(Box, { flexGrow: 1 }), query && count === 0 ? (_jsxs(Text, { color: "error", children: [t('search-no-matches'), " "] })) : count > 0 ? (_jsxs(Text, { dimColor: true, children: [Math.min(current + 1, count), "/", count, ' '] })) : null] }));
6393
+ const caretOffset = cursorOffset < query.length ? previousCodePoint(query, cursorOffset + 1) : query.length;
6394
+ const cursorChar = [...query.slice(caretOffset)][0] ?? ' ';
6395
+ return (_jsxs(NoSelect, { borderTopDimColor: true, borderBottom: false, borderLeft: false, borderRight: false, borderStyle: "single", marginTop: 1, paddingLeft: 2, width: "100%", children: [_jsx(Text, { children: "/" }), _jsx(Text, { children: query.slice(0, caretOffset) }), _jsx(InputCaret, { children: cursorChar }), caretOffset < query.length && _jsx(Text, { children: query.slice(caretOffset + cursorChar.length) }), _jsx(Box, { flexGrow: 1 }), query && count === 0 ? (_jsxs(Text, { color: "error", children: [t('search-no-matches'), " "] })) : count > 0 ? (_jsxs(Text, { dimColor: true, children: [Math.min(current + 1, count), "/", count, ' '] })) : null] }));
5934
6396
  }