@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
@@ -4,7 +4,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
4
4
  * 滚动、composer 追问。Esc 返回侧栏,面板状态原样(mountPolicy=enabled
5
5
  * 不卸载,thread 与 draft 都在线程 store)。
6
6
  *
7
- * 键层级:composer 编辑(Esc 收起草稿)> 场景滚动/动作 > Esc 退出场景。
7
+ * 键层级:composer 编辑(Esc 收起草稿、↑ 上到标题)> 场景动作(↑/↓ 选轮、
8
+ * s 送聊天/撤回、c 复制)> Esc 退出场景。选中态与侧栏面板同源(线程 store),
9
+ * 两个形态的键位与落点逐条对齐。
8
10
  */
9
11
  import React from 'react';
10
12
  import { Box, Text, useInput, useTerminalSize } from '../../../ui.js';
@@ -14,7 +16,7 @@ import { btwThreads } from './threads.js';
14
16
  import { getBtwContextBudget, getBtwContextTurns } from '../../../tuiDisplayPrefs.js';
15
17
  import { BtwComposer, btwComposerKey } from './BtwComposer.js';
16
18
  import { BtwThreadView } from './BtwThreadView.js';
17
- export function BtwThreadScene({ channel, onClose, }) {
19
+ export function BtwThreadScene({ channel, onClose, onFocusChat, }) {
18
20
  const { columns, rows } = useTerminalSize();
19
21
  const sessionId = String(channel.agentId);
20
22
  const thread = React.useSyncExternalStore(btwThreads.subscribe, () => btwThreads.get(sessionId));
@@ -29,11 +31,15 @@ export function BtwThreadScene({ channel, onClose, }) {
29
31
  const [notice, setNotice] = React.useState(null);
30
32
  const scrollRef = React.useRef(null);
31
33
  const busy = thread !== undefined && thread.activeTurnId !== null;
34
+ // 选中轮与侧栏面板同源(线程 store):↑/↓ 移动、s 送聊天/撤回、c 复制。
35
+ const turns = thread?.turns ?? [];
36
+ const selectedId = thread?.selectedTurnId ?? null;
37
+ const selectedTurn = turns.find(turn => turn.turnId === selectedId);
32
38
  const attachTurn = React.useCallback((turn) => {
33
39
  if (turn.phase !== 'completed')
34
- return;
40
+ return false;
35
41
  if (typeof channel.attachContext !== 'function')
36
- return;
42
+ return false;
37
43
  channel.attachContext({
38
44
  source: 'panel',
39
45
  sourceId: turn.turnId,
@@ -42,7 +48,42 @@ export function BtwThreadScene({ channel, onClose, }) {
42
48
  });
43
49
  const staged = channel.attachedContexts.find(entry => entry.sourceId === turn.turnId);
44
50
  channel.notify(staged?.truncated === true ? t('btw-thread-answer-truncated') : t('btw-thread-answer-attached'), { color: 'success' });
51
+ return true;
45
52
  }, [channel]);
53
+ /**
54
+ * `s` = 送聊天,再按一次 = 撤回(与侧栏面板、jobs/companion 同一契约)。
55
+ * 送出去之后这个整屏场景就让位:关掉场景 + 焦点交回主输入框——等价于侧栏
56
+ * 形态里「面板留着、焦点回到输入框」,两种形态的落点一致。
57
+ */
58
+ const sendToChat = React.useCallback((turn) => {
59
+ // oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: partial fixture channels
60
+ const staged = (channel.attachedContexts ?? []).find(entry => entry.sourceId === turn.turnId);
61
+ if (staged !== undefined) {
62
+ if (typeof channel.detachContext === 'function')
63
+ channel.detachContext(staged.id);
64
+ channel.notify(t('panel-context-detached'), { color: 'success' });
65
+ return;
66
+ }
67
+ if (!attachTurn(turn))
68
+ return;
69
+ onFocusChat?.();
70
+ onClose();
71
+ }, [attachTurn, channel, onFocusChat, onClose]);
72
+ /** 点标题行:选中那一轮并离开编辑层(高亮只在列表态显示)。 */
73
+ const selectTurn = React.useCallback((turnId) => {
74
+ btwThreads.select(sessionId, turnId);
75
+ setComposerFocus(false);
76
+ }, [sessionId]);
77
+ const copySelected = React.useCallback(() => {
78
+ const turn = btwThreads.selectedTurn(sessionId);
79
+ const answer = turn !== undefined && turn.answer !== ''
80
+ ? turn.answer
81
+ : [...(btwThreads.get(sessionId)?.turns ?? [])].reverse().find(candidate => candidate.phase === 'completed')?.answer;
82
+ if (answer === undefined)
83
+ return;
84
+ void setClipboard(answer);
85
+ channel.notify(t('copied-chars', { n: answer.length }), { timeoutMs: 1500 });
86
+ }, [sessionId, channel]);
46
87
  useInput((input, key, event) => {
47
88
  if (composerFocus) {
48
89
  const text = btwThreads.get(sessionId)?.draft ?? '';
@@ -80,14 +121,23 @@ export function BtwThreadScene({ channel, onClose, }) {
80
121
  onClose();
81
122
  return;
82
123
  }
124
+ // ↑/↓ 只挪选中,滚动交给 BtwThreadView 的「最小揭示」(出了视口才滚)。
83
125
  if (key.upArrow) {
84
- scrollRef.current?.scrollBy(-3);
85
126
  event.stopImmediatePropagation();
127
+ btwThreads.moveSelection(sessionId, -1);
86
128
  return;
87
129
  }
88
130
  if (key.downArrow) {
89
- scrollRef.current?.scrollBy(3);
90
131
  event.stopImmediatePropagation();
132
+ const list = btwThreads.get(sessionId)?.turns ?? [];
133
+ const current = btwThreads.selectedTurn(sessionId);
134
+ const at = current === undefined ? list.length - 1 : list.findIndex(turn => turn.turnId === current.turnId);
135
+ // 已在最后一条:↓ 回输入框(与输入框里按 ↑ 上到标题互为往返)。
136
+ if (list.length === 0 || at === list.length - 1) {
137
+ setComposerFocus(true);
138
+ return;
139
+ }
140
+ btwThreads.moveSelection(sessionId, 1);
91
141
  return;
92
142
  }
93
143
  if (key.pageUp) {
@@ -114,20 +164,16 @@ export function BtwThreadScene({ channel, onClose, }) {
114
164
  return;
115
165
  }
116
166
  if (input === 's' && !key.ctrl && !key.meta) {
117
- const latest = [...(btwThreads.get(sessionId)?.turns ?? [])].reverse().find(turn => turn.phase === 'completed');
118
- if (latest !== undefined)
119
- attachTurn(latest);
167
+ const turn = btwThreads.selectedTurn(sessionId);
168
+ if (turn !== undefined)
169
+ sendToChat(turn);
120
170
  event.stopImmediatePropagation();
121
171
  return;
122
172
  }
123
173
  if (input === 'c' && !key.ctrl && !key.meta) {
124
- const latest = [...(btwThreads.get(sessionId)?.turns ?? [])].reverse().find(turn => turn.phase === 'completed');
125
- if (latest !== undefined) {
126
- void setClipboard(latest.answer);
127
- channel.notify(t('copied-chars', { n: latest.answer.length }), { timeoutMs: 1500 });
128
- }
174
+ copySelected();
129
175
  event.stopImmediatePropagation();
130
176
  }
131
177
  });
132
- return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, children: [_jsx(Text, { color: "warning", bold: true, children: t('btw-fullscreen-title') }), _jsx(Text, { dimColor: true, wrap: "truncate", children: ' ' + t('btw-scene-hints') })] }), _jsx(BtwThreadView, { thread: thread, width: columns - 2, height: Math.max(3, rows - 4), alive: true, onAttachTurn: attachTurn, scrollHandleRef: scrollRef }), _jsx(BtwComposer, { state: { text: thread?.draft ?? '', caret }, focused: composerFocus, busy: busy, notice: notice === null ? undefined : notice, onActivate: activateComposer })] }));
178
+ return (_jsxs(Box, { flexDirection: "column", width: columns, height: rows, paddingX: 1, children: [_jsxs(Box, { flexDirection: "row", width: "100%", height: 1, flexShrink: 0, children: [_jsx(Text, { color: "warning", bold: true, children: t('btw-fullscreen-title') }), _jsx(Text, { dimColor: true, wrap: "truncate", children: ' ' + t('btw-scene-hints') })] }), _jsx(BtwThreadView, { thread: thread, width: columns - 2, height: Math.max(3, rows - 4), alive: true, selectedTurnId: composerFocus ? undefined : selectedId ?? undefined, onSelectTurn: selectTurn, scrollHandleRef: scrollRef }), _jsx(BtwComposer, { state: { text: thread?.draft ?? '', caret }, focused: composerFocus, busy: busy, notice: notice === null ? undefined : notice, onActivate: activateComposer })] }));
133
179
  }
@@ -7,13 +7,23 @@
7
7
  * 跟尾:默认跟随尾部;用户上滚后暂停 follow,
8
8
  * 出现「有新回答」跳尾提示(点击回底)。ScrollBox 的 sticky 位就是
9
9
  * follow 信号——上滚打破 sticky,scrollToBottom/贴底恢复。
10
+ *
11
+ * 消息区不是控件:点它跟点面板其它地方一样,只由宿主把列焦点交给面板
12
+ * (见 BtwComposer 的点击注释),注入/复制的入口是选中轮 + `s`/`c`。
13
+ * 选中只看标题那一行:反色只覆盖标题本身的字,终端光标也声明在那儿。
14
+ * 选中轮滚出视口时只滚到「恰好露出这一行」:往上走贴视口顶、往下走贴视口底;
15
+ * 已经在视口里就只挪高亮,不动滚动位置。
10
16
  */
11
17
  import React from 'react';
12
18
  import { type ScrollBoxHandle } from '../../../ui.js';
13
- import type { BtwThreadSnapshot, BtwTurn } from './threads.js';
19
+ import type { BtwThreadSnapshot } from './threads.js';
14
20
  export declare function BtwThreadView({ thread, width, height,
15
21
  /** 渲时钟的开关(面板不可见/场景失焦时停表)。 */
16
- alive, onAttachTurn,
22
+ alive,
23
+ /** 当前选中的轮(标题反色 + 光标声明);undefined = 列表没有选中态。 */
24
+ selectedTurnId,
25
+ /** 点标题行把选中挪到那一轮(继续冒泡,宿主照旧拿列焦点)。 */
26
+ onSelectTurn,
17
27
  /** 宿主(全屏场景/浮层)接管键盘滚动用的句柄透传。 */
18
28
  scrollHandleRef, }: {
19
29
  readonly thread: BtwThreadSnapshot | undefined;
@@ -21,8 +31,8 @@ scrollHandleRef, }: {
21
31
  /** 滚动区行预算(含滚动区自身;跳尾提示一行另计)。 */
22
32
  readonly height: number;
23
33
  readonly alive: boolean;
24
- /** 点击已完成轮的答案区触发送到聊天(fallback 形态不传 = 无该交互)。 */
25
- readonly onAttachTurn?: (turn: BtwTurn) => void;
34
+ readonly selectedTurnId?: string | undefined;
35
+ readonly onSelectTurn?: ((turnId: string) => void) | undefined;
26
36
  readonly scrollHandleRef?: {
27
37
  current: ScrollBoxHandle | null;
28
38
  };
@@ -1 +1 @@
1
- {"version":3,"file":"BtwThreadView.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwThreadView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAK3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAsB9D,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,MAAM;AACN,6BAA6B;AAC7B,KAAK,EACL,YAAY;AACZ,+BAA+B;AAC/B,eAAe,GAChB,EAAE;IACD,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAA;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,8CAA8C;IAC9C,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAC/C,QAAQ,CAAC,eAAe,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;KAAE,CAAA;CAC/D,GAAG,KAAK,CAAC,SAAS,CAgHlB"}
1
+ {"version":3,"file":"BtwThreadView.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/BtwThreadView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAO3E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AA2DrD,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,KAAK,EACL,MAAM;AACN,6BAA6B;AAC7B,KAAK;AACL,+CAA+C;AAC/C,cAAc;AACd,mCAAmC;AACnC,YAAY;AACZ,+BAA+B;AAC/B,eAAe,GAChB,EAAE;IACD,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,SAAS,CAAA;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC5C,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAA;IAC9D,QAAQ,CAAC,eAAe,CAAC,EAAE;QAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;KAAE,CAAA;CAC/D,GAAG,KAAK,CAAC,SAAS,CA6JlB"}
@@ -8,12 +8,19 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
8
8
  * 跟尾:默认跟随尾部;用户上滚后暂停 follow,
9
9
  * 出现「有新回答」跳尾提示(点击回底)。ScrollBox 的 sticky 位就是
10
10
  * follow 信号——上滚打破 sticky,scrollToBottom/贴底恢复。
11
+ *
12
+ * 消息区不是控件:点它跟点面板其它地方一样,只由宿主把列焦点交给面板
13
+ * (见 BtwComposer 的点击注释),注入/复制的入口是选中轮 + `s`/`c`。
14
+ * 选中只看标题那一行:反色只覆盖标题本身的字,终端光标也声明在那儿。
15
+ * 选中轮滚出视口时只滚到「恰好露出这一行」:往上走贴视口顶、往下走贴视口底;
16
+ * 已经在视口里就只挪高亮,不动滚动位置。
11
17
  */
12
18
  import React from 'react';
13
19
  import { Box, Text, ScrollBox } from '../../../ui.js';
14
20
  import { Markdown } from '../../Markdown.js';
15
21
  import { SpinnerGlyph } from '../../Spinner/SpinnerGlyph.js';
16
22
  import { t } from '../../../i18n.js';
23
+ import { useDeclaredCursor, useNativeCursor } from '../../../ink/hooks/use-declared-cursor.js';
17
24
  import { getBtwContextTurns, subscribeBtwContextTurns } from '../../../tuiDisplayPrefs.js';
18
25
  /** 80ms spinner 帧(只在有 running 轮且其还没收到首段文本时走时钟)。 */
19
26
  const SPINNER_MS = 80;
@@ -21,9 +28,36 @@ const SPINNER_MS = 80;
21
28
  function BtwEmptyState({ contextTurns }) {
22
29
  return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, children: [_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "subtle", wrap: "truncate", children: t('btw-thread-empty') }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "subtle", wrap: "wrap", children: t('btw-empty-lines') }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, italic: true, wrap: "wrap", children: t('btw-thread-context-recent', { n: contextTurns }) }) })] }));
23
30
  }
31
+ /**
32
+ * 一轮的标题行(问题)。选中 = 只反色标题本身的字(不铺满整行),并把终端
33
+ * 光标声明在这一行上:按 ↑/↓ 时原生光标的拖尾是「在标题之间上下走」,而不是
34
+ * 掉到屏幕左下角(没有声明时渲染器的兜底位置)。点这一行 = 把高亮挪过来
35
+ * (`onSelect`),点击继续冒泡,宿主照旧拿到列焦点。
36
+ */
37
+ function QuestionRow({ turnId, text, selected, onSelect, onRegister }) {
38
+ const native = useNativeCursor();
39
+ // 与 ListItem 同款:移动期间可见、静止 500ms 后收起,形状/闪烁归终端。
40
+ const cursorRef = useDeclaredCursor({ line: 0, column: 0, active: selected, visible: native, hideOnIdle: native });
41
+ // 组装 ref 时必须把 cursorRef 的 cleanup 转交出去(React 19 用返回值当卸载
42
+ // 清理),否则这一行被删掉时光标声明会留在原地。
43
+ const setNode = React.useCallback((node) => {
44
+ const cleanup = cursorRef(node);
45
+ onRegister?.(turnId, node);
46
+ return () => {
47
+ if (typeof cleanup === 'function')
48
+ cleanup();
49
+ onRegister?.(turnId, null);
50
+ };
51
+ }, [cursorRef, onRegister, turnId]);
52
+ return (_jsx(Box, { ref: setNode, onClick: onSelect === undefined ? undefined : () => onSelect(turnId), children: _jsx(Text, { color: "accent", bold: true, inverse: selected, wrap: "wrap", children: text }) }));
53
+ }
24
54
  export function BtwThreadView({ thread, width, height,
25
55
  /** 渲时钟的开关(面板不可见/场景失焦时停表)。 */
26
- alive, onAttachTurn,
56
+ alive,
57
+ /** 当前选中的轮(标题反色 + 光标声明);undefined = 列表没有选中态。 */
58
+ selectedTurnId,
59
+ /** 点标题行把选中挪到那一轮(继续冒泡,宿主照旧拿列焦点)。 */
60
+ onSelectTurn,
27
61
  /** 宿主(全屏场景/浮层)接管键盘滚动用的句柄透传。 */
28
62
  scrollHandleRef, }) {
29
63
  const localScrollRef = React.useRef(null);
@@ -77,6 +111,60 @@ scrollHandleRef, }) {
77
111
  setPendingJump(true);
78
112
  // eslint-disable-next-line react-hooks/exhaustive-deps
79
113
  }, [version, answerLengths, follow]);
114
+ // ── 选中轮的最小滚动揭示 ─────────────────────────────────────────────
115
+ // 行节点表:QuestionRow 挂载时交进来;滚动位置一律走 ScrollBox 的
116
+ // scrollToElement(位置在渲染期读元素 Yoga top,不会用到过期数字)。
117
+ const rowNodes = React.useRef(new Map());
118
+ const registerRow = React.useCallback((turnId, node) => {
119
+ if (node === null)
120
+ rowNodes.current.delete(turnId);
121
+ else
122
+ rowNodes.current.set(turnId, node);
123
+ }, []);
124
+ /**
125
+ * 节点在滚动内容里的行号(不含滚动位移):沿祖先累加 Yoga top,直到撞上滚动
126
+ * 容器(ScrollBox 的节点上才有 scrollTop)。没撞到(浮层回退等无滚动区形态)
127
+ * 返回 undefined——宁可不滚,也不要按错误的坐标系乱跳。
128
+ */
129
+ const contentRowOf = (node) => {
130
+ let rows = 0;
131
+ let current = node;
132
+ while (current !== undefined && current.parentNode !== undefined) {
133
+ if (current.parentNode.scrollTop !== undefined)
134
+ return rows;
135
+ rows += current.yogaNode?.getComputedTop() ?? 0;
136
+ current = current.parentNode;
137
+ }
138
+ return undefined;
139
+ };
140
+ const previousSelectedRef = React.useRef(undefined);
141
+ React.useLayoutEffect(() => {
142
+ const previous = previousSelectedRef.current;
143
+ previousSelectedRef.current = selectedTurnId;
144
+ // 从编辑层或主输入框回列表时也要揭示:长答案跟尾后,标题可能在视口外。
145
+ if (selectedTurnId === undefined || previous === selectedTurnId)
146
+ return;
147
+ const handle = scrollRef.current;
148
+ const node = rowNodes.current.get(selectedTurnId);
149
+ if (handle === null || node === undefined)
150
+ return;
151
+ const viewport = handle.getViewportHeight();
152
+ if (viewport <= 0)
153
+ return;
154
+ const rows = Math.max(1, Math.ceil(node.yogaNode?.getComputedHeight() ?? 1));
155
+ const top = contentRowOf(node);
156
+ if (top === undefined)
157
+ return;
158
+ const scrollTop = handle.getScrollTop();
159
+ // 用算好的内容行号直接 scrollTo:scrollToElement 读的是元素相对**父节点**的
160
+ // top,标题盒子嵌在 turn 里,用它会把滚动甩到内容顶部。布局已稳定(只有选中
161
+ // 变了),这里的数字不会过期。
162
+ // 往上走出视口 → 贴视口顶;往下走出视口 → 整行贴视口底(恰好露出,不多滚)。
163
+ if (top < scrollTop)
164
+ handle.scrollTo(top);
165
+ else if (top + rows > scrollTop + viewport)
166
+ handle.scrollTo(top + rows - viewport);
167
+ }, [selectedTurnId]);
80
168
  const jumpTail = React.useCallback(() => {
81
169
  scrollRef.current?.scrollToBottom();
82
170
  setFollow(true);
@@ -84,10 +172,7 @@ scrollHandleRef, }) {
84
172
  }, []);
85
173
  if (thread === undefined || thread.turns.length === 0)
86
174
  return _jsx(BtwEmptyState, { contextTurns: contextTurns });
87
- return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", paddingX: 1, children: [_jsx(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, stickyScroll: true, children: thread.turns.map((turn, index) => (_jsxs(Box, { flexDirection: "column", children: [index > 0 && _jsx(Text, { dimColor: true, children: '┈'.repeat(Math.max(4, width - 2)) }), _jsx(Text, { color: "accent", bold: true, wrap: "wrap", children: turn.question }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [turn.phase === 'completed' ? (_jsx(Box, { onClick: onAttachTurn === undefined ? undefined : event => {
88
- event.stopImmediatePropagation();
89
- onAttachTurn(turn);
90
- }, children: _jsx(Markdown, { cacheTokens: false, children: turn.answer }) })) : turn.phase === 'failed' || turn.phase === 'cancelled' ? (_jsxs(_Fragment, { children: [turn.answer !== '' && _jsx(Markdown, { cacheTokens: false, children: turn.answer }), turn.phase === 'failed'
175
+ return (_jsxs(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", paddingX: 1, children: [_jsx(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, stickyScroll: true, children: thread.turns.map((turn, index) => (_jsxs(Box, { flexDirection: "column", children: [index > 0 && _jsx(Text, { dimColor: true, children: '┈'.repeat(Math.max(4, width - 2)) }), _jsx(QuestionRow, { turnId: turn.turnId, text: turn.question, selected: turn.turnId === selectedTurnId, onSelect: onSelectTurn, onRegister: registerRow }), _jsxs(Box, { marginLeft: 2, flexDirection: "column", children: [turn.phase === 'completed' ? (_jsx(Markdown, { cacheTokens: false, children: turn.answer })) : turn.phase === 'failed' || turn.phase === 'cancelled' ? (_jsxs(_Fragment, { children: [turn.answer !== '' && _jsx(Markdown, { cacheTokens: false, children: turn.answer }), turn.phase === 'failed'
91
176
  ? _jsxs(Text, { color: "error", wrap: "wrap", children: [t('btw-thread-error'), turn.error === undefined ? '' : ': ' + turn.error] })
92
177
  : _jsx(Text, { dimColor: true, italic: true, children: t('btw-thread-cancelled') })] })) : turn.answer !== '' ? (_jsx(Markdown, { cacheTokens: false, children: turn.answer })) : (_jsxs(Box, { flexShrink: 0, children: [_jsx(SpinnerGlyph, { frame: frame, messageColor: "warning" }), _jsxs(Text, { color: "warning", children: [" ", t('btw-answering')] })] })), turn.omittedOlderCount > 0 && (_jsx(Text, { dimColor: true, italic: true, wrap: "truncate", children: t('btw-thread-context-omitted', { n: turn.omittedOlderCount }) }))] })] }, turn.turnId))) }), pendingJump && !follow && (_jsx(Box, { flexShrink: 0, onClick: event => { event.stopImmediatePropagation(); jumpTail(); }, children: _jsxs(Text, { color: "permission", children: ["\u2193 ", t('btw-thread-unread')] }) }))] }));
93
178
  }
@@ -22,6 +22,9 @@ export interface BtwThreadSnapshot {
22
22
  readonly turns: readonly BtwTurn[];
23
23
  readonly activeTurnId: string | null;
24
24
  readonly draft: string;
25
+ /** 列表选中的轮(`s` 送聊天 / `c` 复制的对象);null = 跟最后一条。
26
+ * 与 draft 同理放在 store 里:面板与全屏场景共用同一份选中态。 */
27
+ readonly selectedTurnId: string | null;
25
28
  /** seen-through 标尺之后的完成/失败轮(cancelled 不计:用户自己中止,
26
29
  * 不是没看到的新答案)。 */
27
30
  readonly unread: {
@@ -55,6 +58,12 @@ export type BtwSubmitResult = {
55
58
  readonly ok: false;
56
59
  readonly reason: 'empty' | 'busy' | 'congested';
57
60
  };
61
+ /**
62
+ * 有效选中轮:钉住的 id 还在就继续用它,否则跟最后一条(新轮到达自动跟尾、
63
+ * 轮被清掉/换话题自动落回)。面板与全屏场景共用这一条解析,保证两个形态
64
+ * 的选中语义逐字一致。
65
+ */
66
+ export declare function effectiveSelectedTurnId(turns: readonly BtwTurn[], pinned: string | null): string | null;
58
67
  /** 钳到 1–8;非有限值取默认 4。 */
59
68
  export declare function normalizeRecentTurnsLimit(value: number | undefined): number;
60
69
  export interface BtwContextSelection {
@@ -97,6 +106,15 @@ declare class BtwThreadStore {
97
106
  */
98
107
  newTopic(sessionId: string): boolean;
99
108
  setDraft(sessionId: string, text: string): void;
109
+ /** 指定选中某一轮(点标题行;null = 回到跟最后一条)。 */
110
+ select(sessionId: string, turnId: string | null): void;
111
+ /** 当前选中轮(实时解析,不依赖渲染期快照)。 */
112
+ selectedTurn(sessionId: string): BtwTurn | undefined;
113
+ /**
114
+ * ↑/↓ 移动选中:从当前有效选中出发、夹在两端(delta = ±1)。落点即钉住,
115
+ * 所以移动之后不再跟尾;返回新选中轮(线程为空 = undefined)。
116
+ */
117
+ moveSelection(sessionId: string, delta: number): BtwTurn | undefined;
100
118
  /** 看到最新线程:把已落定轮全部记为已读(running 轮落定时再见分晓)。 */
101
119
  markSeen(sessionId: string): void;
102
120
  /** 测试/多夹具隔离用:清空全部线程状态。 */
@@ -1 +1 @@
1
- {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/threads.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"threads.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/btw/threads.ts"],"names":[],"mappings":"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"}
@@ -24,6 +24,16 @@ export const BTW_CONTEXT_CHAR_BUDGET = 24_000;
24
24
  export const BTW_ANSWER_CHAR_BUDGET = 8_000;
25
25
  /** 跨线程并发上限:超过显示忙,不隐式取消。 */
26
26
  export const BTW_MAX_CONCURRENT_ASKS = 2;
27
+ /**
28
+ * 有效选中轮:钉住的 id 还在就继续用它,否则跟最后一条(新轮到达自动跟尾、
29
+ * 轮被清掉/换话题自动落回)。面板与全屏场景共用这一条解析,保证两个形态
30
+ * 的选中语义逐字一致。
31
+ */
32
+ export function effectiveSelectedTurnId(turns, pinned) {
33
+ if (pinned !== null && turns.some(turn => turn.turnId === pinned))
34
+ return pinned;
35
+ return turns.length === 0 ? null : turns[turns.length - 1].turnId;
36
+ }
27
37
  /** 钳到 1–8;非有限值取默认 4。 */
28
38
  export function normalizeRecentTurnsLimit(value) {
29
39
  if (value === undefined || !Number.isFinite(value))
@@ -92,6 +102,7 @@ function buildSnapshot(record) {
92
102
  turns: Object.freeze([...record.turns]),
93
103
  activeTurnId: active === null ? null : active.turnId,
94
104
  draft: record.draft,
105
+ selectedTurnId: effectiveSelectedTurnId(record.turns, record.selectedTurnId),
95
106
  unread: Object.freeze({ count: unreadCount, error: unreadError }),
96
107
  version: record.version,
97
108
  });
@@ -147,6 +158,8 @@ class BtwThreadStore {
147
158
  omittedOlderCount: selection.omittedOlderCount,
148
159
  };
149
160
  record.turns.push(turn);
161
+ // 新轮到达回到跟尾:选中态跟的是「最后一条」,上一轮的钉位不再有意义。
162
+ record.selectedTurnId = null;
150
163
  this.bump(record);
151
164
  const controller = new AbortController();
152
165
  this.controllers.set(turn.turnId, controller);
@@ -230,6 +243,7 @@ class BtwThreadStore {
230
243
  record.generation += 1;
231
244
  record.turns = [];
232
245
  record.draft = '';
246
+ record.selectedTurnId = null;
233
247
  record.seenThroughSeq = this.turnSeq;
234
248
  this.bump(record);
235
249
  return true;
@@ -241,6 +255,41 @@ class BtwThreadStore {
241
255
  record.draft = text;
242
256
  this.bump(record);
243
257
  }
258
+ /** 指定选中某一轮(点标题行;null = 回到跟最后一条)。 */
259
+ select(sessionId, turnId) {
260
+ const record = this.recordOf(sessionId);
261
+ if (record.selectedTurnId === turnId)
262
+ return;
263
+ record.selectedTurnId = turnId;
264
+ this.bump(record);
265
+ }
266
+ /** 当前选中轮(实时解析,不依赖渲染期快照)。 */
267
+ selectedTurn(sessionId) {
268
+ const record = this.threads.get(sessionId);
269
+ if (record === undefined)
270
+ return undefined;
271
+ const id = effectiveSelectedTurnId(record.turns, record.selectedTurnId);
272
+ return id === null ? undefined : record.turns.find(turn => turn.turnId === id);
273
+ }
274
+ /**
275
+ * ↑/↓ 移动选中:从当前有效选中出发、夹在两端(delta = ±1)。落点即钉住,
276
+ * 所以移动之后不再跟尾;返回新选中轮(线程为空 = undefined)。
277
+ */
278
+ moveSelection(sessionId, delta) {
279
+ const record = this.recordOf(sessionId);
280
+ if (record.turns.length === 0)
281
+ return undefined;
282
+ const current = effectiveSelectedTurnId(record.turns, record.selectedTurnId);
283
+ const at = record.turns.findIndex(turn => turn.turnId === current);
284
+ const from = at === -1 ? record.turns.length - 1 : at;
285
+ const next = Math.min(record.turns.length - 1, Math.max(0, from + delta));
286
+ const turnId = record.turns[next].turnId;
287
+ if (record.selectedTurnId !== turnId) {
288
+ record.selectedTurnId = turnId;
289
+ this.bump(record);
290
+ }
291
+ return record.turns[next];
292
+ }
244
293
  /** 看到最新线程:把已落定轮全部记为已读(running 轮落定时再见分晓)。 */
245
294
  markSeen(sessionId) {
246
295
  const record = this.threads.get(sessionId);
@@ -269,6 +318,7 @@ class BtwThreadStore {
269
318
  generation: 0,
270
319
  turns: [],
271
320
  draft: '',
321
+ selectedTurnId: null,
272
322
  seenThroughSeq: this.turnSeq,
273
323
  version: 0,
274
324
  snapshot: Object.freeze({
@@ -279,6 +329,7 @@ class BtwThreadStore {
279
329
  turns: Object.freeze([]),
280
330
  activeTurnId: null,
281
331
  draft: '',
332
+ selectedTurnId: null,
282
333
  unread: Object.freeze({ count: 0, error: false }),
283
334
  version: 0,
284
335
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"builtinPanels.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/builtinPanels.tsx"],"names":[],"mappings":"AA6NA,2BAA2B;AAC3B,wBAAgB,qBAAqB,IAAI,IAAI,CAmG5C"}
1
+ {"version":3,"file":"builtinPanels.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/builtinPanels.tsx"],"names":[],"mappings":"AAiOA,2BAA2B;AAC3B,wBAAgB,qBAAqB,IAAI,IAAI,CAmG5C"}
@@ -141,6 +141,10 @@ function AgentsPanelAdapter({ focused, visible }) {
141
141
  React.useEffect(() => {
142
142
  const running = subagents.filter(s => s.status === 'running' || s.status === 'starting').length;
143
143
  const failedIds = new Set(subagents.filter(s => s.status === 'failed').map(s => s.agentId));
144
+ // A failed team member is durable; it counts once even beside a failed run.
145
+ for (const member of channel.team?.members ?? [])
146
+ if (member.phase === 'failed')
147
+ failedIds.add(member.id);
144
148
  if (visible) {
145
149
  seenFailedRef.current = failedIds;
146
150
  panelStore.setBadge('agents', running > 0 ? { level: 'info', unread: 0 } : null);
@@ -162,7 +166,7 @@ function AgentsPanelAdapter({ focused, visible }) {
162
166
  if (typeof route === 'object' && detail !== undefined) {
163
167
  return (_jsx(SubagentDetailScene, { subagent: detail, variant: "panel", focused: focused, visible: visible, onBack: () => setRoute('dashboard'), onInterrupt: (id) => channel.subagentControl?.interrupt(id), ...(channel.subagentControl?.history === undefined ? {} : { loadTranscript: channel.subagentControl.history }), onOpenView: () => agentViewStore.request(detail.agentId, 'agent-detail', true), messages: detailMessages, ...(detailCompose === undefined ? {} : { compose: detailCompose }) }));
164
168
  }
165
- return (_jsx(SubagentDashboard, { subagents: subagents, variant: "panel", focused: focused, visible: visible, onSelect: (id) => setRoute({ detail: id }), onOpenView: (id) => agentViewStore.request(id, 'agents-dashboard', true), messages: messageControl?.messages() }));
169
+ return (_jsx(SubagentDashboard, { subagents: subagents, team: channel.team, sessionId: channel.sessionId, variant: "panel", focused: focused, visible: visible, onSelect: (id) => setRoute({ detail: id }), onOpenView: (id) => agentViewStore.request(id, 'agents-dashboard', true), messages: messageControl?.messages() }));
166
170
  }
167
171
  let registered = false;
168
172
  /** 幂等:重复调用(夹具多次挂载)不再注册。 */
@@ -19,13 +19,17 @@
19
19
  * 渲染路径(LogoV2 底部块,welcomePad 缩进)。
20
20
  */
21
21
  import React from 'react';
22
+ import { type SplashImageBox } from '../../splashArtRows.js';
22
23
  export type SplashMascotSkin = 'deepy' | 'whaleGirl';
23
24
  /** 读 companion.skin(LogoV2 的测试缝 prop 优先);非吉祥物皮肤返回
24
25
  * undefined(LogoV2 走原鲸鱼/女仆娘路径,零改动)。 */
25
26
  export declare function useSplashMascotSkin(pinned?: string): SplashMascotSkin | undefined;
27
+ /** 图片原生尺寸的紧凑槽;仅启动页使用,协议/像元/素材未就绪时保持原回退。 */
28
+ export declare function useSplashMascotBox(skin: SplashMascotSkin | undefined, compact: boolean): SplashImageBox | undefined;
26
29
  /** 启动页吉祥物本体:按 skin 渲染动画,点击交互(poke/连点)在内层盒。 */
27
- export declare function SplashMascot({ skin, active }: {
30
+ export declare function SplashMascot({ skin, active, imageBox }: {
28
31
  readonly skin: SplashMascotSkin;
32
+ readonly imageBox?: SplashImageBox;
29
33
  /** 动画许可:false(冻结/落地页 whaleIdle=false)时定格 idle 帧 0、零时钟。 */
30
34
  readonly active: boolean;
31
35
  }): React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"SplashMascot.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/companion/SplashMascot.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAiBzB,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,WAAW,CAAA;AAEpD;wCACwC;AACxC,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAIjF;AAGD,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;IAC7C,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB,GAAG,KAAK,CAAC,SAAS,CAqElB"}
1
+ {"version":3,"file":"SplashMascot.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/companion/SplashMascot.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAiB/E,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,WAAW,CAAA;AAEpD;wCACwC;AACxC,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAIjF;AAGD,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CAUnH;AAED,8CAA8C;AAC9C,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE;IACvD,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAA;IAClC,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB,GAAG,KAAK,CAAC,SAAS,CAsElB"}
@@ -20,10 +20,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
20
20
  * 渲染路径(LogoV2 底部块,welcomePad 缩进)。
21
21
  */
22
22
  import React from 'react';
23
- import { Box } from '../../../ui.js';
23
+ import { Box, useTerminalImages, useTerminalImageCellSize, useTerminalImageProtocol } from '../../../ui.js';
24
+ import { fitSplashImageBox } from '../../splashArtRows.js';
25
+ import { loadWhaleGirlKit } from './deepy.js';
24
26
  import { getCompanionSkin, subscribeCompanionSkin } from '../../../tuiDisplayPrefs.js';
25
27
  import { TICKLE_MIN_CLICKS, TICKLE_WINDOW_MS } from './mood.js';
26
- import { DeepySkin, WhaleGirlSkin } from './skins.js';
28
+ import { DeepySkin, WhaleGirlSkin, loadWhaleGirlImageKit } from './skins.js';
27
29
  import { initialCompanionPoseState, nextCompanionPoseStep } from './pose.js';
28
30
  /** 点击反应档时长:poke 帧表一轮 2100ms,取头段(同 CompanionPanel 的口径)。 */
29
31
  const SPLASH_POKE_MS = 1400;
@@ -40,8 +42,20 @@ export function useSplashMascotSkin(pinned) {
40
42
  const id = pinned ?? setting;
41
43
  return id === 'deepy' || id === 'whaleGirl' ? id : undefined;
42
44
  }
45
+ /** 图片原生尺寸的紧凑槽;仅启动页使用,协议/像元/素材未就绪时保持原回退。 */
46
+ export function useSplashMascotBox(skin, compact) {
47
+ // 高度降级可能暂时撤掉吉祥物,因此能力探测不能只依赖吉祥物挂载。
48
+ const available = useTerminalImages(compact && skin === 'whaleGirl');
49
+ const protocol = useTerminalImageProtocol();
50
+ const cell = useTerminalImageCellSize();
51
+ const canvas = available && compact && skin === 'whaleGirl' && cell !== undefined
52
+ && (protocol === 'kitty' || protocol === 'sixel') && loadWhaleGirlKit() !== undefined
53
+ ? loadWhaleGirlImageKit()?.canvas : undefined;
54
+ return React.useMemo(() => canvas !== undefined && cell !== undefined
55
+ ? fitSplashImageBox(canvas, cell, WhaleGirlSkin.cells) : undefined, [canvas, cell]);
56
+ }
43
57
  /** 启动页吉祥物本体:按 skin 渲染动画,点击交互(poke/连点)在内层盒。 */
44
- export function SplashMascot({ skin, active }) {
58
+ export function SplashMascot({ skin, active, imageBox }) {
45
59
  const [, setBump] = React.useState(0);
46
60
  // 稳态 idle 从挂载起循环;冻结时 now 钉在挂载值 → elapsed 恒 0 → 帧 0。
47
61
  const mountedAtRef = React.useRef(Date.now());
@@ -78,6 +92,7 @@ export function SplashMascot({ skin, active }) {
78
92
  now,
79
93
  width: SPLASH_MASCOT_COLUMNS,
80
94
  animationSemantic,
95
+ ...(imageBox === undefined ? {} : { imageBox }),
81
96
  };
82
97
  return (_jsx(Box, { flexDirection: "column", alignItems: "center", flexShrink: 0, children: _jsx(Box, { onClick: (event) => {
83
98
  event.stopImmediatePropagation();
@@ -93,7 +108,7 @@ export function SplashMascot({ skin, active }) {
93
108
  overrideRef.current = rapid
94
109
  ? { semantic: 'tickle', since: at, until: at + TICKLE_WINDOW_MS }
95
110
  : {
96
- semantic: event.localCol < SPLASH_MASCOT_COLUMNS / 2 ? 'poke-left' : 'poke-right',
111
+ semantic: event.localCol < (imageBox?.columns ?? (skin === 'whaleGirl' ? WhaleGirlSkin.cells.columns : SPLASH_MASCOT_COLUMNS)) / 2 ? 'poke-left' : 'poke-right',
97
112
  since: at,
98
113
  until: at + SPLASH_POKE_MS,
99
114
  };
@@ -11,6 +11,7 @@
11
11
  * 皮肤 = id + cells + render(pose, ctx),自定义皮肤走同一接口进入。
12
12
  */
13
13
  import React from 'react';
14
+ import type { SplashImageBox } from '../../splashArtRows.js';
14
15
  import type { I18nKey } from '../../../i18n.js';
15
16
  import type { TerminalImageSource } from '../../../ink/terminal-image.js';
16
17
  import type { CompanionMood } from './mood.js';
@@ -29,6 +30,8 @@ export interface CompanionSkinRenderInput {
29
30
  * 旧调用方(缺省)皮肤退回 pose.mood 分层,属皮肤接口「未支持即
30
31
  * 退化」契约。 */
31
32
  readonly animationSemantic?: string;
33
+ /** 启动页专属紧凑图片槽;侧栏不传,保持原来的固定几何。 */
34
+ readonly imageBox?: SplashImageBox;
32
35
  }
33
36
  export interface CompanionSkin {
34
37
  readonly id: string;
@@ -86,6 +89,11 @@ interface WhaleGirlImageAnimation {
86
89
  interface WhaleGirlImageKit {
87
90
  /** img/ 目录的绝对路径(帧 PNG 解码用)。 */
88
91
  readonly dir: string;
92
+ /** idle 首帧 PNG 头部声明的稳定画布,不等待像素解码。 */
93
+ readonly canvas?: {
94
+ readonly width: number;
95
+ readonly height: number;
96
+ };
89
97
  readonly byKey: Readonly<Record<string, WhaleGirlImageAnimation>>;
90
98
  }
91
99
  /** 惰性加载 + 缓存图像 timings;缺失/校验失败返回 undefined(退字母格)。 */
@@ -1 +1 @@
1
- {"version":3,"file":"skins.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/companion/skins.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,MAAM,OAAO,CAAA;AAMzB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAA;AAYzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAA;AAE9C,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB;;;;;iBAKa;IACb,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAA;IACnD;;;;kBAIc;IACd,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACvD,MAAM,CAAC,KAAK,EAAE,wBAAwB,GAAG,KAAK,CAAC,SAAS,CAAA;CACzD;AAED,wDAAwD;AACxD,eAAO,MAAM,SAAS,EAAE,aA0BvB,CAAA;AAWD;;2BAE2B;AAC3B,wBAAgB,wBAAwB,CACtC,IAAI,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzD,UAAU,EAAE,MAAM,GACjB,MAAM,CAGR;AASD;;;;oCAIoC;AACpC,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI1E,CAAA;AAED;mDACmD;AACnD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGhF;AAgBD;;;;0BAI0B;AAC1B,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,aAAa,EACnB,iBAAiB,EAAE,MAAM,GAAG,SAAS,EACrC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAC/B,MAAM,GAAG,SAAS,CAWpB;AAsDD,eAAO,MAAM,aAAa,EAAE,aAe3B,CAAA;AAyBD,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,UAAU,uBAAuB;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,oBAAoB,EAAE,CAAA;IAChD,wBAAwB;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,UAAU,iBAAiB;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAA;CAClE;AA4BD,qDAAqD;AACrD,wBAAgB,qBAAqB,IAAI,iBAAiB,GAAG,SAAS,CAiBrE;AAED;2CAC2C;AAC3C,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CASxG;AAoBD,uDAAuD;AACvD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAG3E;AAwDD;;eAEe;AACf,eAAO,MAAM,uBAAuB,EAAE,SAAS,MAAM,EAKpD,CAAA;AA8CD,mCAAmC;AACnC,wBAAgB,6BAA6B,IAAI,SAAS,MAAM,EAAE,CAEjE;AAED,6BAA6B;AAC7B,wBAAgB,kCAAkC,IAAI,SAAS,MAAM,EAAE,CAEtE;AAED,wCAAwC;AACxC,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,mBAAmB,EAAE,GAAG,IAAI,CAExG;AAED,qBAAqB;AACrB,wBAAgB,mCAAmC,IAAI,MAAM,CAE5D;AAED,oCAAoC;AACpC,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE/D;AAED,wDAAwD;AACxD,wBAAgB,gCAAgC,IAAI,IAAI,CAUvD;AA8BD;;;;qBAIqB;AACrB,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,GAAG,EAAE,iBAAiB,GAAG,SAAS,GACjC,SAAS,mBAAmB,EAAE,GAAG,SAAS,CAwB5C;AAWD;;;;;iCAKiC;AACjC,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,KAAK,CAAC,SAAS,GACzB,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,aAAa,EAAE,OAAO,CAAC,CAW/D;AAyED;8BAC8B;AAC9B,eAAO,MAAM,SAAS,EAAE,aAQvB,CAAA;AAQD,sCAAsC;AACtC,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAM1E;AAED;8BAC8B;AAC9B,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAE/D"}
1
+ {"version":3,"file":"skins.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/companion/skins.tsx"],"names":[],"mappings":"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"}