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

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 (308) hide show
  1. package/README.md +98 -8
  2. package/guide/dsh-tui-guide/claude-backend.en.md +8 -0
  3. package/guide/dsh-tui-guide/claude-backend.md +5 -0
  4. package/guide/dsh-tui-guide/codex-backend.en.md +13 -3
  5. package/guide/dsh-tui-guide/codex-backend.md +9 -2
  6. package/guide/dsh-tui-guide/configuration.en.md +39 -2
  7. package/guide/dsh-tui-guide/configuration.md +34 -2
  8. package/guide/dsh-tui-guide/getting-started.en.md +32 -9
  9. package/guide/dsh-tui-guide/getting-started.md +27 -8
  10. package/guide/dsh-tui-guide/interaction.en.md +8 -1
  11. package/guide/dsh-tui-guide/interaction.md +8 -1
  12. package/guide/dsh-tui-guide/plugins.en.md +66 -5
  13. package/guide/dsh-tui-guide/plugins.md +37 -3
  14. package/guide/dsh-tui-guide/user-guide.en.md +3 -2
  15. package/guide/dsh-tui-guide/user-guide.md +3 -2
  16. package/lib/settings.json +1 -1
  17. package/lib/types/adapter/channel/projection.d.ts.map +1 -1
  18. package/lib/types/adapter/channel/projection.js +1 -0
  19. package/lib/types/adapter/channel/ui-policy.d.ts +1 -1
  20. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  21. package/lib/types/adapter/channel/ui-policy.js +1 -0
  22. package/lib/types/adapter/ports/channel-catalog.d.ts +5 -1
  23. package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
  24. package/lib/types/adapter/ports/channel-settings.d.ts +5 -3
  25. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  26. package/lib/types/adapter/ports/channel-ui.d.ts +7 -1
  27. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  28. package/lib/types/adapter/ports/channel-view.d.ts +47 -0
  29. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  30. package/lib/types/adapter/ports/channel.d.ts +2 -0
  31. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  32. package/lib/types/agent/events.d.ts +3 -2
  33. package/lib/types/agent/events.d.ts.map +1 -1
  34. package/lib/types/backends/codex/contract.d.ts +3 -0
  35. package/lib/types/backends/codex/contract.d.ts.map +1 -1
  36. package/lib/types/backends/codex/contract.js +3 -0
  37. package/lib/types/backends/codex/session/async-questions.d.ts +17 -0
  38. package/lib/types/backends/codex/session/async-questions.d.ts.map +1 -0
  39. package/lib/types/backends/codex/session/async-questions.js +89 -0
  40. package/lib/types/backends/codex/session/session.d.ts.map +1 -1
  41. package/lib/types/backends/codex/session/session.js +35 -9
  42. package/lib/types/backends/codex/text.d.ts +3 -3
  43. package/lib/types/backends/codex/text.js +1 -1
  44. package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
  45. package/lib/types/backends/codex/translate/items.js +3 -1
  46. package/lib/types/backends/codex/translate/question-reply.d.ts +11 -0
  47. package/lib/types/backends/codex/translate/question-reply.d.ts.map +1 -0
  48. package/lib/types/backends/codex/translate/question-reply.js +53 -0
  49. package/lib/types/channel/projection.d.ts.map +1 -1
  50. package/lib/types/channel/projection.js +10 -0
  51. package/lib/types/commands.d.ts +10 -0
  52. package/lib/types/commands.d.ts.map +1 -1
  53. package/lib/types/commands.js +11 -2
  54. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  55. package/lib/types/components/CommandSuggestions.js +4 -1
  56. package/lib/types/components/LogoV2.d.ts +4 -1
  57. package/lib/types/components/LogoV2.d.ts.map +1 -1
  58. package/lib/types/components/LogoV2.js +5 -3
  59. package/lib/types/components/MessageList.d.ts.map +1 -1
  60. package/lib/types/components/MessageList.js +95 -14
  61. package/lib/types/components/PermissionsPicker.d.ts +10 -1
  62. package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
  63. package/lib/types/components/PermissionsPicker.js +24 -16
  64. package/lib/types/components/PluginInstallPane.d.ts +21 -0
  65. package/lib/types/components/PluginInstallPane.d.ts.map +1 -0
  66. package/lib/types/components/PluginInstallPane.js +84 -0
  67. package/lib/types/components/PluginManagePane.d.ts +21 -0
  68. package/lib/types/components/PluginManagePane.d.ts.map +1 -0
  69. package/lib/types/components/PluginManagePane.js +69 -0
  70. package/lib/types/components/PromptInput.d.ts.map +1 -1
  71. package/lib/types/components/PromptInput.js +7 -3
  72. package/lib/types/components/SubagentCard.d.ts +13 -1
  73. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  74. package/lib/types/components/SubagentCard.js +27 -12
  75. package/lib/types/components/SubagentDashboard.d.ts +8 -1
  76. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  77. package/lib/types/components/SubagentDashboard.js +58 -16
  78. package/lib/types/components/launchpadLayout.d.ts +14 -1
  79. package/lib/types/components/launchpadLayout.d.ts.map +1 -1
  80. package/lib/types/components/launchpadLayout.js +36 -17
  81. package/lib/types/components/messages/TeamMessageBubble.d.ts +20 -0
  82. package/lib/types/components/messages/TeamMessageBubble.d.ts.map +1 -0
  83. package/lib/types/components/messages/TeamMessageBubble.js +15 -0
  84. package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -1
  85. package/lib/types/components/sidePanel/PanelHost.js +5 -1
  86. package/lib/types/components/sidePanel/PanelStore.d.ts +8 -0
  87. package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
  88. package/lib/types/components/sidePanel/PanelStore.js +11 -0
  89. package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
  90. package/lib/types/components/sidePanel/SidePanelColumn.js +13 -1
  91. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +7 -0
  92. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -1
  93. package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +4 -0
  94. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +3 -0
  95. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
  96. package/lib/types/components/sidePanel/btw/BtwComposer.js +20 -8
  97. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +2 -1
  98. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -1
  99. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +104 -13
  100. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +6 -2
  101. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -1
  102. package/lib/types/components/sidePanel/btw/BtwThreadScene.js +61 -15
  103. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +14 -4
  104. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
  105. package/lib/types/components/sidePanel/btw/BtwThreadView.js +90 -5
  106. package/lib/types/components/sidePanel/btw/threads.d.ts +18 -0
  107. package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -1
  108. package/lib/types/components/sidePanel/btw/threads.js +51 -0
  109. package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
  110. package/lib/types/components/sidePanel/builtinPanels.js +5 -1
  111. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +5 -1
  112. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -1
  113. package/lib/types/components/sidePanel/companion/SplashMascot.js +19 -4
  114. package/lib/types/components/sidePanel/companion/skins.d.ts +8 -0
  115. package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
  116. package/lib/types/components/sidePanel/companion/skins.js +57 -12
  117. package/lib/types/components/sidePanel/types.d.ts +6 -0
  118. package/lib/types/components/sidePanel/types.d.ts.map +1 -1
  119. package/lib/types/components/splashArtRows.d.ts +29 -0
  120. package/lib/types/components/splashArtRows.d.ts.map +1 -0
  121. package/lib/types/components/splashArtRows.js +31 -0
  122. package/lib/types/components/teamRoster.d.ts +70 -0
  123. package/lib/types/components/teamRoster.d.ts.map +1 -0
  124. package/lib/types/components/teamRoster.js +78 -0
  125. package/lib/types/dsh-adapter/admission-loader.d.ts +82 -0
  126. package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -1
  127. package/lib/types/dsh-adapter/admission-loader.js +73 -28
  128. package/lib/types/dsh-adapter/agent-view.d.ts.map +1 -1
  129. package/lib/types/dsh-adapter/agent-view.js +3 -1
  130. package/lib/types/dsh-adapter/approvals.d.ts +7 -0
  131. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/approvals.js +45 -1
  133. package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -1
  134. package/lib/types/dsh-adapter/backend/translate.js +68 -8
  135. package/lib/types/dsh-adapter/backend-assembly.d.ts +31 -0
  136. package/lib/types/dsh-adapter/backend-assembly.d.ts.map +1 -0
  137. package/lib/types/dsh-adapter/backend-assembly.js +225 -0
  138. package/lib/types/dsh-adapter/backend-contribution.d.ts +36 -0
  139. package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/backend-contribution.js +41 -0
  141. package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -1
  142. package/lib/types/dsh-adapter/backend-registry.js +22 -3
  143. package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
  144. package/lib/types/dsh-adapter/backends.js +4 -5
  145. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  146. package/lib/types/dsh-adapter/bundled-presets.js +60 -3
  147. package/lib/types/dsh-adapter/channel/binding-events.d.ts +1 -0
  148. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  149. package/lib/types/dsh-adapter/channel/binding-events.js +1 -0
  150. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  151. package/lib/types/dsh-adapter/channel/command-completions.js +64 -7
  152. package/lib/types/dsh-adapter/channel/compaction.d.ts +7 -2
  153. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  154. package/lib/types/dsh-adapter/channel/compaction.js +100 -26
  155. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +3 -0
  156. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
  157. package/lib/types/dsh-adapter/channel/core/binding-feed.js +2 -1
  158. package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/core/compose.js +12 -0
  160. package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
  161. package/lib/types/dsh-adapter/channel/extensions.js +68 -8
  162. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +6 -0
  163. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  164. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +104 -12
  165. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  166. package/lib/types/dsh-adapter/channel/model-actions.js +8 -1
  167. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  168. package/lib/types/dsh-adapter/channel/permissions.js +4 -1
  169. package/lib/types/dsh-adapter/channel/projection-helpers.d.ts.map +1 -1
  170. package/lib/types/dsh-adapter/channel/projection-helpers.js +2 -0
  171. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  172. package/lib/types/dsh-adapter/channel/session-metadata.js +4 -3
  173. package/lib/types/dsh-adapter/channel/session-reset.js +2 -2
  174. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  175. package/lib/types/dsh-adapter/channel/session-resume.js +7 -0
  176. package/lib/types/dsh-adapter/channel/settings-host.d.ts +3 -0
  177. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  178. package/lib/types/dsh-adapter/channel/settings-host.js +135 -5
  179. package/lib/types/dsh-adapter/channel/state.d.ts +6 -0
  180. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  181. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  182. package/lib/types/dsh-adapter/channel/subagent-projection.js +18 -6
  183. package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -0
  184. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  185. package/lib/types/dsh-adapter/channel/transcript.js +19 -2
  186. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts +55 -0
  187. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts.map +1 -0
  188. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.js +96 -0
  189. package/lib/types/dsh-adapter/contract.d.ts +4 -4
  190. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  191. package/lib/types/dsh-adapter/contract.js +5 -5
  192. package/lib/types/dsh-adapter/effect-ledger.d.ts +7 -0
  193. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  194. package/lib/types/dsh-adapter/effect-ledger.js +8 -1
  195. package/lib/types/dsh-adapter/entry-slot.d.ts +3 -1
  196. package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -1
  197. package/lib/types/dsh-adapter/entry-slot.js +2 -2
  198. package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -1
  199. package/lib/types/dsh-adapter/fresh-agent.js +6 -1
  200. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
  201. package/lib/types/dsh-adapter/host-access.js +99 -0
  202. package/lib/types/dsh-adapter/host-contract.d.ts +1 -1
  203. package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -1
  204. package/lib/types/dsh-adapter/host-contract.js +4 -3
  205. package/lib/types/dsh-adapter/host-dsh.d.ts +8 -2
  206. package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -1
  207. package/lib/types/dsh-adapter/host-dsh.js +45 -30
  208. package/lib/types/dsh-adapter/host-entry.js +40 -13
  209. package/lib/types/dsh-adapter/index.d.ts +9 -10
  210. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  211. package/lib/types/dsh-adapter/index.js +8 -6
  212. package/lib/types/dsh-adapter/install/pnpm-profile-add.d.ts.map +1 -1
  213. package/lib/types/dsh-adapter/install/pnpm-profile-add.js +9 -3
  214. package/lib/types/dsh-adapter/invariant.d.ts +7 -2
  215. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -1
  216. package/lib/types/dsh-adapter/invariant.js +6 -3
  217. package/lib/types/dsh-adapter/migrate/index.js +2 -2
  218. package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
  219. package/lib/types/dsh-adapter/panels.js +6 -0
  220. package/lib/types/dsh-adapter/plugin-declaration.d.ts +99 -1
  221. package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -1
  222. package/lib/types/dsh-adapter/plugin-declaration.js +132 -2
  223. package/lib/types/dsh-adapter/plugin-feed.d.ts +94 -0
  224. package/lib/types/dsh-adapter/plugin-feed.d.ts.map +1 -0
  225. package/lib/types/dsh-adapter/plugin-feed.js +135 -0
  226. package/lib/types/dsh-adapter/plugin-guard.d.ts +115 -0
  227. package/lib/types/dsh-adapter/plugin-guard.d.ts.map +1 -0
  228. package/lib/types/dsh-adapter/plugin-guard.js +108 -0
  229. package/lib/types/dsh-adapter/plugin-install.d.ts +160 -0
  230. package/lib/types/dsh-adapter/plugin-install.d.ts.map +1 -0
  231. package/lib/types/dsh-adapter/plugin-install.js +545 -0
  232. package/lib/types/dsh-adapter/plugin-manage.d.ts +178 -0
  233. package/lib/types/dsh-adapter/plugin-manage.d.ts.map +1 -0
  234. package/lib/types/dsh-adapter/plugin-manage.js +468 -0
  235. package/lib/types/dsh-adapter/plugin-manager.d.ts +78 -2
  236. package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -1
  237. package/lib/types/dsh-adapter/plugin-manager.js +32 -0
  238. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  239. package/lib/types/dsh-adapter/plugin.js +49 -2
  240. package/lib/types/dsh-adapter/plugins-info.d.ts +87 -1
  241. package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
  242. package/lib/types/dsh-adapter/plugins-info.js +131 -26
  243. package/lib/types/dsh-adapter/process-exit.d.ts +1 -1
  244. package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -1
  245. package/lib/types/dsh-adapter/process-exit.js +1 -1
  246. package/lib/types/dsh-adapter/session-projection-store.d.ts +66 -0
  247. package/lib/types/dsh-adapter/session-projection-store.d.ts.map +1 -0
  248. package/lib/types/dsh-adapter/session-projection-store.js +149 -0
  249. package/lib/types/dsh-adapter/settingsEditor.js +2 -2
  250. package/lib/types/dsh-adapter/sideQuestion.d.ts +21 -0
  251. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  252. package/lib/types/dsh-adapter/sideQuestion.js +53 -0
  253. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  254. package/lib/types/dsh-adapter/subagents.js +2 -1
  255. package/lib/types/dsh-adapter/team-mode.d.ts +74 -0
  256. package/lib/types/dsh-adapter/team-mode.d.ts.map +1 -0
  257. package/lib/types/dsh-adapter/team-mode.js +188 -0
  258. package/lib/types/dsh-adapter/team-roster.d.ts +67 -0
  259. package/lib/types/dsh-adapter/team-roster.d.ts.map +1 -0
  260. package/lib/types/dsh-adapter/team-roster.js +136 -0
  261. package/lib/types/dsh-adapter/team-tools.d.ts +58 -0
  262. package/lib/types/dsh-adapter/team-tools.d.ts.map +1 -0
  263. package/lib/types/dsh-adapter/team-tools.js +208 -0
  264. package/lib/types/dsh-adapter/types.d.ts +1 -1
  265. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  266. package/lib/types/i18n.d.ts +607 -16
  267. package/lib/types/i18n.d.ts.map +1 -1
  268. package/lib/types/i18n.js +295 -9
  269. package/lib/types/ink/components/ScrollBox.d.ts +9 -0
  270. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  271. package/lib/types/ink/components/ScrollBox.js +23 -0
  272. package/lib/types/ink/dom.d.ts.map +1 -1
  273. package/lib/types/kernelPrefs.d.ts +1 -1
  274. package/lib/types/kernelPrefs.d.ts.map +1 -1
  275. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  276. package/lib/types/native-ts/yoga-layout/index.js +8 -1
  277. package/lib/types/permissionPresetLabels.d.ts +25 -0
  278. package/lib/types/permissionPresetLabels.d.ts.map +1 -0
  279. package/lib/types/permissionPresetLabels.js +33 -0
  280. package/lib/types/preset-patch.d.ts +22 -0
  281. package/lib/types/preset-patch.d.ts.map +1 -0
  282. package/lib/types/preset-patch.js +14 -0
  283. package/lib/types/screens/Chat.d.ts +33 -1
  284. package/lib/types/screens/Chat.d.ts.map +1 -1
  285. package/lib/types/screens/Chat.js +301 -9
  286. package/lib/types/screens/Launchpad.d.ts +7 -1
  287. package/lib/types/screens/Launchpad.d.ts.map +1 -1
  288. package/lib/types/screens/Launchpad.js +19 -4
  289. package/lib/types/screens/Settings.d.ts.map +1 -1
  290. package/lib/types/screens/Settings.js +1 -0
  291. package/lib/types/screens/chat/usePluginWriteFlow.d.ts +68 -0
  292. package/lib/types/screens/chat/usePluginWriteFlow.d.ts.map +1 -0
  293. package/lib/types/screens/chat/usePluginWriteFlow.js +92 -0
  294. package/lib/types/screens/chatOverlay.d.ts +19 -1
  295. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  296. package/lib/types/sessionModes.d.ts +5 -3
  297. package/lib/types/sessionModes.d.ts.map +1 -1
  298. package/lib/types/sessionModes.js +9 -3
  299. package/lib/types/tips.js +2 -2
  300. package/lib/types/update.d.ts +31 -22
  301. package/lib/types/update.d.ts.map +1 -1
  302. package/lib/types/update.js +85 -42
  303. package/lib/types/utils/paths.d.ts +11 -0
  304. package/lib/types/utils/paths.d.ts.map +1 -1
  305. package/lib/types/utils/paths.js +13 -0
  306. package/package.json +126 -120
  307. package/tui-profile/feed/README.md +63 -0
  308. package/tui-profile/feed/first-party.json +10 -0
@@ -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":"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"}
1
+ {"version":3,"file":"skins.d.ts","sourceRoot":"","sources":["../../../../../src/components/sidePanel/companion/skins.tsx"],"names":[],"mappings":"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"}
@@ -16,7 +16,7 @@ import { existsSync, readFileSync } from 'node:fs';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { join } from 'node:path';
18
18
  import { Box, Text, Image, useTerminalImages, useTerminalImageProtocol, useTerminalImageCellSize } from '../../../ui.js';
19
- import { WhaleArt, renderSpriteRows } from '../../Whale.js';
19
+ import { WhaleArt, renderSpriteRows, renderCellRows } from '../../Whale.js';
20
20
  import { loadSharp } from '../../../dsh-adapter/sharp.js';
21
21
  import { DEEPY_CELLS, DEEPY_MOOD_ANIMATION, DEEPY_SEMANTIC_ANIMATION, frameAt, loadDeepyKit, loadWhaleGirlKit, renderedDeepyAnimation, } from './deepy.js';
22
22
  /** deepy 小鲸鱼(默认):语义/心情 → 动画,elapsed → frameAt 确定性选帧。 */
@@ -122,14 +122,31 @@ export function resolveWhaleGirlAnimationKey(pose, animationSemantic, hasKey) {
122
122
  * 回归锁「全部帧内容 ⊆ [5, 5+31)」防素材更新后悄悄越窗被截。 */
123
123
  const WHALE_GIRL_LETTER_WINDOW_START = 5;
124
124
  const whaleGirlWindowCache = new Map();
125
- function renderedWhaleGirlWindowRows(kit, key) {
125
+ function renderedWhaleGirlWindowRows(kit, key, imageBox) {
126
126
  const animation = kit.byKey[key];
127
127
  if (animation === undefined)
128
128
  return undefined;
129
- const cacheKey = kit.id + ':window:' + key;
129
+ const cacheKey = kit.id + ':window:' + key + (imageBox === undefined ? '' : `:${imageBox.columns}x${imageBox.rows}`);
130
130
  let rendered = whaleGirlWindowCache.get(cacheKey);
131
131
  if (rendered === undefined) {
132
- rendered = Object.freeze(animation.frames.map(frame => renderSpriteRows(frame.rows.map(row => row.slice(WHALE_GIRL_LETTER_WINDOW_START, WHALE_GIRL_LETTER_WINDOW_START + WHALE_GIRL_CELLS.columns)), kit.palette)));
132
+ rendered = Object.freeze(animation.frames.map(frame => {
133
+ if (imageBox === undefined)
134
+ return renderSpriteRows(frame.rows.map(row => row.slice(WHALE_GIRL_LETTER_WINDOW_START, WHALE_GIRL_LETTER_WINDOW_START + WHALE_GIRL_CELLS.columns)), kit.palette);
135
+ // 解码前/失败时整幅字母格 contain 进同一个槽,不裁掉头脚,也不换画跳高。
136
+ const pixelRows = imageBox.rows * 2;
137
+ const scale = Math.min(imageBox.columns / WHALE_GIRL_CELLS.columns, pixelRows / kit.rows);
138
+ const width = Math.max(1, Math.floor(WHALE_GIRL_CELLS.columns * scale));
139
+ const height = Math.max(1, Math.floor(kit.rows * scale));
140
+ const left = Math.floor((imageBox.columns - width) / 2);
141
+ const top = Math.floor((pixelRows - height) / 2);
142
+ return renderCellRows(imageBox.columns, pixelRows, (x, y) => {
143
+ if (x < left || x >= left + width || y < top || y >= top + height)
144
+ return undefined;
145
+ const sx = Math.min(WHALE_GIRL_CELLS.columns - 1, Math.floor((x - left) * WHALE_GIRL_CELLS.columns / width));
146
+ const sy = Math.min(kit.rows - 1, Math.floor((y - top) * kit.rows / height));
147
+ return kit.palette[frame.rows[sy]?.[sx + WHALE_GIRL_LETTER_WINDOW_START] ?? '.'];
148
+ });
149
+ }));
133
150
  whaleGirlWindowCache.set(cacheKey, rendered);
134
151
  }
135
152
  return rendered;
@@ -146,14 +163,14 @@ function renderWhaleGirlLetterGrid(input) {
146
163
  const animationKey = resolveWhaleGirlAnimationKey(pose, animationSemantic, key => kit.byKey[key] !== undefined);
147
164
  if (animationKey === undefined)
148
165
  return DeepySkin.render({ ...input, width: WHALE_GIRL_CELLS.columns });
149
- const rendered = renderedWhaleGirlWindowRows(kit, animationKey);
166
+ const rendered = renderedWhaleGirlWindowRows(kit, animationKey, input.imageBox);
150
167
  const animation = kit.byKey[animationKey];
151
168
  if (rendered === undefined || animation === undefined) {
152
169
  return DeepySkin.render({ ...input, width: WHALE_GIRL_CELLS.columns });
153
170
  }
154
171
  const frameIndex = frameAt(animation, now - moodSince);
155
172
  const rows = rendered[frameIndex] ?? rendered[0] ?? [];
156
- return (_jsx(Box, { flexDirection: "column", flexShrink: 0, width: WHALE_GIRL_CELLS.columns, children: rows.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, index))) }));
173
+ return (_jsx(Box, { flexDirection: "column", flexShrink: 0, width: input.imageBox?.columns ?? WHALE_GIRL_CELLS.columns, children: rows.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, index))) }));
157
174
  }
158
175
  export const WhaleGirlSkin = {
159
176
  id: 'whaleGirl',
@@ -210,8 +227,25 @@ export function loadWhaleGirlImageKit() {
210
227
  continue;
211
228
  const kit = parseWhaleGirlImageKit(JSON.parse(readFileSync(join(dir, 'timings.json'), 'utf8')), dir);
212
229
  if (kit !== undefined) {
213
- whaleGirlImageKitCache = kit;
214
- return kit;
230
+ const first = kit.byKey.idle?.frames[0];
231
+ let canvas;
232
+ if (first !== undefined) {
233
+ try {
234
+ const png = readFileSync(join(dir, 'idle', first.file));
235
+ if (png.length >= 24 && png.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))
236
+ && png.toString('ascii', 12, 16) === 'IHDR') {
237
+ const width = png.readUInt32BE(16);
238
+ const height = png.readUInt32BE(20);
239
+ if (width > 0 && height > 0 && width <= 4096 && height <= 4096)
240
+ canvas = { width, height };
241
+ }
242
+ }
243
+ catch {
244
+ // 缺失/坏帧仍走原来的异步解码失败与字母格回退。
245
+ }
246
+ }
247
+ whaleGirlImageKitCache = { ...kit, ...(canvas === undefined ? {} : { canvas }) };
248
+ return whaleGirlImageKitCache;
215
249
  }
216
250
  }
217
251
  catch {
@@ -537,17 +571,28 @@ function WhaleGirlRasterSkin(input) {
537
571
  const frameRatio = source.width / source.height;
538
572
  // 盒宽=图宽(钳在 cells.columns 内;超宽像元比下 contain 收行不裁剪)。
539
573
  const rawColumns = Math.max(1, Math.round(cellRatio * WHALE_GIRL_CELLS.rows * frameRatio));
540
- const columns = whaleGirlImageBoxColumns(cellSize, frameRatio);
541
- const rows = rawColumns > columns
574
+ const columns = input.imageBox?.columns ?? whaleGirlImageBoxColumns(cellSize, frameRatio);
575
+ const rows = input.imageBox?.rows ?? (rawColumns > columns
542
576
  ? Math.max(1, Math.round(columns / (cellRatio * frameRatio)))
543
- : WHALE_GIRL_CELLS.rows;
577
+ : WHALE_GIRL_CELLS.rows);
544
578
  image = (_jsx(Image, { transparent: true, source: source, width: columns, height: rows, alt: "", presentation: "transcript", children: _jsx(Text, { children: Array.from({ length: rows }, () => ' '.repeat(columns)).join('\n') }) }));
545
579
  }
546
580
  }
547
581
  // 本次候选或上一帧;都没有(冷启动)时画字母格。切到还没解码的键时
548
582
  // 保持上一帧,不闪回字母格。
549
583
  const [visibleImage] = useHeldCommittedImage(image);
550
- return (_jsx(Box, { ref: boxRef, flexDirection: "column", flexShrink: 0, alignItems: "center", justifyContent: "center", width: WHALE_GIRL_CELLS.columns, height: WHALE_GIRL_CELLS.rows, children: visibleImage !== undefined ? visibleImage : renderWhaleGirlLetterGrid(input) }));
584
+ let raster = visibleImage;
585
+ // 换键等待解码时保留旧像素,但 resize 后不能把旧的大 Image 盒塞进新小槽。
586
+ if (input.imageBox !== undefined && React.isValidElement(raster)
587
+ && (raster.props.width !== input.imageBox.columns || raster.props.height !== input.imageBox.rows)) {
588
+ const { columns, rows } = input.imageBox;
589
+ raster = React.cloneElement(raster, {
590
+ width: columns,
591
+ height: rows,
592
+ children: _jsx(Text, { children: Array.from({ length: rows }, () => ' '.repeat(columns)).join('\n') }),
593
+ });
594
+ }
595
+ return (_jsx(Box, { ref: boxRef, flexDirection: "column", flexShrink: 0, alignItems: "center", justifyContent: "center", width: input.imageBox?.columns ?? WHALE_GIRL_CELLS.columns, height: input.imageBox?.rows ?? WHALE_GIRL_CELLS.rows, children: raster !== undefined ? raster : renderWhaleGirlLetterGrid(input) }));
551
596
  }
552
597
  const WHALE_CELLS = Object.freeze({ columns: 40, rows: 13 });
553
598
  /** 现有像素鲸鱼:直接消费 nativeWhalePose(与开屏 splash 同一规划器、
@@ -74,6 +74,12 @@ export interface PanelEntry {
74
74
  /** 同 id 重注册时递增,用于重挂 error boundary。 */
75
75
  readonly registrationId: number;
76
76
  readonly badge: PanelBadge | null;
77
+ /**
78
+ * 面板自己广告的键位片段(底栏用)。`''` = 面板明确「此刻没有要广告的键」
79
+ * (底栏连能力位那一段也不画);没设置过则由底栏按 capabilities 兜底。
80
+ * 层内状态(编辑层 vs 列表层)只有面板自己知道,所以由面板发、宿主只拼。
81
+ */
82
+ readonly hint?: string;
77
83
  readonly lastError: {
78
84
  readonly message: string;
79
85
  readonly at: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/sidePanel/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { Brand } from '../branding.js';
2
+ /** 启动页立绘槽的占行:鲸鱼自然高度、portrait 的 minimal 等高盒、吉祥物的侧栏默认盒。 */
3
+ export declare const WHALE_ART_ROWS = 13;
4
+ export declare const PORTRAIT_ART_ROWS = 11;
5
+ export declare const MASCOT_ART_ROWS = 15;
6
+ export type SplashArtForm = 'whale' | 'portrait' | 'mascot';
7
+ export interface SplashImageBox {
8
+ readonly columns: number;
9
+ readonly rows: number;
10
+ }
11
+ /** 与 LogoV2 的默认品牌及 mascot → portrait → whale 分支一致。 */
12
+ export declare function resolveSplashArtForm(input: {
13
+ readonly brand: Brand | undefined;
14
+ readonly whaleGirl: boolean;
15
+ readonly mascotSkin: string | undefined;
16
+ }): SplashArtForm;
17
+ export declare function splashArtRows(form: SplashArtForm, imageBox?: SplashImageBox): number;
18
+ /**
19
+ * 启动页图片按原生画布占位:只缩小、不预留放大后用不上的空间。
20
+ * 同一个稳定画布用于全部动画帧;不按 alpha 包围盒逐帧裁剪。
21
+ */
22
+ export declare function fitSplashImageBox(source: {
23
+ readonly width: number;
24
+ readonly height: number;
25
+ }, cell: {
26
+ readonly width: number;
27
+ readonly height: number;
28
+ }, limit: SplashImageBox): SplashImageBox;
29
+ //# sourceMappingURL=splashArtRows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"splashArtRows.d.ts","sourceRoot":"","sources":["../../../src/components/splashArtRows.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAE3C,yDAAyD;AACzD,eAAO,MAAM,cAAc,KAAK,CAAA;AAChC,eAAO,MAAM,iBAAiB,KAAK,CAAA;AACnC,eAAO,MAAM,eAAe,KAAK,CAAA;AAEjC,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,UAAU,GAAG,QAAQ,CAAA;AAC3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,sDAAsD;AACtD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CACxC,GAAG,aAAa,CAKhB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,MAAM,CAIpF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC3D,IAAI,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzD,KAAK,EAAE,cAAc,GACpB,cAAc,CAMhB"}
@@ -0,0 +1,31 @@
1
+ /** 启动页立绘槽的占行:鲸鱼自然高度、portrait 的 minimal 等高盒、吉祥物的侧栏默认盒。 */
2
+ export const WHALE_ART_ROWS = 13;
3
+ export const PORTRAIT_ART_ROWS = 11;
4
+ export const MASCOT_ART_ROWS = 15;
5
+ /** 与 LogoV2 的默认品牌及 mascot → portrait → whale 分支一致。 */
6
+ export function resolveSplashArtForm(input) {
7
+ const brand = input.brand ?? 'deepseek';
8
+ if (brand === 'deepseek' && (input.mascotSkin === 'deepy' || input.mascotSkin === 'whaleGirl'))
9
+ return 'mascot';
10
+ if (input.whaleGirl || brand !== 'deepseek')
11
+ return 'portrait';
12
+ return 'whale';
13
+ }
14
+ export function splashArtRows(form, imageBox) {
15
+ if (form === 'whale')
16
+ return WHALE_ART_ROWS;
17
+ if (form === 'portrait')
18
+ return PORTRAIT_ART_ROWS;
19
+ return imageBox?.rows ?? MASCOT_ART_ROWS;
20
+ }
21
+ /**
22
+ * 启动页图片按原生画布占位:只缩小、不预留放大后用不上的空间。
23
+ * 同一个稳定画布用于全部动画帧;不按 alpha 包围盒逐帧裁剪。
24
+ */
25
+ export function fitSplashImageBox(source, cell, limit) {
26
+ const scale = Math.min(1, limit.columns * cell.width / source.width, limit.rows * cell.height / source.height);
27
+ return {
28
+ columns: Math.max(1, Math.min(limit.columns, Math.ceil(source.width * scale / cell.width))),
29
+ rows: Math.max(1, Math.min(limit.rows, Math.ceil(source.height * scale / cell.height))),
30
+ };
31
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Agent Teams in the agents surfaces (issue #1241, phase 2): fold the
3
+ * session's `TeamView` and its subagent rows into what the dashboard
4
+ * renders. A teammate is a continuable subagent of the Lead whose row id is
5
+ * the member id, so the two join by id; neither side overwrites the other's
6
+ * state (see `teamMemberStatus`). Pure: no I/O, no backend import.
7
+ */
8
+ import type { TeamMember, TeamTask, TeamView } from '../adapter/ports/channel-view.js';
9
+ import type { SubagentState } from '../dsh-adapter/subagents.js';
10
+ /** A member's state as shown: durable `phase` first, then the run. `active`
11
+ * is an active member whose run this session cannot see (a teammate's own
12
+ * subagent rows never hold its siblings). */
13
+ export type TeamMemberStatus = 'provisioning' | 'running' | 'idle' | 'active' | 'failed';
14
+ /** One teammate, with its subagent row once the host has announced it. */
15
+ export interface TeamMemberRow {
16
+ readonly member: TeamMember;
17
+ readonly subagent?: SubagentState;
18
+ readonly status: TeamMemberStatus;
19
+ }
20
+ export interface TeamDashboardModel {
21
+ readonly lead?: TeamMember;
22
+ /** Whether the session on screen is the Lead (its subagent rows are the teammates). */
23
+ readonly viewedFromLead: boolean;
24
+ readonly teammates: readonly TeamMemberRow[];
25
+ /** Subagent rows that are not team members (workflow / ralph spawns). */
26
+ readonly others: readonly SubagentState[];
27
+ }
28
+ /**
29
+ * A member's shown state. A failed `phase` is durable and wins; provisioning
30
+ * has no run yet. An active member is running only while its row runs: a
31
+ * finished turn leaves the member alive and waiting (a message wakes it),
32
+ * so a completed — or failed, or absent — run reads as idle, never done.
33
+ * @param member - Roster row.
34
+ * @param subagent - The member's subagent row, if any.
35
+ * @param runKnown - Whether the subagent rows are the Lead's (default).
36
+ * @returns the state to render.
37
+ */
38
+ export declare function teamMemberStatus(member: TeamMember, subagent: SubagentState | undefined, runKnown?: boolean): TeamMemberStatus;
39
+ /**
40
+ * Join the roster with the subagent rows.
41
+ * @param team - The session's team.
42
+ * @param subagents - The session's subagent rows.
43
+ * @param sessionId - The session on screen; inside a teammate its rows are
44
+ * its own children, never joined with the roster.
45
+ * @returns the Lead, teammates in roster order, and the remaining rows.
46
+ */
47
+ export declare function teamDashboardModel(team: TeamView, subagents: readonly SubagentState[], sessionId?: string): TeamDashboardModel;
48
+ /**
49
+ * Teammates on the roster: those known to be running or provisioning, and
50
+ * those that may be running. Inside a teammate a sibling's run is not
51
+ * visible, so an active sibling is `unseen`; the teammate on screen itself
52
+ * counts in neither.
53
+ * @param team - The session's team.
54
+ * @param subagents - The session's subagent rows.
55
+ * @param sessionId - The session on screen.
56
+ * @returns the three counts.
57
+ */
58
+ export declare function teamMemberCounts(team: TeamView, subagents: readonly SubagentState[], sessionId?: string): {
59
+ readonly total: number;
60
+ readonly active: number;
61
+ readonly unseen: number;
62
+ };
63
+ /** Completed / total of the task board. */
64
+ export declare function teamTaskProgress(tasks: readonly TeamTask[]): {
65
+ readonly completed: number;
66
+ readonly total: number;
67
+ };
68
+ /** A pending task some blocker still holds back. */
69
+ export declare function isTeamTaskBlocked(task: TeamTask): boolean;
70
+ //# sourceMappingURL=teamRoster.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teamRoster.d.ts","sourceRoot":"","sources":["../../../src/components/teamRoster.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAA;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAEhE;;8CAE8C;AAC9C,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAExF,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,aAAa,CAAA;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;CAClC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAA;IAC1B,uFAAuF;IACvF,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAA;IAC5C,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,CAAA;CAC1C;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,GAAG,SAAS,EAAE,QAAQ,UAAO,GAAG,gBAAgB,CAK3H;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,aAAa,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAmB9H;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,aAAa,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAQtL;AAED,2CAA2C;AAC3C,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAEnH;AAED,oDAAoD;AACpD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEzD"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * A member's shown state. A failed `phase` is durable and wins; provisioning
3
+ * has no run yet. An active member is running only while its row runs: a
4
+ * finished turn leaves the member alive and waiting (a message wakes it),
5
+ * so a completed — or failed, or absent — run reads as idle, never done.
6
+ * @param member - Roster row.
7
+ * @param subagent - The member's subagent row, if any.
8
+ * @param runKnown - Whether the subagent rows are the Lead's (default).
9
+ * @returns the state to render.
10
+ */
11
+ export function teamMemberStatus(member, subagent, runKnown = true) {
12
+ if (member.phase === 'failed')
13
+ return 'failed';
14
+ if (member.phase === 'provisioning')
15
+ return 'provisioning';
16
+ if (!runKnown)
17
+ return 'active';
18
+ return subagent?.status === 'running' || subagent?.status === 'starting' ? 'running' : 'idle';
19
+ }
20
+ /**
21
+ * Join the roster with the subagent rows.
22
+ * @param team - The session's team.
23
+ * @param subagents - The session's subagent rows.
24
+ * @param sessionId - The session on screen; inside a teammate its rows are
25
+ * its own children, never joined with the roster.
26
+ * @returns the Lead, teammates in roster order, and the remaining rows.
27
+ */
28
+ export function teamDashboardModel(team, subagents, sessionId) {
29
+ const viewedFromLead = sessionId === undefined || sessionId === team.leadSessionId;
30
+ const byId = new Map();
31
+ if (viewedFromLead)
32
+ for (const row of subagents)
33
+ byId.set(row.agentId, row);
34
+ const teammates = [];
35
+ const memberIds = new Set();
36
+ for (const member of team.members) {
37
+ if (member.role !== 'teammate')
38
+ continue;
39
+ const subagent = byId.get(member.id);
40
+ if (subagent !== undefined)
41
+ memberIds.add(member.id);
42
+ teammates.push({ member, status: teamMemberStatus(member, subagent, viewedFromLead), ...subagent === undefined ? {} : { subagent } });
43
+ }
44
+ const lead = team.members.find(member => member.role === 'lead');
45
+ return {
46
+ ...lead === undefined ? {} : { lead },
47
+ viewedFromLead,
48
+ teammates,
49
+ others: subagents.filter(row => !memberIds.has(row.agentId)),
50
+ };
51
+ }
52
+ /**
53
+ * Teammates on the roster: those known to be running or provisioning, and
54
+ * those that may be running. Inside a teammate a sibling's run is not
55
+ * visible, so an active sibling is `unseen`; the teammate on screen itself
56
+ * counts in neither.
57
+ * @param team - The session's team.
58
+ * @param subagents - The session's subagent rows.
59
+ * @param sessionId - The session on screen.
60
+ * @returns the three counts.
61
+ */
62
+ export function teamMemberCounts(team, subagents, sessionId) {
63
+ const { teammates } = teamDashboardModel(team, subagents, sessionId);
64
+ const counted = teammates.filter(row => row.member.id !== sessionId);
65
+ return {
66
+ total: teammates.length,
67
+ active: counted.filter(row => row.status === 'running' || row.status === 'provisioning').length,
68
+ unseen: counted.filter(row => row.status === 'active').length,
69
+ };
70
+ }
71
+ /** Completed / total of the task board. */
72
+ export function teamTaskProgress(tasks) {
73
+ return { completed: tasks.filter(task => task.status === 'completed').length, total: tasks.length };
74
+ }
75
+ /** A pending task some blocker still holds back. */
76
+ export function isTeamTaskBlocked(task) {
77
+ return task.status === 'pending' && !task.ready;
78
+ }