@deepseek-harness-tui/dsh-tui 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +92 -5
  2. package/guide/dsh-tui-guide/codex-backend.en.md +13 -3
  3. package/guide/dsh-tui-guide/codex-backend.md +9 -2
  4. package/guide/dsh-tui-guide/configuration.en.md +39 -2
  5. package/guide/dsh-tui-guide/configuration.md +34 -2
  6. package/guide/dsh-tui-guide/getting-started.en.md +15 -0
  7. package/guide/dsh-tui-guide/getting-started.md +15 -0
  8. package/guide/dsh-tui-guide/interaction.en.md +8 -1
  9. package/guide/dsh-tui-guide/interaction.md +8 -1
  10. package/guide/dsh-tui-guide/plugins.en.md +66 -5
  11. package/guide/dsh-tui-guide/plugins.md +37 -3
  12. package/guide/dsh-tui-guide/user-guide.en.md +3 -2
  13. package/guide/dsh-tui-guide/user-guide.md +3 -2
  14. package/lib/settings.json +1 -1
  15. package/lib/types/adapter/channel/projection.d.ts.map +1 -1
  16. package/lib/types/adapter/channel/projection.js +1 -0
  17. package/lib/types/adapter/channel/ui-policy.d.ts +1 -1
  18. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  19. package/lib/types/adapter/channel/ui-policy.js +1 -0
  20. package/lib/types/adapter/ports/channel-catalog.d.ts +5 -1
  21. package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
  22. package/lib/types/adapter/ports/channel-settings.d.ts +5 -3
  23. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  24. package/lib/types/adapter/ports/channel-ui.d.ts +7 -1
  25. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  26. package/lib/types/adapter/ports/channel-view.d.ts +47 -0
  27. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  28. package/lib/types/adapter/ports/channel.d.ts +2 -0
  29. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  30. package/lib/types/agent/events.d.ts +3 -2
  31. package/lib/types/agent/events.d.ts.map +1 -1
  32. package/lib/types/backends/codex/contract.d.ts +3 -0
  33. package/lib/types/backends/codex/contract.d.ts.map +1 -1
  34. package/lib/types/backends/codex/contract.js +3 -0
  35. package/lib/types/backends/codex/session/async-questions.d.ts +17 -0
  36. package/lib/types/backends/codex/session/async-questions.d.ts.map +1 -0
  37. package/lib/types/backends/codex/session/async-questions.js +89 -0
  38. package/lib/types/backends/codex/session/session.d.ts.map +1 -1
  39. package/lib/types/backends/codex/session/session.js +35 -9
  40. package/lib/types/backends/codex/text.d.ts +3 -3
  41. package/lib/types/backends/codex/text.js +1 -1
  42. package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
  43. package/lib/types/backends/codex/translate/items.js +3 -1
  44. package/lib/types/backends/codex/translate/question-reply.d.ts +11 -0
  45. package/lib/types/backends/codex/translate/question-reply.d.ts.map +1 -0
  46. package/lib/types/backends/codex/translate/question-reply.js +53 -0
  47. package/lib/types/channel/projection.d.ts.map +1 -1
  48. package/lib/types/channel/projection.js +10 -0
  49. package/lib/types/commands.d.ts +10 -0
  50. package/lib/types/commands.d.ts.map +1 -1
  51. package/lib/types/commands.js +11 -2
  52. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  53. package/lib/types/components/CommandSuggestions.js +4 -1
  54. package/lib/types/components/LogoV2.d.ts +4 -1
  55. package/lib/types/components/LogoV2.d.ts.map +1 -1
  56. package/lib/types/components/LogoV2.js +5 -3
  57. package/lib/types/components/MessageList.d.ts.map +1 -1
  58. package/lib/types/components/MessageList.js +95 -14
  59. package/lib/types/components/PermissionsPicker.d.ts +10 -1
  60. package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
  61. package/lib/types/components/PermissionsPicker.js +24 -16
  62. package/lib/types/components/PluginInstallPane.d.ts +21 -0
  63. package/lib/types/components/PluginInstallPane.d.ts.map +1 -0
  64. package/lib/types/components/PluginInstallPane.js +84 -0
  65. package/lib/types/components/PluginManagePane.d.ts +21 -0
  66. package/lib/types/components/PluginManagePane.d.ts.map +1 -0
  67. package/lib/types/components/PluginManagePane.js +69 -0
  68. package/lib/types/components/PromptInput.d.ts.map +1 -1
  69. package/lib/types/components/PromptInput.js +7 -3
  70. package/lib/types/components/SubagentCard.d.ts +13 -1
  71. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  72. package/lib/types/components/SubagentCard.js +27 -12
  73. package/lib/types/components/SubagentDashboard.d.ts +8 -1
  74. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  75. package/lib/types/components/SubagentDashboard.js +58 -16
  76. package/lib/types/components/launchpadLayout.d.ts +14 -1
  77. package/lib/types/components/launchpadLayout.d.ts.map +1 -1
  78. package/lib/types/components/launchpadLayout.js +36 -17
  79. package/lib/types/components/messages/TeamMessageBubble.d.ts +20 -0
  80. package/lib/types/components/messages/TeamMessageBubble.d.ts.map +1 -0
  81. package/lib/types/components/messages/TeamMessageBubble.js +15 -0
  82. package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -1
  83. package/lib/types/components/sidePanel/PanelHost.js +5 -1
  84. package/lib/types/components/sidePanel/PanelStore.d.ts +8 -0
  85. package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
  86. package/lib/types/components/sidePanel/PanelStore.js +11 -0
  87. package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
  88. package/lib/types/components/sidePanel/SidePanelColumn.js +13 -1
  89. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +7 -0
  90. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -1
  91. package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +4 -0
  92. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +3 -0
  93. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
  94. package/lib/types/components/sidePanel/btw/BtwComposer.js +20 -8
  95. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +2 -1
  96. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -1
  97. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +104 -13
  98. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +6 -2
  99. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -1
  100. package/lib/types/components/sidePanel/btw/BtwThreadScene.js +61 -15
  101. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +14 -4
  102. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
  103. package/lib/types/components/sidePanel/btw/BtwThreadView.js +90 -5
  104. package/lib/types/components/sidePanel/btw/threads.d.ts +18 -0
  105. package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -1
  106. package/lib/types/components/sidePanel/btw/threads.js +51 -0
  107. package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
  108. package/lib/types/components/sidePanel/builtinPanels.js +5 -1
  109. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +5 -1
  110. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -1
  111. package/lib/types/components/sidePanel/companion/SplashMascot.js +19 -4
  112. package/lib/types/components/sidePanel/companion/skins.d.ts +8 -0
  113. package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
  114. package/lib/types/components/sidePanel/companion/skins.js +57 -12
  115. package/lib/types/components/sidePanel/types.d.ts +6 -0
  116. package/lib/types/components/sidePanel/types.d.ts.map +1 -1
  117. package/lib/types/components/splashArtRows.d.ts +29 -0
  118. package/lib/types/components/splashArtRows.d.ts.map +1 -0
  119. package/lib/types/components/splashArtRows.js +31 -0
  120. package/lib/types/components/teamRoster.d.ts +70 -0
  121. package/lib/types/components/teamRoster.d.ts.map +1 -0
  122. package/lib/types/components/teamRoster.js +78 -0
  123. package/lib/types/dsh-adapter/admission-loader.d.ts +82 -0
  124. package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/admission-loader.js +73 -28
  126. package/lib/types/dsh-adapter/agent-view.d.ts.map +1 -1
  127. package/lib/types/dsh-adapter/agent-view.js +3 -1
  128. package/lib/types/dsh-adapter/approvals.d.ts +7 -0
  129. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  130. package/lib/types/dsh-adapter/approvals.js +45 -1
  131. package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/backend/translate.js +68 -8
  133. package/lib/types/dsh-adapter/backend-assembly.d.ts +31 -0
  134. package/lib/types/dsh-adapter/backend-assembly.d.ts.map +1 -0
  135. package/lib/types/dsh-adapter/backend-assembly.js +225 -0
  136. package/lib/types/dsh-adapter/backend-contribution.d.ts +36 -0
  137. package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/backend-contribution.js +41 -0
  139. package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/backend-registry.js +22 -3
  141. package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
  142. package/lib/types/dsh-adapter/backends.js +4 -5
  143. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  144. package/lib/types/dsh-adapter/bundled-presets.js +60 -3
  145. package/lib/types/dsh-adapter/channel/binding-events.d.ts +1 -0
  146. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  147. package/lib/types/dsh-adapter/channel/binding-events.js +1 -0
  148. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  149. package/lib/types/dsh-adapter/channel/command-completions.js +64 -7
  150. package/lib/types/dsh-adapter/channel/compaction.d.ts +7 -2
  151. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  152. package/lib/types/dsh-adapter/channel/compaction.js +100 -26
  153. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +3 -0
  154. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
  155. package/lib/types/dsh-adapter/channel/core/binding-feed.js +2 -1
  156. package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
  157. package/lib/types/dsh-adapter/channel/core/compose.js +12 -0
  158. package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/extensions.js +68 -8
  160. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +6 -0
  161. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +104 -12
  163. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  164. package/lib/types/dsh-adapter/channel/model-actions.js +8 -1
  165. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  166. package/lib/types/dsh-adapter/channel/permissions.js +4 -1
  167. package/lib/types/dsh-adapter/channel/projection-helpers.d.ts.map +1 -1
  168. package/lib/types/dsh-adapter/channel/projection-helpers.js +2 -0
  169. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  170. package/lib/types/dsh-adapter/channel/session-metadata.js +4 -3
  171. package/lib/types/dsh-adapter/channel/session-reset.js +2 -2
  172. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  173. package/lib/types/dsh-adapter/channel/session-resume.js +7 -0
  174. package/lib/types/dsh-adapter/channel/settings-host.d.ts +3 -0
  175. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  176. package/lib/types/dsh-adapter/channel/settings-host.js +135 -5
  177. package/lib/types/dsh-adapter/channel/state.d.ts +6 -0
  178. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  180. package/lib/types/dsh-adapter/channel/subagent-projection.js +18 -6
  181. package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -0
  182. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  183. package/lib/types/dsh-adapter/channel/transcript.js +19 -2
  184. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts +55 -0
  185. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts.map +1 -0
  186. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.js +96 -0
  187. package/lib/types/dsh-adapter/contract.d.ts +4 -4
  188. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  189. package/lib/types/dsh-adapter/contract.js +5 -5
  190. package/lib/types/dsh-adapter/effect-ledger.d.ts +7 -0
  191. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  192. package/lib/types/dsh-adapter/effect-ledger.js +8 -1
  193. package/lib/types/dsh-adapter/entry-slot.d.ts +3 -1
  194. package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -1
  195. package/lib/types/dsh-adapter/entry-slot.js +2 -2
  196. package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -1
  197. package/lib/types/dsh-adapter/fresh-agent.js +6 -1
  198. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
  199. package/lib/types/dsh-adapter/host-access.js +95 -0
  200. package/lib/types/dsh-adapter/host-contract.d.ts +1 -1
  201. package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -1
  202. package/lib/types/dsh-adapter/host-contract.js +3 -2
  203. package/lib/types/dsh-adapter/host-dsh.d.ts +8 -2
  204. package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/host-dsh.js +45 -30
  206. package/lib/types/dsh-adapter/host-entry.js +35 -10
  207. package/lib/types/dsh-adapter/index.d.ts +9 -10
  208. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  209. package/lib/types/dsh-adapter/index.js +8 -6
  210. package/lib/types/dsh-adapter/invariant.d.ts +7 -2
  211. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -1
  212. package/lib/types/dsh-adapter/invariant.js +6 -3
  213. package/lib/types/dsh-adapter/migrate/index.js +2 -2
  214. package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
  215. package/lib/types/dsh-adapter/panels.js +6 -0
  216. package/lib/types/dsh-adapter/plugin-declaration.d.ts +99 -1
  217. package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -1
  218. package/lib/types/dsh-adapter/plugin-declaration.js +132 -2
  219. package/lib/types/dsh-adapter/plugin-feed.d.ts +94 -0
  220. package/lib/types/dsh-adapter/plugin-feed.d.ts.map +1 -0
  221. package/lib/types/dsh-adapter/plugin-feed.js +135 -0
  222. package/lib/types/dsh-adapter/plugin-guard.d.ts +115 -0
  223. package/lib/types/dsh-adapter/plugin-guard.d.ts.map +1 -0
  224. package/lib/types/dsh-adapter/plugin-guard.js +108 -0
  225. package/lib/types/dsh-adapter/plugin-install.d.ts +160 -0
  226. package/lib/types/dsh-adapter/plugin-install.d.ts.map +1 -0
  227. package/lib/types/dsh-adapter/plugin-install.js +545 -0
  228. package/lib/types/dsh-adapter/plugin-manage.d.ts +178 -0
  229. package/lib/types/dsh-adapter/plugin-manage.d.ts.map +1 -0
  230. package/lib/types/dsh-adapter/plugin-manage.js +468 -0
  231. package/lib/types/dsh-adapter/plugin-manager.d.ts +78 -2
  232. package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -1
  233. package/lib/types/dsh-adapter/plugin-manager.js +32 -0
  234. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  235. package/lib/types/dsh-adapter/plugin.js +49 -2
  236. package/lib/types/dsh-adapter/plugins-info.d.ts +87 -1
  237. package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
  238. package/lib/types/dsh-adapter/plugins-info.js +131 -26
  239. package/lib/types/dsh-adapter/process-exit.d.ts +1 -1
  240. package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -1
  241. package/lib/types/dsh-adapter/process-exit.js +1 -1
  242. package/lib/types/dsh-adapter/session-projection-store.d.ts +66 -0
  243. package/lib/types/dsh-adapter/session-projection-store.d.ts.map +1 -0
  244. package/lib/types/dsh-adapter/session-projection-store.js +149 -0
  245. package/lib/types/dsh-adapter/settingsEditor.js +2 -2
  246. package/lib/types/dsh-adapter/sideQuestion.d.ts +21 -0
  247. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  248. package/lib/types/dsh-adapter/sideQuestion.js +53 -0
  249. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  250. package/lib/types/dsh-adapter/subagents.js +2 -1
  251. package/lib/types/dsh-adapter/team-mode.d.ts +74 -0
  252. package/lib/types/dsh-adapter/team-mode.d.ts.map +1 -0
  253. package/lib/types/dsh-adapter/team-mode.js +188 -0
  254. package/lib/types/dsh-adapter/team-roster.d.ts +67 -0
  255. package/lib/types/dsh-adapter/team-roster.d.ts.map +1 -0
  256. package/lib/types/dsh-adapter/team-roster.js +136 -0
  257. package/lib/types/dsh-adapter/team-tools.d.ts +58 -0
  258. package/lib/types/dsh-adapter/team-tools.d.ts.map +1 -0
  259. package/lib/types/dsh-adapter/team-tools.js +208 -0
  260. package/lib/types/dsh-adapter/types.d.ts +1 -1
  261. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  262. package/lib/types/i18n.d.ts +607 -16
  263. package/lib/types/i18n.d.ts.map +1 -1
  264. package/lib/types/i18n.js +295 -9
  265. package/lib/types/ink/components/ScrollBox.d.ts +9 -0
  266. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  267. package/lib/types/ink/components/ScrollBox.js +23 -0
  268. package/lib/types/ink/dom.d.ts.map +1 -1
  269. package/lib/types/kernelPrefs.d.ts +1 -1
  270. package/lib/types/kernelPrefs.d.ts.map +1 -1
  271. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  272. package/lib/types/native-ts/yoga-layout/index.js +8 -1
  273. package/lib/types/permissionPresetLabels.d.ts +25 -0
  274. package/lib/types/permissionPresetLabels.d.ts.map +1 -0
  275. package/lib/types/permissionPresetLabels.js +33 -0
  276. package/lib/types/preset-patch.d.ts +22 -0
  277. package/lib/types/preset-patch.d.ts.map +1 -0
  278. package/lib/types/preset-patch.js +14 -0
  279. package/lib/types/screens/Chat.d.ts +33 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +301 -9
  282. package/lib/types/screens/Launchpad.d.ts +7 -1
  283. package/lib/types/screens/Launchpad.d.ts.map +1 -1
  284. package/lib/types/screens/Launchpad.js +19 -4
  285. package/lib/types/screens/Settings.d.ts.map +1 -1
  286. package/lib/types/screens/Settings.js +1 -0
  287. package/lib/types/screens/chat/usePluginWriteFlow.d.ts +68 -0
  288. package/lib/types/screens/chat/usePluginWriteFlow.d.ts.map +1 -0
  289. package/lib/types/screens/chat/usePluginWriteFlow.js +92 -0
  290. package/lib/types/screens/chatOverlay.d.ts +19 -1
  291. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  292. package/lib/types/sessionModes.d.ts +5 -3
  293. package/lib/types/sessionModes.d.ts.map +1 -1
  294. package/lib/types/sessionModes.js +9 -3
  295. package/lib/types/tips.js +2 -2
  296. package/lib/types/utils/paths.d.ts +11 -0
  297. package/lib/types/utils/paths.d.ts.map +1 -1
  298. package/lib/types/utils/paths.js +13 -0
  299. package/package.json +126 -120
  300. package/tui-profile/feed/README.md +63 -0
  301. package/tui-profile/feed/first-party.json +10 -0
@@ -80,7 +80,10 @@ export function CommandSuggestions({ commands, selectedIndex, columns, query = '
80
80
  : stringWidth(rawDescription) > descriptionWidth
81
81
  ? truncateToWidth(rawDescription, descriptionWidth - 1) + '…'
82
82
  : rawDescription;
83
- const padAfter = Math.max(0, nameWidth - stringWidth(command.name));
83
+ // 名字比名字列还宽时(长 spec、长 bundle 名)差值为 0,描述会贴着名字
84
+ // 渲染成 `…ple.gitInstall from a git URL`——至少留一格分隔;超出的这一格
85
+ // 由行尾的 truncate 裁掉,行内容不会因此多出一行。
86
+ const padAfter = Math.max(1, nameWidth - stringWidth(command.name));
84
87
  // 灰区整行一个 `subtle`,且刻意不做查询命中提亮(灰区不该看起来像
85
88
  // 「可用」)。选中行仍走下方通用样式,保证光标始终可见。
86
89
  if (isHeld && !isSelected) {
@@ -3,6 +3,7 @@ import { type Tip } from '../tips.js';
3
3
  import { type UpstreamDriftSummary } from '../dsh-adapter/contract.js';
4
4
  import { type Brand } from '../branding.js';
5
5
  import { type SplashEgg } from './splashEggs.js';
6
+ import type { SplashImageBox } from './splashArtRows.js';
6
7
  import { type WhaleIntroId } from './whaleFrames.js';
7
8
  /**
8
9
  * The header splash: one layout, two phases. The **opening** (~1.7–3.5s,
@@ -32,7 +33,7 @@ import { type WhaleIntroId } from './whaleFrames.js';
32
33
  * with a clickable "star us on GitHub" line whose indent is recomputed from
33
34
  * its own width.
34
35
  */
35
- export declare function LogoV2({ model, effort, cwd, skipIntro, intro, tip, fontId, whale, whaleIdle, whaleGirl, brand, starred, starReveal, onStarClick, working, drift, egg, starChance, align, chrome, arrangement, companionSkin, }: {
36
+ export declare function LogoV2({ model, effort, cwd, skipIntro, intro, tip, fontId, whale, whaleIdle, whaleGirl, brand, starred, starReveal, onStarClick, working, drift, egg, starChance, align, chrome, arrangement, companionSkin, mascotBox, }: {
36
37
  /** 模型/effort/工作目录只画在 full 形态里;minimal(落地页)不传也行。 */
37
38
  model?: string;
38
39
  effort?: string | undefined;
@@ -128,5 +129,7 @@ export declare function LogoV2({ model, effort, cwd, skipIntro, intro, tip, font
128
129
  /** 测试缝:钉住启动页吉祥物皮肤(undefined——生产——读 companion.skin;
129
130
  * 'whale'/未知 = 维持原鲸鱼/女仆娘路径,见 SplashMascot.tsx)。 */
130
131
  companionSkin?: string;
132
+ /** 落地页传入与高度预算相同的紧凑图片槽。 */
133
+ mascotBox?: SplashImageBox;
131
134
  }): React.ReactNode;
132
135
  //# sourceMappingURL=LogoV2.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAiB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAoD,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAMxH,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAM9E,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAU/E,OAAO,EAA+E,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AA+CjI;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAU,EACV,MAAM,EACN,GAAQ,EACR,SAAiB,EACjB,KAAK,EACL,GAAG,EACH,MAAM,EACN,KAAY,EACZ,SAAgB,EAChB,SAAiB,EACjB,KAAkB,EAClB,OAAe,EACf,UAAU,EACV,WAAW,EACX,OAAe,EACf,KAAK,EACL,GAAG,EACH,UAAU,EACV,KAAe,EACf,MAAe,EACf,WAAmB,EACnB,aAAa,GACd,EAAE;IACD,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB;0CACsC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,GAAG,CAAA;IACT;;qCAEiC;IACjC,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB;oEACgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;;8CAO0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;mCAG+B;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,UAAU,CAAC,EAAE,SAAS,CAAA;IACtB;sCACkC;IAClC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB;;;4CAGwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;mCAG+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;2EACuE;IACvE,KAAK,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACnC;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC9B;wDACoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,GAAG,KAAK,CAAC,SAAS,CA0jBlB"}
1
+ {"version":3,"file":"LogoV2.d.ts","sourceRoot":"","sources":["../../../src/components/LogoV2.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAiB,KAAK,GAAG,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,EAAoD,KAAK,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAMxH,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAM9E,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAU/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACxD,OAAO,EAA+E,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAA;AA+CjI;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,MAAM,CAAC,EACrB,KAAU,EACV,MAAM,EACN,GAAQ,EACR,SAAiB,EACjB,KAAK,EACL,GAAG,EACH,MAAM,EACN,KAAY,EACZ,SAAgB,EAChB,SAAiB,EACjB,KAAkB,EAClB,OAAe,EACf,UAAU,EACV,WAAW,EACX,OAAe,EACf,KAAK,EACL,GAAG,EACH,UAAU,EACV,KAAe,EACf,MAAe,EACf,WAAmB,EACnB,aAAa,EACb,SAAS,GACV,EAAE;IACD,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iFAAiF;IACjF,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,YAAY,CAAA;IACpB;0CACsC;IACtC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,6EAA6E;IAC7E,GAAG,CAAC,EAAE,GAAG,CAAA;IACT;;qCAEiC;IACjC,GAAG,CAAC,EAAE,SAAS,GAAG,IAAI,CAAA;IACtB;oEACgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,CAAA;IACf;;;;;;;8CAO0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;mCAG+B;IAC/B,KAAK,CAAC,EAAE,KAAK,CAAA;IACb,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,UAAU,CAAC,EAAE,SAAS,CAAA;IACtB;sCACkC;IAClC,WAAW,CAAC,EAAE,MAAM,IAAI,CAAA;IACxB;;;4CAGwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;mCAG+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;2EACuE;IACvE,KAAK,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACnC;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IAC1B;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC9B;wDACoD;IACpD,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,cAAc,CAAA;CAC3B,GAAG,KAAK,CAAC,SAAS,CA4jBlB"}
@@ -23,7 +23,7 @@ import { STANDARD_FRAME_INDEX, WhaleArt } from './Whale.js';
23
23
  import { WhaleGirlArt } from './WhaleGirl.js';
24
24
  import { ClaudeGirlArt } from './ClaudeGirl.js';
25
25
  import { MAID_BOX_CENTER, MaidPortrait, portraitAssetsOf, useMaidPortraits } from './maidPortrait.js';
26
- import { SplashMascot, useSplashMascotSkin } from './sidePanel/companion/SplashMascot.js';
26
+ import { SplashMascot, useSplashMascotSkin, useSplashMascotBox } from './sidePanel/companion/SplashMascot.js';
27
27
  import { OPENING_SEQUENCES, pickOpeningSequence, WHALE_FRAME_INDEX } from './whaleFrames.js';
28
28
  import { RESTING_POSE } from './whaleLayers.js';
29
29
  import { initialWhaleIdleState, nextWhaleIdleStep, } from './whaleIdle.js';
@@ -90,7 +90,7 @@ function capitalize(text) {
90
90
  * with a clickable "star us on GitHub" line whose indent is recomputed from
91
91
  * its own width.
92
92
  */
93
- export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro, tip, fontId, whale = true, whaleIdle = true, whaleGirl = false, brand = 'deepseek', starred = false, starReveal, onStarClick, working = false, drift, egg, starChance, align = 'start', chrome = 'full', arrangement = 'row', companionSkin, }) {
93
+ export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro, tip, fontId, whale = true, whaleIdle = true, whaleGirl = false, brand = 'deepseek', starred = false, starReveal, onStarClick, working = false, drift, egg, starChance, align = 'start', chrome = 'full', arrangement = 'row', companionSkin, mascotBox, }) {
94
94
  // One intro per logo mount: the production path rolls (startup splash
95
95
  // and each /deepseek replay roll independently), the `intro` seam pins
96
96
  // a specific animation for probes.
@@ -127,6 +127,8 @@ export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro,
127
127
  // 'whale'/未知皮肤 → undefined,原路径零改动。冻结/落地页(whaleIdle=
128
128
  // false)时吉祥物定格 idle 帧 0、零时钟(SplashMascot 内部保证)。
129
129
  const mascotSkin = useSplashMascotSkin(companionSkin);
130
+ const compactMascotBox = useSplashMascotBox(mascotSkin, brand === 'deepseek' && arrangement === 'column' && chrome === 'minimal');
131
+ const imageBox = mascotBox ?? compactMascotBox;
130
132
  // ── Whale behaviors (ported from the dsh-ui-whale pet) ─────────────────
131
133
  // Intro-phase click → heart pass: whole heart frames over the opening
132
134
  // animation (one-way heart1→heart2→heart3). Once the header settles, the
@@ -475,7 +477,7 @@ export function LogoV2({ model = '', effort, cwd = '', skipIntro = false, intro,
475
477
  setHeartSeq(0);
476
478
  setHeartKey(k => k + 1);
477
479
  }
478
- }, children: _jsx(Box, { width: WHALE_BOX_WIDTH, flexDirection: "column", alignItems: "center", children: brand === 'deepseek' && mascotSkin !== undefined ? (_jsx(SplashMascot, { skin: mascotSkin, active: !whaleFrozen && whaleIdle })) : portraitMode ? (_jsx(Box, { width: WHALE_BOX_WIDTH, height: textColumnRows, flexDirection: "row", justifyContent: "center", alignItems: "center", children: maidImageActive ? (_jsx(MaidPortrait, { source: maidHappy ? (portraits?.happy ?? maidSource) : maidSource, maxColumns: WHALE_BOX_WIDTH, maxRows: textColumnRows, presentation: "transcript" })) : (claudeArt ? _jsx(ClaudeGirlArt, { width: WHALE_BOX_WIDTH }) : _jsx(WhaleGirlArt, { width: WHALE_BOX_WIDTH })) })) : (_jsx(WhaleArt, { frameIndex: frameIndex, pose: settled && whaleIdle && !whaleFrozen ? (idlePose ?? RESTING_POSE) : undefined, width: WHALE_BOX_WIDTH })) }) })), (showBigTitle || showPlainTitle) && (_jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [chrome !== 'minimal' && (_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] })), showBigTitle ? (_jsxs(_Fragment, { children: [bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `ds-${index}`))), _jsx(Box, { height: 1 }), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `h-${index}`)))] })) : (showPlainTitle && (_jsx(Text, { color: "accent", bold: true, wrap: "truncate-end", children: words.plain }))), chrome !== 'minimal' && (_jsxs(_Fragment, { children: [_jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), getLang() === 'zh' ? randomTip.zh : randomTip.en, _jsx(Text, { dimColor: true, children: ' · /tips ' + tr('logo-tip-more') })] })] })), chrome !== 'minimal' && driftLine != null && (_jsxs(Text, { color: "warning", wrap: "wrap", children: ["\u26A0", ' ', tOr(`logo-drift-${driftLine.kind}`, `The dsh engine (${driftLine.versions.join(' / ')}) does not match the validated ${UPSTREAM_VALIDATED_VERSION}; reinstall via npm i -g @deepseek-ai/dsh@${UPSTREAM_VALIDATED_VERSION}.`, {
480
+ }, children: _jsx(Box, { width: WHALE_BOX_WIDTH, flexDirection: "column", alignItems: "center", children: brand === 'deepseek' && mascotSkin !== undefined ? (_jsx(SplashMascot, { skin: mascotSkin, active: !whaleFrozen && whaleIdle, imageBox: imageBox })) : portraitMode ? (_jsx(Box, { width: WHALE_BOX_WIDTH, height: textColumnRows, flexDirection: "row", justifyContent: "center", alignItems: "center", children: maidImageActive ? (_jsx(MaidPortrait, { source: maidHappy ? (portraits?.happy ?? maidSource) : maidSource, maxColumns: WHALE_BOX_WIDTH, maxRows: textColumnRows, presentation: "transcript" })) : (claudeArt ? _jsx(ClaudeGirlArt, { width: WHALE_BOX_WIDTH }) : _jsx(WhaleGirlArt, { width: WHALE_BOX_WIDTH })) })) : (_jsx(WhaleArt, { frameIndex: frameIndex, pose: settled && whaleIdle && !whaleFrozen ? (idlePose ?? RESTING_POSE) : undefined, width: WHALE_BOX_WIDTH })) }) })), (showBigTitle || showPlainTitle) && (_jsxs(Box, { flexDirection: "column", flexShrink: 1, children: [chrome !== 'minimal' && (_jsxs(Text, { wrap: "truncate-end", children: [sweep('✦ dsh-TUI', t, wordmarkRGB, wordmarkShimmerRGB, 60), _jsx(Text, { dimColor: true, children: ' v' + VERSION })] })), showBigTitle ? (_jsxs(_Fragment, { children: [bigDeepSeek.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `ds-${index}`))), _jsx(Box, { height: 1 }), bigHarness.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row.replace(/\s+$/u, '') }, `h-${index}`)))] })) : (showPlainTitle && (_jsx(Text, { color: "accent", bold: true, wrap: "truncate-end", children: words.plain }))), chrome !== 'minimal' && (_jsxs(_Fragment, { children: [_jsxs(Text, { wrap: "truncate-end", children: [model, effort !== undefined && _jsx(Text, { dimColor: true, children: ' · ' + capitalize(effort) + ' effort' })] }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: cwd }), _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { dimColor: true, children: tr('logo-tip-prefix') }), getLang() === 'zh' ? randomTip.zh : randomTip.en, _jsx(Text, { dimColor: true, children: ' · /tips ' + tr('logo-tip-more') })] })] })), chrome !== 'minimal' && driftLine != null && (_jsxs(Text, { color: "warning", wrap: "wrap", children: ["\u26A0", ' ', tOr(`logo-drift-${driftLine.kind}`, `The dsh engine (${driftLine.versions.join(' / ')}) does not match the validated ${UPSTREAM_VALIDATED_VERSION}; reinstall via npm i -g @deepseek-ai/dsh@${UPSTREAM_VALIDATED_VERSION}.`, {
479
481
  installed: driftLine.versions.join(' / '),
480
482
  validated: UPSTREAM_VALIDATED_VERSION,
481
483
  primary: UPSTREAM_VALIDATED_VERSION,
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/MessageList.tsx"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { Box, Text, useTerminalSize } from '../ui.js';
5
5
  import { normalizeIdePath } from '../dsh-adapter/ide-channel.js';
6
6
  import { Divider } from './design-system/Divider.js';
7
7
  import { UserPromptMessage } from './messages/UserPromptMessage.js';
8
+ import { TeamMessageBubble } from './messages/TeamMessageBubble.js';
8
9
  import { AssistantTextLeafRow, ThinkingLeafRow, ToolLeafRow } from './messages/TranscriptLeaves.js';
9
10
  import { liveOutputMaxLines, liveOutputRows } from './messages/liveOutputLines.js';
10
11
  import { SubagentMessage } from './Chat/SubagentMessage.js';
@@ -79,6 +80,16 @@ const NOOP_TOGGLE_STREAM_VIEW = (_rowId) => { };
79
80
  // replayed history paints complete); once created, a cursor keeps revealing
80
81
  // until it catches up — settling mid-reveal must not snap (that is the
81
82
  // "non-streaming delivery becomes a smooth flow" contract).
83
+ /** A row that opens a turn on the rail and the pinned header: a user row,
84
+ * but not an Agent Teams peer message (never the human's prompt). */
85
+ function isTurnRow(row) {
86
+ return row.kind === 'user' && row.label !== 'team-message';
87
+ }
88
+ /** The sender a team-message row shows (empty when the event named none);
89
+ * undefined for every other row, which renders as the human's prompt. */
90
+ function teamSenderOf(row) {
91
+ return row.label === 'team-message' ? row.sender ?? '' : undefined;
92
+ }
82
93
  function assistantRevealText(row, enabled) {
83
94
  const stripped = stripNarration(row.text);
84
95
  return revealTextOf(`a${row.id}`, stripped, {
@@ -263,7 +274,9 @@ function signatureParts(row, columns, expanded, expandedRows, streamViewToggledR
263
274
  // differ from JS length), not the JS string length — two paths with
264
275
  // equal length but different terminal widths must not share a cached
265
276
  // height (coderabbit review, repo width convention).
266
- signatureScratch.push(row.selectionAttached === undefined ? 0 : 1, stringWidth(displaySelectionPath(row.selectionAttached?.path ?? '', sessionCwd)), String(row.selectionAttached?.lines ?? ''));
277
+ signatureScratch.push(row.selectionAttached === undefined ? 0 : 1, stringWidth(displaySelectionPath(row.selectionAttached?.path ?? '', sessionCwd)), String(row.selectionAttached?.lines ?? ''),
278
+ // A team message adds its sender line above the body.
279
+ teamSenderOf(row) ?? '');
267
280
  // Long-line fold: expanding a folded row swaps the folded preview for
268
281
  // the raw line (thousands of rows), so both expansion switches are
269
282
  // height inputs on user rows too — same rationale as the default arm.
@@ -674,11 +687,14 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
674
687
  parts.length === cachedParts.length &&
675
688
  typeof parts[2] === 'number' && typeof cachedParts[2] === 'number' && parts[2] >= cachedParts[2] &&
676
689
  parts.every((part, index) => index === 2 || part === cachedParts[index]);
677
- if (!growingStream)
678
- heightsRef.current.delete(row.id);
679
- // Retaining the estimate must not skip the next fresh Yoga read.
680
- else if (localRefs.current.has(row.id))
690
+ // Keep a mounted row's estimate until the fresh Yoga read: falling back
691
+ // here could eject still-visible rows from this render's mount window.
692
+ // An unmounted row really paints the fallback spacer until it remounts.
693
+ // Retaining an estimate must never skip the next fresh measurement.
694
+ if (localRefs.current.has(row.id))
681
695
  growingStreamNeedsMeasure = true;
696
+ else if (!growingStream)
697
+ heightsRef.current.delete(row.id);
682
698
  heightsVersionRef.current++;
683
699
  }
684
700
  }
@@ -706,11 +722,29 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
706
722
  offsets[i] = total;
707
723
  total += heightOf(visibleRows[i]);
708
724
  }
709
- const scrollTop = scrollHandle?.getScrollTop() ?? 0;
725
+ // Predict the anchor's signed offset delta before scanning the mount window.
726
+ // A remeasured offscreen spacer must return its provisional shrink, not leave
727
+ // the reader permanently over-corrected. Scan against the corrected position
728
+ // so the anchor stays mounted; the layout effect refines that prediction
729
+ // from fresh Yoga before paint. Never fight following, wheel debt, or a
730
+ // position the user changed. A row below the viewport top (the header's
731
+ // fallback pick) does not own the reader's position.
732
+ const anchorRef = React.useRef(null);
733
+ const scrollTopRaw = scrollHandle?.getScrollTop() ?? 0;
710
734
  const pending = scrollHandle?.getPendingDelta() ?? 0;
711
735
  const viewport = scrollHandle?.getViewportHeight() ?? 24;
712
736
  const sticky = scrollHandle?.isSticky() ?? true;
713
737
  const base = baseRef.current ?? DEFAULT_HEADER_LINES;
738
+ const prevAnchor = anchorRef.current;
739
+ let anchorCorrection = 0;
740
+ if (scrollHandle && prevAnchor !== null && prevAnchor.top <= prevAnchor.scrollTop &&
741
+ !sticky && pending === 0 && scrollTopRaw === prevAnchor.scrollTop) {
742
+ const anchored = visibleRows[prevAnchor.index];
743
+ if (anchored !== undefined && anchored.id === prevAnchor.id) {
744
+ anchorCorrection = prevAnchor.top - (base + (offsets[prevAnchor.index] ?? 0));
745
+ }
746
+ }
747
+ const scrollTop = Math.max(0, scrollTopRaw - anchorCorrection);
714
748
  // Mount the union of the committed position and any in-flight pending
715
749
  // delta, plus overscan; when sticky, always reach the tail (streaming row).
716
750
  const relTop = Math.min(scrollTop, scrollTop + pending) - OVERSCAN_LINES - base;
@@ -992,7 +1026,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
992
1026
  const measuredTops = new Map();
993
1027
  for (let i = 0; i < visibleRows.length; i++) {
994
1028
  const row = visibleRows[i];
995
- if (row.kind !== 'user')
1029
+ if (!isTurnRow(row))
996
1030
  continue;
997
1031
  measuredTops.set(row.id, base + offsets[i] + (margins.get(row.id) === true ? 1 : 0));
998
1032
  }
@@ -1005,7 +1039,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
1005
1039
  // click goes through the reveal path, not scrollTo).
1006
1040
  const turns = [];
1007
1041
  for (const row of rows) {
1008
- if (row.kind !== 'user')
1042
+ if (!isTurnRow(row))
1009
1043
  continue;
1010
1044
  let cached = previewCache.get(row.id);
1011
1045
  const imageCount = row.images?.length ?? 0;
@@ -1096,6 +1130,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
1096
1130
  lastTimelineReportRef.current = timeline;
1097
1131
  onTimeline?.(timeline);
1098
1132
  });
1133
+ // Scroll anchoring, commit half of the render-time pass above.
1099
1134
  // Post-commit: measure mounted rows, derive the content-space base from
1100
1135
  // the first mounted row's Yoga top, and clamp render-time scrollTop to the
1101
1136
  // mounted coverage so burst scrolls never show blank spacer.
@@ -1132,6 +1167,14 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
1132
1167
  }
1133
1168
  }
1134
1169
  if (scrollHandle) {
1170
+ // Fresh bounds must move with a prefix's real height, too: an estimated
1171
+ // max can otherwise clamp away a positive correction larger than overscan.
1172
+ const mountedTop = top ?? base + topPad;
1173
+ const lastMounted = visibleRows[end - 1];
1174
+ const lastYoga = lastMounted ? localRefs.current.get(lastMounted.id)?.yogaNode : undefined;
1175
+ const mountedEnd = lastYoga === undefined
1176
+ ? base + mountedBottom
1177
+ : lastYoga.getComputedTop() + lastYoga.getComputedHeight();
1135
1178
  if (sticky || (start === 0 && end >= visibleRows.length)) {
1136
1179
  // Sticky still needs the MIN clamp: the first wheel-up breaks sticky
1137
1180
  // on the DOM (ScrollBox.scrollBy) several frames before React
@@ -1141,11 +1184,12 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
1141
1184
  // behavior as the steady-state scroll path. The MAX clamp stays
1142
1185
  // disabled: sticky follow pushes scrollTop to each frame's new
1143
1186
  // maxScroll, which a stale mounted max would clamp away.
1144
- const min = start > 0 ? Math.max(0, base + topPad - viewport) : undefined;
1187
+ const min = start > 0 ? Math.max(0, mountedTop - viewport) : undefined;
1145
1188
  scrollHandle.setClampBounds(min, undefined);
1146
1189
  }
1147
1190
  else {
1148
- const min = Math.max(0, base + topPad - viewport);
1191
+ // With no top spacer, the mounted header must remain reachable at Home.
1192
+ const min = start > 0 ? Math.max(0, mountedTop - viewport) : 0;
1149
1193
  // Upper clamp only while unmounted content remains below the window
1150
1194
  // (bottomPad spacer): it exists to pin the paint to the mounted edge
1151
1195
  // during burst scrolls that outrun React's window re-render. Once the
@@ -1156,8 +1200,45 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
1156
1200
  // would then cull the last line at every non-sticky paint — the
1157
1201
  // scrolled-away-and-back tail loss. Leave the max open; the renderer
1158
1202
  // still caps at the frame's real maxScroll.
1159
- scrollHandle.setClampBounds(min, bottomPad <= 0 ? undefined : Math.max(min, base + mountedBottom - viewport));
1203
+ scrollHandle.setClampBounds(min, bottomPad <= 0 ? undefined : Math.max(min, mountedEnd - viewport));
1204
+ }
1205
+ // Yoga is fresh even when this render retained an old height estimate.
1206
+ // Refine the prediction before paint, not on the later measure tick, and
1207
+ // recheck input intent in case scrolling moved between render and commit.
1208
+ const anchorBase = baseRef.current ?? base;
1209
+ let anchoredTop = scrollHandle.getScrollTop();
1210
+ if (prevAnchor !== null && prevAnchor.top <= prevAnchor.scrollTop &&
1211
+ visibleRows[prevAnchor.index]?.id === prevAnchor.id &&
1212
+ !scrollHandle.isSticky() && scrollHandle.getPendingDelta() === 0 &&
1213
+ anchoredTop === prevAnchor.scrollTop) {
1214
+ const measuredTop = localRefs.current.get(prevAnchor.id)?.yogaNode?.getComputedTop();
1215
+ const correction = measuredTop === undefined ? anchorCorrection : prevAnchor.top - measuredTop;
1216
+ if (correction !== 0) {
1217
+ scrollHandle.anchorBy(-correction);
1218
+ anchoredTop = scrollHandle.getScrollTop();
1219
+ }
1220
+ }
1221
+ else if (anchorCorrection !== 0) {
1222
+ changed = true;
1223
+ }
1224
+ // Pick and record in the same fresh coordinates as the correction.
1225
+ // Recording old offsets after a fresh read would consume that delta again.
1226
+ let pick = start;
1227
+ let pickedTop = anchorBase + (offsets[start] ?? 0);
1228
+ for (let i = start; i < end; i++) {
1229
+ const row = visibleRows[i];
1230
+ const rowTop = localRefs.current.get(row.id)?.yogaNode?.getComputedTop() ?? anchorBase + (offsets[i] ?? 0);
1231
+ if (i === start || rowTop <= anchoredTop) {
1232
+ pick = i;
1233
+ pickedTop = rowTop;
1234
+ }
1235
+ if (rowTop > anchoredTop)
1236
+ break;
1160
1237
  }
1238
+ const picked = visibleRows[pick];
1239
+ anchorRef.current = picked === undefined
1240
+ ? null
1241
+ : { id: picked.id, index: pick, top: pickedTop, scrollTop: anchoredTop };
1161
1242
  }
1162
1243
  if ((changed || growingStreamNeedsMeasure) && measureTimerRef.current === null) {
1163
1244
  // Layout corrections can cascade for many rows. Yield to the next
@@ -1229,7 +1310,7 @@ export function MessageList({ rows, expanded, expandedRows, selectedId, onToggle
1229
1310
  else if (row.kind === 'reasoning' && smoothStreaming) {
1230
1311
  displayText = revealTextOf(`r${row.id}`, row.text, { enabled: true, active: displayStreaming });
1231
1312
  }
1232
- return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: displayText, interruptBackend: row.interruptBackend, images: row.images, textFull: row.kind === 'reasoning' ? row.text : undefined, executionTarget: row.executionTarget, selectionAttached: row.selectionAttached, streaming: displayStreaming, thinkingOpen: row.thinkingOpen === true, durationMs: row.durationMs, reasoningTokens: row.reasoningTokens, time: row.time, marginTopOnTurn: marginTopOnTurn, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, smoothStreaming: smoothStreaming, fresh: row.fresh === true, revealVersion: revealVersion, activityFrames: activityFrames, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, toolSourceFolded: row.folded === true, toolLiveOutput: tool?.liveOutput, toolLiveOutputDropped: tool?.liveOutputDropped, fullscreen: fullscreen, turnUsage: row.turnUsage, subagent: subagent, job: job, jobGroup: jobGroup, onToggleRow: onToggleRow, onToggleStreamView: onToggleStreamView, streamViewToggled: streamViewToggledRows.has(row.id), onOpenSubagent: onOpenSubagent, onOpenSubagentView: onOpenSubagentView, onOpenJobs: onOpenJobs, onWatchJobOutput: onWatchJobOutput, onOpenFile: onOpenFile, sessionCwd: sessionCwd, onPreviewImage: onPreviewImage, suppressImageGraphics: suppressImageGraphics, setRowRef: setRowRef }, row.id));
1313
+ return (_jsx(MemoRow, { rowId: row.id, kind: row.kind, text: displayText, interruptBackend: row.interruptBackend, images: row.images, textFull: row.kind === 'reasoning' ? row.text : undefined, executionTarget: row.executionTarget, selectionAttached: row.selectionAttached, sender: teamSenderOf(row), streaming: displayStreaming, thinkingOpen: row.thinkingOpen === true, durationMs: row.durationMs, reasoningTokens: row.reasoningTokens, time: row.time, marginTopOnTurn: marginTopOnTurn, isSelected: selectedId === row.id, isExpanded: expandedRows.has(row.id), expanded: expanded, model: model, diffLayout: diffLayout, thinkingFold: thinkingFold, toolBackground: toolBackground, foldTerminalCommand: foldTerminalCommand, smoothStreaming: smoothStreaming, fresh: row.fresh === true, revealVersion: revealVersion, activityFrames: activityFrames, background: rowBackground(row.id), toolCallId: tool?.callId, toolName: tool?.name, toolArgsText: tool?.argsText, toolArgsFull: tool?.argsFull, toolStatus: tool?.status, toolResultText: tool?.resultText, toolResultFull: tool?.resultFull, toolErrorText: tool?.errorText, toolFootnote: failureHintRowId === row.id ? failureHint : undefined, toolCallView: tool?.callView, toolResultView: tool?.resultView, toolStartedAt: tool?.startedAt, toolDurationMs: tool?.durationMs, toolSourceFolded: row.folded === true, toolLiveOutput: tool?.liveOutput, toolLiveOutputDropped: tool?.liveOutputDropped, fullscreen: fullscreen, turnUsage: row.turnUsage, subagent: subagent, job: job, jobGroup: jobGroup, onToggleRow: onToggleRow, onToggleStreamView: onToggleStreamView, streamViewToggled: streamViewToggledRows.has(row.id), onOpenSubagent: onOpenSubagent, onOpenSubagentView: onOpenSubagentView, onOpenJobs: onOpenJobs, onWatchJobOutput: onWatchJobOutput, onOpenFile: onOpenFile, sessionCwd: sessionCwd, onPreviewImage: onPreviewImage, suppressImageGraphics: suppressImageGraphics, setRowRef: setRowRef }, row.id));
1233
1314
  }), bottomPad > 0 && _jsx(Box, { height: bottomPad, flexShrink: 0 })] }));
1234
1315
  }
1235
1316
  /** Load-earlier / show-previous divider row with a mouse hover tint — the
@@ -1238,7 +1319,7 @@ function ClickableDivider({ title, onClick }) {
1238
1319
  const [hovered, setHovered] = useState(false);
1239
1320
  return (_jsx(Box, { marginTop: 1, onClick: onClick, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), backgroundColor: hovered ? 'userMessageBackgroundHover' : undefined, children: _jsx(Divider, { title: title }) }));
1240
1321
  }
1241
- function TranscriptRow({ rowId, kind, text, interruptBackend, images, textFull, executionTarget, selectionAttached, sessionCwd, streaming, thinkingOpen, durationMs, reasoningTokens, time, marginTopOnTurn, isSelected, isExpanded, expanded, model, diffLayout, smoothStreaming, fresh, revealVersion, thinkingFold, toolBackground, foldTerminalCommand, activityFrames, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, toolSourceFolded, toolLiveOutput, toolLiveOutputDropped, fullscreen, turnUsage, subagent, job, jobGroup, onToggleRow, onToggleStreamView, streamViewToggled, onOpenSubagent, onOpenSubagentView, onOpenJobs, onWatchJobOutput, onOpenFile, onPreviewImage, suppressImageGraphics, setRowRef, }) {
1322
+ function TranscriptRow({ rowId, kind, text, interruptBackend, images, textFull, executionTarget, selectionAttached, sender, sessionCwd, streaming, thinkingOpen, durationMs, reasoningTokens, time, marginTopOnTurn, isSelected, isExpanded, expanded, model, diffLayout, smoothStreaming, fresh, revealVersion, thinkingFold, toolBackground, foldTerminalCommand, activityFrames, background, toolCallId, toolName, toolArgsText, toolArgsFull, toolStatus, toolResultText, toolResultFull, toolErrorText, toolFootnote, toolCallView, toolResultView, toolStartedAt, toolDurationMs, toolSourceFolded, toolLiveOutput, toolLiveOutputDropped, fullscreen, turnUsage, subagent, job, jobGroup, onToggleRow, onToggleStreamView, streamViewToggled, onOpenSubagent, onOpenSubagentView, onOpenJobs, onWatchJobOutput, onOpenFile, onPreviewImage, suppressImageGraphics, setRowRef, }) {
1242
1323
  const ref = React.useCallback((el) => {
1243
1324
  setRowRef(rowId, el);
1244
1325
  }, [setRowRef, rowId]);
@@ -1297,7 +1378,7 @@ function TranscriptRow({ rowId, kind, text, interruptBackend, images, textFull,
1297
1378
  lines: selectionAttached.lines,
1298
1379
  count: selectionAttached.lines,
1299
1380
  path: displaySelectionPath(selectionAttached.path, sessionCwd),
1300
- })] })), text !== '' && (_jsx(UserPromptMessage, { text: displayText, marginTopOnTurn: marginTopOnTurn, isSelected: isSelected })), images !== undefined && (_jsx(Box, { marginTop: text === '' && marginTopOnTurn ? 1 : 0, children: _jsx(TranscriptImages, { images: images, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics }) }))] }));
1381
+ })] })), text !== '' && sender !== undefined && (_jsx(TeamMessageBubble, { sender: sender, text: displayText, marginTopOnTurn: marginTopOnTurn, isSelected: isSelected })), text !== '' && sender === undefined && (_jsx(UserPromptMessage, { text: displayText, marginTopOnTurn: marginTopOnTurn, isSelected: isSelected })), images !== undefined && (_jsx(Box, { marginTop: text === '' && marginTopOnTurn ? 1 : 0, children: _jsx(TranscriptImages, { images: images, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics }) }))] }));
1301
1382
  case 'assistant':
1302
1383
  return streaming ? (_jsxs(Box, { alignItems: "flex-start", flexDirection: "row", marginTop: marginTopOnTurn ? 1 : 0, width: "100%", backgroundColor: background, ref: ref, onClick: foldClickable ? foldOnClick : undefined, children: [_jsx(Box, { minWidth: 2, children: _jsx(Text, { color: "text", children: "\u25CF" }) }), _jsxs(Box, { flexDirection: "column", children: [_jsx(StreamingMarkdown, { children: stripNarration(displayText) }), images !== undefined && _jsx(TranscriptImages, { images: images, indent: 0, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics })] })] })) : (_jsxs(Box, { width: "100%", flexDirection: "column", backgroundColor: background, ref: ref, onClick: foldClickable ? foldOnClick : undefined, children: [expanded && (_jsx(Box, { flexDirection: "row", justifyContent: "flex-end", gap: 1, marginTop: 1, children: _jsx(MessageMetadata, { timestamp: time, model: model }) })), _jsx(AssistantTextLeafRow, { text: stripNarration(displayText), marginTopOnTurn: marginTopOnTurn, isSelected: isSelected, isExpanded: isExpanded }), images !== undefined && _jsx(TranscriptImages, { images: images, onPreview: onPreviewImage, suppressGraphics: suppressImageGraphics })] }));
1303
1384
  case 'reasoning': {
@@ -7,14 +7,23 @@ import type { PermissionPresetOption } from '../dsh-adapter/channel.js';
7
7
  * `/permission <preset>` through the same external-command path a hand-typed
8
8
  * argument takes. The roster comes from the adapter snapshot so host plugins
9
9
  * can contribute additional preset identities without UI changes.
10
+ *
11
+ * DSH's experimental `auto` preset is tagged EXP, and picking it first shows
12
+ * a session-scoped risk confirmation (`confirming`); Chat owns the keys.
10
13
  */
11
- export declare function PermissionsPicker({ options, focusIndex, currentValue, cwd, onPick, }: {
14
+ export declare function PermissionsPicker({ options, focusIndex, currentValue, cwd, confirming, onPick, onConfirm, onCancelConfirm, }: {
12
15
  options: readonly PermissionPresetOption[];
13
16
  focusIndex: number;
14
17
  currentValue: string | undefined;
15
18
  cwd: string;
19
+ /** Show the Auto review risk confirmation instead of the list. */
20
+ confirming?: boolean;
16
21
  /** Mouse pick (fullscreen): clicked row's absolute index (Chat applies
17
22
  * the same code path as the keyboard Enter). */
18
23
  onPick?: (index: number) => void;
24
+ /** Mouse confirm / back on the risk confirmation (fullscreen); the
25
+ * keyboard path stays Enter / Esc in Chat. */
26
+ onConfirm?: () => void;
27
+ onCancelConfirm?: () => void;
19
28
  }): React.ReactNode;
20
29
  //# sourceMappingURL=PermissionsPicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"PermissionsPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PermissionsPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAEvE;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,UAAU,EACV,YAAY,EACZ,GAAG,EACH,MAAM,GACP,EAAE;IACD,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;IACX;qDACiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CAwClB"}
1
+ {"version":3,"file":"PermissionsPicker.d.ts","sourceRoot":"","sources":["../../../src/components/PermissionsPicker.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAEvE;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,UAAU,EACV,YAAY,EACZ,GAAG,EACH,UAAkB,EAClB,MAAM,EACN,SAAS,EACT,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;qDACiD;IACjD,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAChC;mDAC+C;IAC/C,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;CAC7B,GAAG,KAAK,CAAC,SAAS,CA+BlB"}
@@ -1,5 +1,6 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { t } from '../i18n.js';
3
+ import { PERMISSION_PRESET_AUTO, permissionPresetDescription, permissionPresetLabel } from '../permissionPresetLabels.js';
3
4
  import { Box, Text } from '../ui.js';
4
5
  import { Pane } from './design-system/Pane.js';
5
6
  import { Select } from './Select.js';
@@ -11,23 +12,30 @@ import { HintLine } from './design-system/HintLine.js';
11
12
  * `/permission <preset>` through the same external-command path a hand-typed
12
13
  * argument takes. The roster comes from the adapter snapshot so host plugins
13
14
  * can contribute additional preset identities without UI changes.
15
+ *
16
+ * DSH's experimental `auto` preset is tagged EXP, and picking it first shows
17
+ * a session-scoped risk confirmation (`confirming`); Chat owns the keys.
14
18
  */
15
- export function PermissionsPicker({ options, focusIndex, currentValue, cwd, onPick, }) {
19
+ export function PermissionsPicker({ options, focusIndex, currentValue, cwd, confirming = false, onPick, onConfirm, onCancelConfirm, }) {
20
+ if (confirming)
21
+ return _jsx(AutoReviewConfirm, { onConfirm: onConfirm, onCancel: onCancelConfirm });
16
22
  return (_jsx(Pane, { color: "permission", children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('permission-picker-title') }) }), _jsx(Select, { options: options.map(option => ({
17
23
  value: option.value,
18
- label: option.value === 'read-only'
19
- ? t('permission-preset-readonly')
20
- : option.value === 'workspace-write'
21
- ? t('permission-preset-workspace-write')
22
- : option.value === 'danger-full-access'
23
- ? t('permission-preset-full-access')
24
- : option.name,
25
- description: option.value === 'read-only'
26
- ? t('permission-preset-readonly-desc')
27
- : option.value === 'workspace-write'
28
- ? t('permission-preset-workspace-write-desc')
29
- : option.value === 'danger-full-access'
30
- ? t('permission-preset-full-access-desc')
31
- : option.description ?? option.name,
24
+ label: option.value === PERMISSION_PRESET_AUTO
25
+ ? _jsxs(_Fragment, { children: [permissionPresetLabel(option), " ", _jsx(Text, { color: "warning", children: t('permission-preset-exp-tag') })] })
26
+ : permissionPresetLabel(option),
27
+ description: permissionPresetDescription(option),
32
28
  })), focusIndex: focusIndex, selectedValue: currentValue, onPick: onPick ? index => onPick(index) : undefined }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('hint-confirm-exit') }) }), _jsx(Text, { dimColor: true, children: t('permission-root-hint', { cwd }) })] }) }));
33
29
  }
30
+ const AUTO_CONFIRM_POINTS = [
31
+ 'permission-auto-confirm-session',
32
+ 'permission-auto-confirm-sandbox',
33
+ 'permission-auto-confirm-cost',
34
+ 'permission-auto-confirm-risk',
35
+ ];
36
+ function AutoReviewConfirm({ onConfirm, onCancel, }) {
37
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "warning", bold: true, children: t('permission-auto-confirm-title') }) }), AUTO_CONFIRM_POINTS.map(key => (_jsxs(Box, { children: [_jsx(Text, { children: "\u00B7 " }), _jsx(Box, { flexShrink: 1, children: _jsx(Text, { children: t(key) }) })] }, key))), onConfirm !== undefined && onCancel !== undefined && (_jsx(Box, { marginTop: 1, children: _jsx(Select, { options: [
38
+ { value: 'enable', label: t('permission-auto-confirm-enable') },
39
+ { value: 'back', label: t('permission-auto-confirm-back') },
40
+ ], focusIndex: 0, selectedValue: undefined, onPick: index => (index === 0 ? onConfirm() : onCancel()) }) }))] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('permission-auto-confirm-actions') }) })] }));
41
+ }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { PluginInstallStep } from '../dsh-adapter/plugin-install.js';
3
+ /**
4
+ * `/plugin install <spec>`: the pane that asks what the flow cannot answer on
5
+ * its own (Stage C-4).
6
+ *
7
+ * The flow (`dsh-adapter/plugin-install.ts`) writes every line of the install
8
+ * into the transcript as it happens — the inspection, pnpm's phases, the result
9
+ * — so this pane only carries the two things a person must decide before that:
10
+ * gate 1's pre-install notice and gate 3's trust confirmation. It also renders
11
+ * the two "decide and retry" steps (unapproved build scripts, an incompatible
12
+ * version), which are the same kind of question.
13
+ *
14
+ * Presentational only: the step state lives in Chat, keys are handled there
15
+ * (Enter confirms / retries, Esc cancels), exactly like the SDK install wizard.
16
+ */
17
+ export declare function PluginInstallPane({ step, busy }: {
18
+ step: PluginInstallStep;
19
+ busy: boolean;
20
+ }): React.ReactNode;
21
+ //# sourceMappingURL=PluginInstallPane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginInstallPane.d.ts","sourceRoot":"","sources":["../../../src/components/PluginInstallPane.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,iBAAiB,EAAqB,MAAM,kCAAkC,CAAA;AAqB5F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAgF7G"}
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { t } from '../i18n.js';
3
+ import { Box, Text } from '../ui.js';
4
+ import { cleanRenderText, NOTICE_CELLS } from '../channel/sanitize.js';
5
+ import { HintLine } from './design-system/HintLine.js';
6
+ import { LoadingState } from './design-system/LoadingState.js';
7
+ import { Pane } from './design-system/Pane.js';
8
+ /** Foreign text on its way to the screen: control sequences stripped, bounded. */
9
+ const clean = (value) => cleanRenderText(value, NOTICE_CELLS);
10
+ /**
11
+ * The target's identity is the subject of the confirmation, and it is foreign
12
+ * text like everything else here: the name comes from the package's own
13
+ * manifest, so it can carry newlines or thousands of cells. Bounded to what a
14
+ * line can show — at 50 columns an unbounded name buries the title and the key
15
+ * hints, which are exactly what the person needs to answer the question.
16
+ */
17
+ const TARGET_CELLS = 80;
18
+ /**
19
+ * `/plugin install <spec>`: the pane that asks what the flow cannot answer on
20
+ * its own (Stage C-4).
21
+ *
22
+ * The flow (`dsh-adapter/plugin-install.ts`) writes every line of the install
23
+ * into the transcript as it happens — the inspection, pnpm's phases, the result
24
+ * — so this pane only carries the two things a person must decide before that:
25
+ * gate 1's pre-install notice and gate 3's trust confirmation. It also renders
26
+ * the two "decide and retry" steps (unapproved build scripts, an incompatible
27
+ * version), which are the same kind of question.
28
+ *
29
+ * Presentational only: the step state lives in Chat, keys are handled there
30
+ * (Enter confirms / retries, Esc cancels), exactly like the SDK install wizard.
31
+ */
32
+ export function PluginInstallPane({ step, busy }) {
33
+ if (busy) {
34
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsx(Box, { marginTop: 1, children: _jsx(LoadingState, { message: t('plugins-install-installing') }) })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-cancel') }) })] }));
35
+ }
36
+ if (step.kind === 'confirm') {
37
+ const { artifact, trust, notice } = step;
38
+ const spec = artifact.name === undefined
39
+ ? t('plugins-install-unidentified')
40
+ : cleanRenderText(`${artifact.name}${artifact.version === undefined ? '' : `@${artifact.version}`}`, TARGET_CELLS);
41
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }) }), _jsx(Text, { children: t('plugins-install-configure', {
42
+ spec,
43
+ kind: artifact.kind,
44
+ bundle: artifact.bundle === true ? 'bundle' : artifact.bundle === false ? 'not a bundle' : 'unknown',
45
+ }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [trust.kind === 'third-party' && _jsx(Text, { children: t('plugins-install-trust-third-party') }), notice.kind === 'declared' && _jsx(Text, { dimColor: true, children: t('plugins-install-notice-declared') }), notice.kind === 'undeclared' && _jsx(Text, { children: t('plugins-install-notice-undeclared') }), notice.kind === 'invalid' && _jsx(Text, { children: t('plugins-install-notice-invalid', { err: notice.error }) }), notice.kind === 'unjudged' && _jsx(Text, { children: t('plugins-install-notice-unjudged') })] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-confirm') }) })] }));
46
+ }
47
+ if (step.kind === 'build-blocked') {
48
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-builds-title') }), step.builds.map(build => _jsx(Text, { dimColor: true, children: ` ${clean(build)}` }, build))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-builds') }) })] }));
49
+ }
50
+ if (step.kind === 'incompatible') {
51
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-incompatible-title') }), step.packages.map(entry => _jsx(Text, { dimColor: true, children: describe(entry) }, `${entry.name}@${entry.version}`))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-exemptions-title') }), exemptionLines(step.exemptions).map((line, index) => _jsx(Text, { dimColor: true, children: line }, index))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-incompatible') }) })] }));
52
+ }
53
+ // `done` never renders: its lines are already in the transcript, so Chat
54
+ // closes the pane instead of leaving an empty box behind.
55
+ return null;
56
+ }
57
+ /**
58
+ * One package the running host refuses, with the peers it fails.
59
+ *
60
+ * Every field here is foreign text — a package name, a version, a peer range
61
+ * the author wrote — and the pane is a render path like any other, so each one
62
+ * goes through the same sanitizer the rest of the interface uses before it can
63
+ * reach the screen.
64
+ */
65
+ function describe(entry) {
66
+ const peers = Object.entries(entry.peers)
67
+ .map(([name, range]) => `${clean(name)} ${clean(range)}`)
68
+ .join(', ');
69
+ return ` ${clean(entry.name)}@${clean(entry.version)} (running ${clean(entry.runtimeVersion)}${peers === '' ? '' : `; needs ${peers}`})`;
70
+ }
71
+ /**
72
+ * The profile's compatibility file as rows. The file maps `package@version` to
73
+ * the runtime versions exempted for it, and a corrupt one answers warnings
74
+ * instead — both shapes are the person's business here, because this is the
75
+ * step where they decide whether to add another. The file is user-editable and
76
+ * carries whatever somebody typed, so its rows are sanitized too.
77
+ */
78
+ function exemptionLines(exemptions) {
79
+ const rows = Object.entries(exemptions.exemptions)
80
+ .map(([packageVersion, runtimes]) => ` ${clean(packageVersion)} → ${runtimes.map(runtime => clean(runtime)).join(', ')}`);
81
+ if (rows.length === 0 && exemptions.warnings.length === 0)
82
+ return [` ${t('plugins-info-registries-none')}`];
83
+ return [...rows, ...exemptions.warnings.map(warning => ` ${clean(warning)}`)];
84
+ }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { PluginManageStep } from '../dsh-adapter/plugin-manage.js';
3
+ /**
4
+ * `/plugin remove | enable | disable`: the pane that asks what the flow cannot
5
+ * answer on its own (Stage C-5).
6
+ *
7
+ * The flow (`dsh-adapter/plugin-manage.ts`) writes every line of the action into
8
+ * the transcript — what it resolved, why it refused, what the service answered —
9
+ * so this pane only carries the one thing a person must decide before the write.
10
+ * Unlike the install pane there is no progress, no cancellation and no retry:
11
+ * each action is a single call that settles once.
12
+ *
13
+ * Presentational only, and the same three parts as its install sibling
14
+ * (`PluginInstallPane`): the pane, the facts that make the question answerable,
15
+ * and the key hints. Keys are handled in Chat (Enter answers, Esc closes).
16
+ */
17
+ export declare function PluginManagePane({ step, busy }: {
18
+ step: PluginManageStep;
19
+ busy: boolean;
20
+ }): React.ReactNode;
21
+ //# sourceMappingURL=PluginManagePane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginManagePane.d.ts","sourceRoot":"","sources":["../../../src/components/PluginManagePane.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,iCAAiC,CAAA;AAiB3F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAqD3G"}