@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TeamMessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/messages/TeamMessageBubble.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,KAAK,KAAK,GAAG;IACX,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,eAAe,EAAE,OAAO,CAAA;IACxB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB,CAAA;AAID;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,UAAkB,EAAE,EAAE,KAAK,GAAG,KAAK,CAAC,SAAS,CAmB/G"}
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from '../../ui.js';
3
+ import { stringWidth } from '../../ink/stringWidth.js';
4
+ import { t } from '../../i18n.js';
5
+ const MARK = '✉ ';
6
+ /**
7
+ * An Agent Teams peer message delivered to this session: a `✉ <sender>` line
8
+ * in the agent tint, then the body in plain text with a hanging indent — it
9
+ * reads apart from the human's bold `❯` prompt it shares a log role with.
10
+ * The body wraps in its own flex column, so it fits whatever column hosts it
11
+ * (the main list, a child scene's padded page, a split with the workbench).
12
+ */
13
+ export function TeamMessageBubble({ sender, text, marginTopOnTurn, isSelected = false }) {
14
+ return (_jsxs(Box, { flexDirection: "column", marginTop: marginTopOnTurn ? 1 : 0, backgroundColor: isSelected ? 'messageActionsBackground' : undefined, paddingRight: 1, children: [_jsxs(Text, { color: "toolDotTask", wrap: "truncate-end", children: [MARK, _jsx(Text, { bold: true, children: sender }), _jsx(Text, { dimColor: true, children: ` · ${t('team-message-label')}` })] }), _jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { width: stringWidth(MARK), flexShrink: 0 }), _jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsx(Text, { wrap: "wrap", children: text }) })] })] }));
15
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PanelHost.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/PanelHost.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AAKnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAE5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,qCAAqC,EAAE,YAAY,CAAA;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E,yCAAyC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,uCAAuC,EAAE,SAAS,CAAA;IAC/E,oDAAoD;IACpD,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACpD;AA4BD,wBAAgB,SAAS,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,SAAS,CAiFlJ"}
1
+ {"version":3,"file":"PanelHost.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/PanelHost.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAKzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AAKnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAE5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,qCAAqC,EAAE,YAAY,CAAA;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E,yCAAyC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,uCAAuC,EAAE,SAAS,CAAA;IAC/E,oDAAoD;IACpD,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACpD;AA4BD,wBAAgB,SAAS,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,SAAS,CAqFlJ"}
@@ -59,7 +59,11 @@ export function PanelHost({ controller, channel, width, height, activity, attent
59
59
  panelStore.clearBadge(activeId);
60
60
  }, [activeId]);
61
61
  const mode = controller.zoom ? 'zoom' : 'split';
62
- const runtimeContext = React.useMemo(() => ({ runtime: controller.runtime, channel, activity, attention, trajectory, openFullscreen }), [controller.runtime, channel, activity, attention, trajectory, openFullscreen]);
62
+ // focusChat 从控制器注入:面板送聊天后要能把列焦点交回聊天(见
63
+ // SidePanelRuntimeContext 的出口注释)。控制器对象每次渲染都是新的,
64
+ // 但 focusChat 本身是空依赖 useCallback,引用稳定。
65
+ const focusChat = controller.focusChat;
66
+ const runtimeContext = React.useMemo(() => ({ runtime: controller.runtime, channel, activity, attention, trajectory, openFullscreen, focusChat }), [controller.runtime, channel, activity, attention, trajectory, openFullscreen, focusChat]);
63
67
  return (_jsx(SidePanelRuntimeContext.Provider, { value: runtimeContext, children: visibleEntries.map(entry => {
64
68
  const def = entry.definition;
65
69
  const isActive = activeEntry !== undefined && def.id === activeEntry.definition.id;
@@ -25,6 +25,9 @@ export type PanelStoreEvent = {
25
25
  } | {
26
26
  readonly type: 'badge';
27
27
  readonly id: string;
28
+ } | {
29
+ readonly type: 'hint';
30
+ readonly id: string;
28
31
  } | {
29
32
  readonly type: 'error';
30
33
  readonly id: string;
@@ -47,6 +50,11 @@ export declare class PanelStore {
47
50
  * level/unread 都没变时不通知:适配器在每次 channel 变化(流式时每个
48
51
  * delta)都会调这里,每次通知都会让订阅 list() 的宿主重渲染。 */
49
52
  setBadge(id: string, badge: Omit<PanelBadge, 'latestAt'> | null): void;
53
+ /**
54
+ * 面板广告自己当前的键位片段(见 PanelEntry.hint)。每次 channel delta 都会
55
+ * 有适配器调 setBadge,这里同理按值短路:没变就不通知宿主重渲染。
56
+ */
57
+ setHint(id: string, hint: string): void;
50
58
  clearBadge(id: string): void;
51
59
  reportError(id: string, error: unknown): void;
52
60
  subscribe: (listener: (event: PanelStoreEvent) => void) => (() => void);
@@ -1 +1 @@
1
- {"version":3,"file":"PanelStore.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/PanelStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAErF,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,uCAAuC;AACvC,eAAO,MAAM,6BAA6B,IAAI,CAAA;AAC9C,kBAAkB;AAClB,eAAO,MAAM,qBAAqB,QAAS,CAAA;AAE3C;;4CAE4C;AAC5C,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAatD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,QAAQ,CAAI;IACpB,+CAA+C;IAC/C,OAAO,CAAC,UAAU,CAA8B;IAEhD,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,IAAI;IA0BpE,IAAI,IAAI,SAAS,UAAU,EAAE;IAI7B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIvC;;+CAE2C;IAC3C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,IAAI;IAWtE,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO5B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAsB7C,SAAS,GAAI,UAAU,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAGrE;IAED,OAAO,CAAC,IAAI;CAIb;AAED,0DAA0D;AAC1D,eAAO,MAAM,UAAU,YAAmB,CAAA"}
1
+ {"version":3,"file":"PanelStore.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/PanelStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAErF,eAAO,MAAM,gBAAgB,KAAK,CAAA;AAElC,uCAAuC;AACvC,eAAO,MAAM,6BAA6B,IAAI,CAAA;AAC9C,kBAAkB;AAClB,eAAO,MAAM,qBAAqB,QAAS,CAAA;AAE3C;;4CAE4C;AAC5C,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAatD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,QAAQ,CAAI;IACpB,+CAA+C;IAC/C,OAAO,CAAC,UAAU,CAA8B;IAEhD,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,eAAe,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,IAAI;IA0BpE,IAAI,IAAI,SAAS,UAAU,EAAE;IAI7B,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIvC;;+CAE2C;IAC3C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,IAAI,GAAG,IAAI;IAWtE;;;OAGG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOvC,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAO5B,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAsB7C,SAAS,GAAI,UAAU,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAGrE;IAED,OAAO,CAAC,IAAI;CAIb;AAED,0DAA0D;AAC1D,eAAO,MAAM,UAAU,YAAmB,CAAA"}
@@ -69,6 +69,17 @@ export class PanelStore {
69
69
  this.entries.set(id, { ...entry, badge: next });
70
70
  this.emit({ type: 'badge', id });
71
71
  }
72
+ /**
73
+ * 面板广告自己当前的键位片段(见 PanelEntry.hint)。每次 channel delta 都会
74
+ * 有适配器调 setBadge,这里同理按值短路:没变就不通知宿主重渲染。
75
+ */
76
+ setHint(id, hint) {
77
+ const entry = this.entries.get(id);
78
+ if (entry === undefined || entry.hint === hint)
79
+ return;
80
+ this.entries.set(id, { ...entry, hint });
81
+ this.emit({ type: 'hint', id });
82
+ }
72
83
  clearBadge(id) {
73
84
  const entry = this.entries.get(id);
74
85
  if (entry === undefined || entry.badge === null)
@@ -1 +1 @@
1
- {"version":3,"file":"SidePanelColumn.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/SidePanelColumn.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AAMnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAI5D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,qCAAqC,EAAE,YAAY,CAAA;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,6BAA6B;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,uCAAuC,EAAE,SAAS,CAAA;CAChF;AAoCD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,oBAAoB,GAAG,KAAK,CAAC,SAAS,CAuEhJ"}
1
+ {"version":3,"file":"SidePanelColumn.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/SidePanelColumn.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AAMnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAI5D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,qCAAqC,EAAE,YAAY,CAAA;IAC9E,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,6BAA6B;IAC7B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,uCAAuC,EAAE,SAAS,CAAA;CAChF;AAoCD,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,oBAAoB,GAAG,KAAK,CAAC,SAAS,CAmFhJ"}
@@ -55,6 +55,18 @@ export function SidePanelColumn({ width, controller, channel, activity, attentio
55
55
  // oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: partial fixture channels
56
56
  const trajectoryUnsupported = controller.activePanelId === 'trajectory' && channel.trajectorySource?.() === 'unsupported';
57
57
  const canExpand = activeEntry?.definition.capabilities?.fullscreen === true && onExpand !== undefined && !trajectoryUnsupported;
58
+ // 底栏拼序 = 重要性:导航 → 面板自己绑的键 → 列控制。宿主不点名任何面板:
59
+ // 面板经 panelStore 广告自己此刻的键位(例如 btw 在编辑层只说「↑ 回标题」、
60
+ // 在列表层才说 s/c),没广告过的才退回能力位那一段。窄面板从尾部截断,所以
61
+ // 面板键排在列控制前;未聚焦时面板收不到按键,那一格继续只说怎么把焦点拿过来。
62
+ const panelSegment = activeEntry === undefined
63
+ ? ''
64
+ : activeEntry.hint !== undefined
65
+ ? activeEntry.hint
66
+ : activeEntry.definition.capabilities?.sendToChat === true ? t('panel-hint-send-to-chat') : '';
67
+ const focusedHint = t('panel-hint-focused')
68
+ + (panelSegment === '' ? '' : ' · ' + panelSegment)
69
+ + ' · ' + t('panel-hint-zoom-width');
58
70
  // 标签点击与 ←/→ 宿主键走同一条路(openPanel 会顺带把焦点给右栏)。
59
71
  const onSelectPanel = React.useCallback((id) => { controller.openPanel(id, { focus: true }); },
60
72
  // openPanel 在 useSidePanel 里是空依赖 useCallback(引用稳定);
@@ -64,5 +76,5 @@ export function SidePanelColumn({ width, controller, channel, activity, attentio
64
76
  const hostHeight = Math.max(1, rows - 4);
65
77
  return (_jsxs(Box, { flexDirection: "column", width: width, flexGrow: 1, children: [_jsx(PanelBar, { tabs: tabs, activeId: controller.activePanelId, width: width - 2, focused: focused, canExpand: canExpand, onExpand: canExpand ? () => onExpand?.(controller.activePanelId ?? '') : undefined, onSelect: onSelectPanel }), _jsx(Rule, { focused: focused }), _jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: anyRegistered
66
78
  ? (_jsx(PanelHost, { controller: controller, channel: channel, width: width, height: hostHeight, activity: activity, attention: attention, trajectory: trajectory, openFullscreen: onExpand }))
67
- : _jsx(EmptyNone, {}) }), _jsx(Rule, { focused: focused }), _jsx(Box, { height: 1, flexShrink: 0, paddingX: 1, overflow: "hidden", children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: focused ? t('panel-hint-focused') : t('panel-hint-unfocused') }) })] }));
79
+ : _jsx(EmptyNone, {}) }), _jsx(Rule, { focused: focused }), _jsx(Box, { height: 1, flexShrink: 0, paddingX: 1, overflow: "hidden", children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: focused ? focusedHint : t('panel-hint-unfocused') }) })] }));
68
80
  }
@@ -30,6 +30,11 @@ export interface SidePanelRuntimeContextValue {
30
30
  * 未接(或该 Panel 没有整屏形态)时 undefined,按钮照画但点击无效——
31
31
  * 宿主是否可展开由 PanelDefinition.capabilities.fullscreen 决定。 */
32
32
  readonly openFullscreen?: (panelId: string) => void;
33
+ /** 「回主输入框」出口:Panel 把内容送聊天(attachContext)后把列焦点交回
34
+ * 聊天——chip 就在眼前、可直接接着打字,toast 里的「Esc 可撤」也立刻
35
+ * 成立(剥 chip 的那把 Esc 只有主输入框有焦点时才收得到)。宿主
36
+ * (PanelHost)从 controller.focusChat 注入;未接时送完焦点不动。 */
37
+ readonly focusChat?: () => void;
33
38
  }
34
39
  export declare const SidePanelRuntimeContext: React.Context<SidePanelRuntimeContextValue | null>;
35
40
  export declare function useSidePanelChannel(): ChannelUi;
@@ -37,6 +42,8 @@ export declare function useSidePanelChannel(): ChannelUi;
37
42
  export declare function useSidePanelTrajectory(): TrajBuild | undefined;
38
43
  /** 「全屏」出口:宿主没接时返回 undefined(按钮点击静默无效)。 */
39
44
  export declare function useSidePanelFullscreen(): ((panelId: string) => void) | undefined;
45
+ /** 「回主输入框」出口:宿主没接时返回 undefined(送聊天后焦点不动)。 */
46
+ export declare function useSidePanelFocusChat(): (() => void) | undefined;
40
47
  export declare const PanelContext: React.Context<{
41
48
  readonly panelId: string;
42
49
  } | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"SidePanelRuntimeContext.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/SidePanelRuntimeContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAA;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B;sDACkD;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E;6CACyC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAA;IAC/B;;+DAE2D;IAC3D,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACpD;AAED,eAAO,MAAM,uBAAuB,oDAAiE,CAAA;AAErG,wBAAgB,mBAAmB,IAAI,SAAS,CAI/C;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,IAAI,SAAS,GAAG,SAAS,CAE9D;AAED,0CAA0C;AAC1C,wBAAgB,sBAAsB,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAEhF;AAED,eAAO,MAAM,YAAY;sBAA2C,MAAM;SAAgB,CAAA"}
1
+ {"version":3,"file":"SidePanelRuntimeContext.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/SidePanelRuntimeContext.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oCAAoC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qCAAqC,CAAA;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAA;AACtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B;sDACkD;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,oDAAoD;IACpD,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/E;6CACyC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAA;IAC/B;;+DAE2D;IAC3D,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACnD;;;0DAGsD;IACtD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;CAChC;AAED,eAAO,MAAM,uBAAuB,oDAAiE,CAAA;AAErG,wBAAgB,mBAAmB,IAAI,SAAS,CAI/C;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,IAAI,SAAS,GAAG,SAAS,CAE9D;AAED,0CAA0C;AAC1C,wBAAgB,sBAAsB,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAEhF;AAED,6CAA6C;AAC7C,wBAAgB,qBAAqB,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAEhE;AAED,eAAO,MAAM,YAAY;sBAA2C,MAAM;SAAgB,CAAA"}
@@ -23,4 +23,8 @@ export function useSidePanelTrajectory() {
23
23
  export function useSidePanelFullscreen() {
24
24
  return React.useContext(SidePanelRuntimeContext)?.openFullscreen;
25
25
  }
26
+ /** 「回主输入框」出口:宿主没接时返回 undefined(送聊天后焦点不动)。 */
27
+ export function useSidePanelFocusChat() {
28
+ return React.useContext(SidePanelRuntimeContext)?.focusChat;
29
+ }
26
30
  export const PanelContext = React.createContext(null);
@@ -32,6 +32,9 @@ type BtwKeyFlags = SidePanelKeyFlags & {
32
32
  /**
33
33
  * 单行 composer 的键语义。返回 null = 未消费(面板形态交宿主回退键,
34
34
  * 全屏形态交场景其余分支);返回对象按 exitFocus > submit > 编辑 写回。
35
+ * ←/→ 先移光标,贴到行首/行尾后返回未消费——面板形态据此切面板。
36
+ * ↑ 让位给列表(选中轮,见 BtwPanelAdapter 的选中态);↓ 在单行框里没有
37
+ * 语义,吃掉即可,免得漏给主聊天去滚 transcript。
35
38
  */
36
39
  export declare function btwComposerKey(state: BtwComposerState, input: string, key: BtwKeyFlags): BtwComposerKeyResult | null;
37
40
  export declare function BtwComposer({ state, focused, busy, notice, onActivate, }: {
@@ -1 +1 @@
1
- {"version":3,"file":"BtwComposer.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwComposer.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAGpD,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,wCAAwC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,qDAAqD;AACrD,KAAK,WAAW,GAAG,iBAAiB,GAAG;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,oBAAoB,GAAG,IAAI,CA0BpH;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAU,GACX,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAA;IAClF,iCAAiC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CA6ClB"}
1
+ {"version":3,"file":"BtwComposer.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwComposer.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAGpD,+CAA+C;AAC/C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,wCAAwC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED,qDAAqD;AACrD,KAAK,WAAW,GAAG,iBAAiB,GAAG;IACrC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,oBAAoB,GAAG,IAAI,CAsCpH;AAED,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAU,GACX,EAAE;IACD,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAA;IAChC,2BAA2B;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IACtB,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAA;IAClF,iCAAiC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CACjC,GAAG,KAAK,CAAC,SAAS,CA6ClB"}
@@ -5,6 +5,9 @@ import { nextCodePoint, previousCodePoint } from '../../AgentMessageComposer.js'
5
5
  /**
6
6
  * 单行 composer 的键语义。返回 null = 未消费(面板形态交宿主回退键,
7
7
  * 全屏形态交场景其余分支);返回对象按 exitFocus > submit > 编辑 写回。
8
+ * ←/→ 先移光标,贴到行首/行尾后返回未消费——面板形态据此切面板。
9
+ * ↑ 让位给列表(选中轮,见 BtwPanelAdapter 的选中态);↓ 在单行框里没有
10
+ * 语义,吃掉即可,免得漏给主聊天去滚 transcript。
8
11
  */
9
12
  export function btwComposerKey(state, input, key) {
10
13
  if (key.escape === true)
@@ -19,6 +22,11 @@ export function btwComposerKey(state, input, key) {
19
22
  // Tab 离开编辑层去列表(与 TrajectoryPanel 同款双形态判定)。
20
23
  if (key.tab === true || input === '\t')
21
24
  return { exitFocus: true };
25
+ // ↑ 也从编辑层上到列表:光标落在本轮标题上(列表形态默认选中最后一条)。
26
+ if (key.upArrow === true)
27
+ return { exitFocus: true };
28
+ if (key.downArrow === true)
29
+ return {};
22
30
  if (key.backspace === true || key.delete === true) {
23
31
  if (caret <= 0)
24
32
  return { state: { ...state, caret } };
@@ -29,10 +37,17 @@ export function btwComposerKey(state, input, key) {
29
37
  // leftArrow 判定不看 shift)——编辑中途也能一键换面板,不必先 Esc 收起。
30
38
  if ((key.leftArrow === true || key.rightArrow === true) && key.shift === true)
31
39
  return null;
32
- if (key.leftArrow === true)
33
- return { state: { ...state, caret: previousCodePoint(state.text, caret) } };
34
- if (key.rightArrow === true)
35
- return { state: { ...state, caret: nextCodePoint(state.text, caret) } };
40
+ // 光标先走、到头让位:还能移就移一格,已经贴着行首/行尾则返回未消费——
41
+ // 面板形态下落宿主切面板,底栏「←/→ 切换」因此在编辑层同样成立;场景
42
+ // 形态下无人接管,等于空操作。
43
+ if (key.leftArrow === true) {
44
+ const previous = previousCodePoint(state.text, caret);
45
+ return previous === caret ? null : { state: { ...state, caret: previous } };
46
+ }
47
+ if (key.rightArrow === true) {
48
+ const next = nextCodePoint(state.text, caret);
49
+ return next === caret ? null : { state: { ...state, caret: next } };
50
+ }
36
51
  if (key.home === true)
37
52
  return { state: { ...state, caret: 0 } };
38
53
  if (key.end === true)
@@ -46,8 +61,5 @@ export function BtwComposer({ state, focused, busy, notice, onActivate, }) {
46
61
  const { text, caret } = state;
47
62
  const shown = Math.min(caret, text.length);
48
63
  const afterCaret = nextCodePoint(text, shown);
49
- return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(Box, { width: "100%", flexShrink: 0, borderStyle: "round", borderColor: focused ? 'accent' : undefined, onClick: onActivate === undefined ? undefined : event => {
50
- event.stopImmediatePropagation();
51
- onActivate();
52
- }, children: _jsxs(Box, { flexDirection: "row", flexShrink: 0, paddingLeft: 1, paddingRight: 1, children: [_jsx(Text, { color: focused ? 'accent' : undefined, bold: true, children: '›' }), _jsx(Text, { children: ' ' }), focused ? (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", flexShrink: 1, minWidth: 0, children: [_jsx(Text, { wrap: "truncate", children: text.slice(0, shown) }), _jsx(InputCaret, { children: text.slice(shown, afterCaret) || ' ' }), text.slice(afterCaret) !== '' ? _jsx(Text, { wrap: "truncate", children: text.slice(afterCaret) }) : null] }), _jsx(Box, { flexGrow: 1, flexShrink: 0, children: _jsx(Text, { children: " " }) }), _jsx(Box, { flexShrink: 0, children: _jsxs(Text, { dimColor: true, children: [" ", t('btw-input-hint-edit')] }) })] })) : (_jsx(Text, { dimColor: true, wrap: "truncate", children: text === '' ? t('btw-input-placeholder') : text }))] }) }), notice !== undefined && (_jsx(Text, { color: notice.failure ? 'error' : undefined, wrap: "truncate", children: notice.text }))] }));
64
+ return (_jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [_jsx(Box, { width: "100%", flexShrink: 0, borderStyle: "round", borderColor: focused ? 'accent' : undefined, onClick: onActivate === undefined ? undefined : () => onActivate(), children: _jsxs(Box, { flexDirection: "row", flexShrink: 0, paddingLeft: 1, paddingRight: 1, children: [_jsx(Text, { color: focused ? 'accent' : undefined, bold: true, children: '›' }), _jsx(Text, { children: ' ' }), focused ? (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", flexShrink: 1, minWidth: 0, children: [_jsx(Text, { wrap: "truncate", children: text.slice(0, shown) }), _jsx(InputCaret, { children: text.slice(shown, afterCaret) || ' ' }), text.slice(afterCaret) !== '' ? _jsx(Text, { wrap: "truncate", children: text.slice(afterCaret) }) : null] }), _jsx(Box, { flexGrow: 1, flexShrink: 0, children: _jsx(Text, { children: " " }) }), _jsx(Box, { flexShrink: 0, children: _jsxs(Text, { dimColor: true, children: [" ", t('btw-input-hint-edit')] }) })] })) : (_jsx(Text, { dimColor: true, wrap: "truncate", children: text === '' ? t('btw-input-placeholder') : text }))] }) }), notice !== undefined && (_jsx(Text, { color: notice.failure ? 'error' : undefined, wrap: "truncate", children: notice.text }))] }));
53
65
  }
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * btw 侧栏面板:线程滚动 + Markdown + 底部 composer 连续追问。Esc 先退出
3
3
  * composer 编辑(草稿保留),列表层不消费 Esc,再交宿主回聊天;Tab 在列表
4
- * 与 composer 间切焦点;未消费的键交宿主(←/→ 仍切面板)。
4
+ * 与 composer 间切焦点;未消费的键交宿主(←/→ 切面板——编辑层里光标贴到
5
+ * 行首/行尾后也让位)。
5
6
  *
6
7
  * badge 派生(镜像 jobs/agents 适配器):面板不可见期间完成的新 answer
7
8
  * 增 info unread、失败 error level 计未读、运行中只亮点不计未读;进入
@@ -1 +1 @@
1
- {"version":3,"file":"BtwPanelAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwPanelAdapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,OAAO,KAAK,EAAmB,UAAU,EAAE,MAAM,aAAa,CAAA;AAY9D,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,UAAU,GAAG,KAAK,CAAC,SAAS,CAsLhG"}
1
+ {"version":3,"file":"BtwPanelAdapter.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwPanelAdapter.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,OAAO,KAAK,EAAmB,UAAU,EAAE,MAAM,aAAa,CAAA;AAY9D,wBAAgB,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,UAAU,GAAG,KAAK,CAAC,SAAS,CAiRhG"}
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
3
  * btw 侧栏面板:线程滚动 + Markdown + 底部 composer 连续追问。Esc 先退出
4
4
  * composer 编辑(草稿保留),列表层不消费 Esc,再交宿主回聊天;Tab 在列表
5
- * 与 composer 间切焦点;未消费的键交宿主(←/→ 仍切面板)。
5
+ * 与 composer 间切焦点;未消费的键交宿主(←/→ 切面板——编辑层里光标贴到
6
+ * 行首/行尾后也让位)。
6
7
  *
7
8
  * badge 派生(镜像 jobs/agents 适配器):面板不可见期间完成的新 answer
8
9
  * 增 info unread、失败 error level 计未读、运行中只亮点不计未读;进入
@@ -12,7 +13,7 @@ import React from 'react';
12
13
  import { Box, Text } from '../../../ui.js';
13
14
  import { t } from '../../../i18n.js';
14
15
  import { panelStore } from '../PanelStore.js';
15
- import { useSidePanelChannel } from '../SidePanelRuntimeContext.js';
16
+ import { useSidePanelChannel, useSidePanelFocusChat } from '../SidePanelRuntimeContext.js';
16
17
  import { usePanelInput } from '../usePanelInput.js';
17
18
  import { truncateWidth } from '../../../trajectory/format.js';
18
19
  import { stringWidth } from '../../../ink/stringWidth.js';
@@ -30,12 +31,16 @@ function btwContextOptions() {
30
31
  }
31
32
  export function BtwPanelAdapter({ width, height, focused, visible }) {
32
33
  const channel = useSidePanelChannel();
34
+ // 送聊天后把列焦点交回主输入框(宿主没接时 undefined = 焦点不动)。
35
+ const focusChat = useSidePanelFocusChat();
33
36
  const sessionId = String(channel.agentId);
34
37
  const thread = useBtwThread(sessionId);
35
38
  const version = thread?.version ?? 0;
36
39
  const busy = thread !== undefined && thread.activeTurnId !== null;
37
40
  // 默认阅读层:箭头归导航(←/→ 切面板、↑/↓ 滚动);Enter/Tab/点击输入框
38
- // 才进编辑层,箭头变光标——聚焦状态有边框高亮与框内提示兜底。
41
+ // 才进编辑层,箭头变光标——光标贴到行首/行尾后再按同一个键同样落回宿主
42
+ // 切面板(BtwComposer 的到头让位),所以底栏「←/→ 切换」在两层都成立;
43
+ // 聚焦状态另有边框高亮与框内提示兜底。
39
44
  const [composerFocus, setComposerFocusState] = React.useState(false);
40
45
  // 聚焦位也骑 ref:Enter 聚焦后紧接着的按键(两键之间没有重渲染)必须
41
46
  // 已经看见编辑层——与 caret 同一款契约,否则第一个字符会被列表层吃掉。
@@ -71,8 +76,10 @@ export function BtwPanelAdapter({ width, height, focused, visible }) {
71
76
  // eslint-disable-next-line react-hooks/exhaustive-deps -- badge derives from the thread snapshot version
72
77
  }, [version, visible]);
73
78
  const attachTurn = React.useCallback((turn) => {
79
+ if (turn.phase !== 'completed')
80
+ return false;
74
81
  if (typeof channel.attachContext !== 'function')
75
- return;
82
+ return false;
76
83
  channel.attachContext({
77
84
  source: 'panel',
78
85
  sourceId: turn.turnId,
@@ -81,7 +88,29 @@ export function BtwPanelAdapter({ width, height, focused, visible }) {
81
88
  });
82
89
  const staged = channel.attachedContexts.find(entry => entry.sourceId === turn.turnId);
83
90
  channel.notify(staged?.truncated === true ? t('btw-thread-answer-truncated') : t('btw-thread-answer-attached'), { color: 'success' });
91
+ return true;
92
+ }, [channel]);
93
+ /** 该轮是否已经挂在主输入框上(sourceId = turnId;部分夹具没有这个面)。 */
94
+ const attachedEntryOf = React.useCallback((turnId) => {
95
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: partial fixture channels
96
+ return (channel.attachedContexts ?? []).find(entry => entry.sourceId === turnId);
84
97
  }, [channel]);
98
+ /**
99
+ * `s` = 送聊天,再按一次 = 撤回(选中行 → 动作)。送出去之后把列焦点交回主
100
+ * 输入框:chip 就在眼前、可直接接着打字,toast 里那句「Esc 可撤」也才成立
101
+ * (剥 chip 的 Esc 只有主输入框有焦点才收得到)。
102
+ */
103
+ const sendToChat = React.useCallback((turn) => {
104
+ const staged = attachedEntryOf(turn.turnId);
105
+ if (staged !== undefined) {
106
+ if (typeof channel.detachContext === 'function')
107
+ channel.detachContext(staged.id);
108
+ channel.notify(t('panel-context-detached'), { color: 'success' });
109
+ return;
110
+ }
111
+ if (attachTurn(turn))
112
+ focusChat?.();
113
+ }, [attachTurn, attachedEntryOf, channel, focusChat]);
85
114
  const submitDraft = React.useCallback(() => {
86
115
  const text = btwThreads.get(sessionId)?.draft ?? '';
87
116
  if (text.trim() === '')
@@ -111,6 +140,35 @@ export function BtwPanelAdapter({ width, height, focused, visible }) {
111
140
  void setClipboard(latest.answer);
112
141
  channel.notify(t('copied-chars', { n: latest.answer.length }), { timeoutMs: 1500 });
113
142
  }, [sessionId, channel]);
143
+ // ── 选中轮:列表形态(composer 不聚焦)的键盘归它 ─────────────────────
144
+ // 选中态存在线程 store 里(与 draft 同理:面板与全屏场景共用),快照给的
145
+ // selectedTurnId 已经解析过「跟最后一条」——null 只在空线程上出现。
146
+ const turns = thread?.turns ?? [];
147
+ const selectedId = thread?.selectedTurnId ?? null;
148
+ const selectedTurn = turns.find(turn => turn.turnId === selectedId);
149
+ /** ↑/↓ 移动选中(夹在两端;到底再按 ↓ 由调用方回输入框)。 */
150
+ const moveSelection = React.useCallback((delta) => {
151
+ btwThreads.moveSelection(sessionId, delta);
152
+ }, [sessionId]);
153
+ /** 点标题行:选中那一轮并离开编辑层(高亮只在列表态显示,见 listActive)。 */
154
+ const selectTurn = React.useCallback((turnId) => {
155
+ btwThreads.select(sessionId, turnId);
156
+ setComposerFocus(false);
157
+ }, [sessionId, setComposerFocus]);
158
+ /** 选中轮本身(读实时线程,不依赖渲染期快照)。 */
159
+ const selectedTurnNow = React.useCallback(() => {
160
+ return btwThreads.selectedTurn(sessionId);
161
+ }, [sessionId]);
162
+ /** `c` = 复制选中轮的答案(选中轮还没答案时退回「最后一条已完成」)。 */
163
+ const copySelected = React.useCallback(() => {
164
+ const turn = selectedTurnNow();
165
+ if (turn !== undefined && turn.answer !== '') {
166
+ void setClipboard(turn.answer);
167
+ channel.notify(t('copied-chars', { n: turn.answer.length }), { timeoutMs: 1500 });
168
+ return;
169
+ }
170
+ copyLatest();
171
+ }, [selectedTurnNow, copyLatest, channel]);
114
172
  // ── 键盘:composer 层 > 列表层 > 宿主(未消费的键返回 false)──────────
115
173
  const onKey = React.useCallback((input, key) => {
116
174
  if (composerFocusRef.current) {
@@ -145,25 +203,36 @@ export function BtwPanelAdapter({ width, height, focused, visible }) {
145
203
  newTopic();
146
204
  return true;
147
205
  }
206
+ // 选中轮 + s/c:与 jobs 面板同一套「选中行 → 动作」契约(s 再按一次撤回)。
148
207
  if (input === 's' && key.ctrl !== true && key.meta !== true) {
149
- const latest = [...(btwThreads.get(sessionId)?.turns ?? [])].reverse().find(turn => turn.phase === 'completed');
150
- if (latest !== undefined)
151
- attachTurn(latest);
208
+ const turn = selectedTurnNow();
209
+ if (turn !== undefined)
210
+ sendToChat(turn);
152
211
  return true;
153
212
  }
154
213
  if (input === 'c' && key.ctrl !== true && key.meta !== true) {
155
- copyLatest();
214
+ copySelected();
156
215
  return true;
157
216
  }
158
- // 阅读态滚动:↑/↓ 步进 3 行、PgUp/PgDn 翻页(编辑态的方向键仍归光标)。
217
+ // 列表键盘:↑/↓ 只挪选中——滚动交给 BtwThreadView 的「最小揭示」:目标标题
218
+ // 已经在视口里就一动不动,出了视口才滚到恰好露出那一行。已经在最后一条时
219
+ // 再按 ↓ = 回输入框(与输入框里按 ↑ 上到标题互为往返)。
159
220
  if (key.upArrow === true) {
160
- scrollRef.current?.scrollBy(-3);
221
+ moveSelection(-1);
161
222
  return true;
162
223
  }
163
224
  if (key.downArrow === true) {
164
- scrollRef.current?.scrollBy(3);
225
+ const list = btwThreads.get(sessionId)?.turns ?? [];
226
+ const current = btwThreads.selectedTurn(sessionId);
227
+ const at = current === undefined ? list.length - 1 : list.findIndex(turn => turn.turnId === current.turnId);
228
+ if (list.length === 0 || at === list.length - 1) {
229
+ setComposerFocus(true);
230
+ return true;
231
+ }
232
+ moveSelection(1);
165
233
  return true;
166
234
  }
235
+ // 翻页仍归滚动(列表里 ↑/↓ 已经改成移动选中了)。
167
236
  if (key.pageUp === true) {
168
237
  scrollRef.current?.scrollBy(-(height - 6));
169
238
  return true;
@@ -175,7 +244,7 @@ export function BtwPanelAdapter({ width, height, focused, visible }) {
175
244
  // 其余不独占:返回 false 交宿主(Esc 回聊天、←/→ 切面板、1-9 跳面板)。
176
245
  return false;
177
246
  // eslint-disable-next-line react-hooks/exhaustive-deps
178
- }, [sessionId, submitDraft, newTopic, attachTurn, copyLatest, height, setCaret]);
247
+ }, [sessionId, submitDraft, newTopic, sendToChat, copySelected, moveSelection, selectedTurnNow, height, setCaret]);
179
248
  usePanelInput(onKey, { active: focused && visible });
180
249
  // ── 头部(只有线程后才画):首问标题 + 状态徽 + 新话题,下压一条细线 ──
181
250
  // 空线程不画头部:标题没有内容,`新话题` 在空线程上也无事可做(清空/换题的
@@ -187,5 +256,27 @@ export function BtwPanelAdapter({ width, height, focused, visible }) {
187
256
  const budget = Math.max(6, width - 2);
188
257
  const titleRoom = budget - stringWidth(newLabel) - stringWidth(chip) - 4;
189
258
  const header = turnCount === 0 ? null : (_jsxs(Box, { flexDirection: "column", width: "100%", flexShrink: 0, children: [_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, paddingLeft: 1, children: [_jsx(Text, { bold: true, wrap: "truncate", children: truncateWidth(title, Math.max(2, titleRoom)) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, children: _jsx(Text, { children: " " }) }), chip !== '' && (_jsx(Box, { flexShrink: 0, children: _jsxs(Text, { color: busy ? 'warning' : undefined, dimColor: !busy, children: [chip, " "] }) })), _jsx(Box, { flexShrink: 0, onClick: event => { event.stopImmediatePropagation(); newTopic(); }, children: _jsxs(Text, { color: "permission", children: ["[n] ", newLabel] }) })] }), _jsx(Box, { width: "100%", height: 1, children: _jsx(Text, { dimColor: true, children: '─'.repeat(Math.max(4, width - 2)) }) })] }));
190
- return (_jsxs(Box, { flexDirection: "column", width: "100%", height: height, overflow: "hidden", children: [header, _jsx(BtwThreadView, { thread: thread, width: width, height: Math.max(3, height - (header === null ? 4 : 6)), alive: visible, onAttachTurn: attachTurn, scrollHandleRef: scrollRef }), _jsx(BtwComposer, { state: { text: thread?.draft ?? '', caret }, focused: composerFocus && focused && visible, busy: busy, notice: notice === undefined || notice === null ? undefined : notice, onActivate: activateComposer })] }));
259
+ // 选中高亮 + 光标声明只在列表态出现:光标在主输入框(列没聚焦)或侧栏输入框
260
+ // (composer 编辑层)时都不显示——用户要的是「列表拿着键盘」这个状态的指示,
261
+ // 不是常驻标记。
262
+ const listActive = focused && visible && !composerFocus;
263
+ // 底栏广告按层走(层内状态只有面板自己知道,所以由面板发、宿主只拼):
264
+ // - 列表层:有轮才说 s/c(已附加的那一轮同一个键是撤回);
265
+ // - 编辑层:s/c 在输入框里只是打字,只说「↑ 回标题」;
266
+ // - 空线程没有可选的轮,明确广告空串(连能力位那一段也不画,免得广告一个按
267
+ // 下去没反应的 s);
268
+ // - 光标在主输入框时面板根本收不到键,整段不画。
269
+ const selectedAttached = selectedTurn !== undefined && attachedEntryOf(selectedTurn.turnId) !== undefined;
270
+ const hintText = !focused || !visible
271
+ ? ''
272
+ : composerFocus
273
+ ? t('btw-hint-edit-back')
274
+ : turns.length === 0
275
+ ? ''
276
+ : t(selectedAttached ? 'btw-list-hint-attached' : 'btw-list-hint');
277
+ React.useEffect(() => {
278
+ panelStore.setHint('btw', hintText);
279
+ return () => { panelStore.setHint('btw', ''); };
280
+ }, [hintText]);
281
+ return (_jsxs(Box, { flexDirection: "column", width: "100%", height: height, overflow: "hidden", children: [header, _jsx(BtwThreadView, { thread: thread, width: width, height: Math.max(3, height - (header === null ? 4 : 6)), alive: visible, selectedTurnId: listActive ? selectedId ?? undefined : undefined, onSelectTurn: selectTurn, scrollHandleRef: scrollRef }), _jsx(BtwComposer, { state: { text: thread?.draft ?? '', caret }, focused: composerFocus && focused && visible, busy: busy, notice: notice === undefined || notice === null ? undefined : notice, onActivate: activateComposer })] }));
191
282
  }
@@ -3,12 +3,16 @@
3
3
  * 滚动、composer 追问。Esc 返回侧栏,面板状态原样(mountPolicy=enabled
4
4
  * 不卸载,thread 与 draft 都在线程 store)。
5
5
  *
6
- * 键层级:composer 编辑(Esc 收起草稿)> 场景滚动/动作 > Esc 退出场景。
6
+ * 键层级:composer 编辑(Esc 收起草稿、↑ 上到标题)> 场景动作(↑/↓ 选轮、
7
+ * s 送聊天/撤回、c 复制)> Esc 退出场景。选中态与侧栏面板同源(线程 store),
8
+ * 两个形态的键位与落点逐条对齐。
7
9
  */
8
10
  import React from 'react';
9
11
  import type { ChannelUi } from '../../../adapter/channel/ui-policy.js';
10
- export declare function BtwThreadScene({ channel, onClose, }: {
12
+ export declare function BtwThreadScene({ channel, onClose, onFocusChat, }: {
11
13
  readonly channel: ChannelUi;
12
14
  readonly onClose: () => void;
15
+ /** 送聊天之后把焦点交回主输入框(宿主没接时只关场景)。 */
16
+ readonly onFocusChat?: (() => void) | undefined;
13
17
  }): React.ReactNode;
14
18
  //# sourceMappingURL=BtwThreadScene.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"BtwThreadScene.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwThreadScene.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAA;AAOtE,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,OAAO,GACR,EAAE;IACD,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAC7B,GAAG,KAAK,CAAC,SAAS,CAqHlB"}
1
+ {"version":3,"file":"BtwThreadScene.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwThreadScene.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAA;AAQtE,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,OAAO,EACP,WAAW,GACZ,EAAE;IACD,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAA;IAC5B,iCAAiC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CAChD,GAAG,KAAK,CAAC,SAAS,CAuKlB"}