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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/README.md +92 -5
  2. package/guide/dsh-tui-guide/codex-backend.en.md +13 -3
  3. package/guide/dsh-tui-guide/codex-backend.md +9 -2
  4. package/guide/dsh-tui-guide/configuration.en.md +39 -2
  5. package/guide/dsh-tui-guide/configuration.md +34 -2
  6. package/guide/dsh-tui-guide/getting-started.en.md +15 -0
  7. package/guide/dsh-tui-guide/getting-started.md +15 -0
  8. package/guide/dsh-tui-guide/interaction.en.md +8 -1
  9. package/guide/dsh-tui-guide/interaction.md +8 -1
  10. package/guide/dsh-tui-guide/plugins.en.md +66 -5
  11. package/guide/dsh-tui-guide/plugins.md +37 -3
  12. package/guide/dsh-tui-guide/user-guide.en.md +3 -2
  13. package/guide/dsh-tui-guide/user-guide.md +3 -2
  14. package/lib/settings.json +1 -1
  15. package/lib/types/adapter/channel/projection.d.ts.map +1 -1
  16. package/lib/types/adapter/channel/projection.js +1 -0
  17. package/lib/types/adapter/channel/ui-policy.d.ts +1 -1
  18. package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
  19. package/lib/types/adapter/channel/ui-policy.js +1 -0
  20. package/lib/types/adapter/ports/channel-catalog.d.ts +5 -1
  21. package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
  22. package/lib/types/adapter/ports/channel-settings.d.ts +5 -3
  23. package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
  24. package/lib/types/adapter/ports/channel-ui.d.ts +7 -1
  25. package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
  26. package/lib/types/adapter/ports/channel-view.d.ts +47 -0
  27. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  28. package/lib/types/adapter/ports/channel.d.ts +2 -0
  29. package/lib/types/adapter/ports/channel.d.ts.map +1 -1
  30. package/lib/types/agent/events.d.ts +3 -2
  31. package/lib/types/agent/events.d.ts.map +1 -1
  32. package/lib/types/backends/codex/contract.d.ts +3 -0
  33. package/lib/types/backends/codex/contract.d.ts.map +1 -1
  34. package/lib/types/backends/codex/contract.js +3 -0
  35. package/lib/types/backends/codex/session/async-questions.d.ts +17 -0
  36. package/lib/types/backends/codex/session/async-questions.d.ts.map +1 -0
  37. package/lib/types/backends/codex/session/async-questions.js +89 -0
  38. package/lib/types/backends/codex/session/session.d.ts.map +1 -1
  39. package/lib/types/backends/codex/session/session.js +35 -9
  40. package/lib/types/backends/codex/text.d.ts +3 -3
  41. package/lib/types/backends/codex/text.js +1 -1
  42. package/lib/types/backends/codex/translate/items.d.ts.map +1 -1
  43. package/lib/types/backends/codex/translate/items.js +3 -1
  44. package/lib/types/backends/codex/translate/question-reply.d.ts +11 -0
  45. package/lib/types/backends/codex/translate/question-reply.d.ts.map +1 -0
  46. package/lib/types/backends/codex/translate/question-reply.js +53 -0
  47. package/lib/types/channel/projection.d.ts.map +1 -1
  48. package/lib/types/channel/projection.js +10 -0
  49. package/lib/types/commands.d.ts +10 -0
  50. package/lib/types/commands.d.ts.map +1 -1
  51. package/lib/types/commands.js +11 -2
  52. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  53. package/lib/types/components/CommandSuggestions.js +4 -1
  54. package/lib/types/components/LogoV2.d.ts +4 -1
  55. package/lib/types/components/LogoV2.d.ts.map +1 -1
  56. package/lib/types/components/LogoV2.js +5 -3
  57. package/lib/types/components/MessageList.d.ts.map +1 -1
  58. package/lib/types/components/MessageList.js +95 -14
  59. package/lib/types/components/PermissionsPicker.d.ts +10 -1
  60. package/lib/types/components/PermissionsPicker.d.ts.map +1 -1
  61. package/lib/types/components/PermissionsPicker.js +24 -16
  62. package/lib/types/components/PluginInstallPane.d.ts +21 -0
  63. package/lib/types/components/PluginInstallPane.d.ts.map +1 -0
  64. package/lib/types/components/PluginInstallPane.js +84 -0
  65. package/lib/types/components/PluginManagePane.d.ts +21 -0
  66. package/lib/types/components/PluginManagePane.d.ts.map +1 -0
  67. package/lib/types/components/PluginManagePane.js +69 -0
  68. package/lib/types/components/PromptInput.d.ts.map +1 -1
  69. package/lib/types/components/PromptInput.js +7 -3
  70. package/lib/types/components/SubagentCard.d.ts +13 -1
  71. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  72. package/lib/types/components/SubagentCard.js +27 -12
  73. package/lib/types/components/SubagentDashboard.d.ts +8 -1
  74. package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
  75. package/lib/types/components/SubagentDashboard.js +58 -16
  76. package/lib/types/components/launchpadLayout.d.ts +14 -1
  77. package/lib/types/components/launchpadLayout.d.ts.map +1 -1
  78. package/lib/types/components/launchpadLayout.js +36 -17
  79. package/lib/types/components/messages/TeamMessageBubble.d.ts +20 -0
  80. package/lib/types/components/messages/TeamMessageBubble.d.ts.map +1 -0
  81. package/lib/types/components/messages/TeamMessageBubble.js +15 -0
  82. package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -1
  83. package/lib/types/components/sidePanel/PanelHost.js +5 -1
  84. package/lib/types/components/sidePanel/PanelStore.d.ts +8 -0
  85. package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -1
  86. package/lib/types/components/sidePanel/PanelStore.js +11 -0
  87. package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -1
  88. package/lib/types/components/sidePanel/SidePanelColumn.js +13 -1
  89. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +7 -0
  90. package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -1
  91. package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +4 -0
  92. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +3 -0
  93. package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -1
  94. package/lib/types/components/sidePanel/btw/BtwComposer.js +20 -8
  95. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +2 -1
  96. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -1
  97. package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +104 -13
  98. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +6 -2
  99. package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -1
  100. package/lib/types/components/sidePanel/btw/BtwThreadScene.js +61 -15
  101. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +14 -4
  102. package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -1
  103. package/lib/types/components/sidePanel/btw/BtwThreadView.js +90 -5
  104. package/lib/types/components/sidePanel/btw/threads.d.ts +18 -0
  105. package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -1
  106. package/lib/types/components/sidePanel/btw/threads.js +51 -0
  107. package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -1
  108. package/lib/types/components/sidePanel/builtinPanels.js +5 -1
  109. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +5 -1
  110. package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -1
  111. package/lib/types/components/sidePanel/companion/SplashMascot.js +19 -4
  112. package/lib/types/components/sidePanel/companion/skins.d.ts +8 -0
  113. package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -1
  114. package/lib/types/components/sidePanel/companion/skins.js +57 -12
  115. package/lib/types/components/sidePanel/types.d.ts +6 -0
  116. package/lib/types/components/sidePanel/types.d.ts.map +1 -1
  117. package/lib/types/components/splashArtRows.d.ts +29 -0
  118. package/lib/types/components/splashArtRows.d.ts.map +1 -0
  119. package/lib/types/components/splashArtRows.js +31 -0
  120. package/lib/types/components/teamRoster.d.ts +70 -0
  121. package/lib/types/components/teamRoster.d.ts.map +1 -0
  122. package/lib/types/components/teamRoster.js +78 -0
  123. package/lib/types/dsh-adapter/admission-loader.d.ts +82 -0
  124. package/lib/types/dsh-adapter/admission-loader.d.ts.map +1 -1
  125. package/lib/types/dsh-adapter/admission-loader.js +73 -28
  126. package/lib/types/dsh-adapter/agent-view.d.ts.map +1 -1
  127. package/lib/types/dsh-adapter/agent-view.js +3 -1
  128. package/lib/types/dsh-adapter/approvals.d.ts +7 -0
  129. package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
  130. package/lib/types/dsh-adapter/approvals.js +45 -1
  131. package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -1
  132. package/lib/types/dsh-adapter/backend/translate.js +68 -8
  133. package/lib/types/dsh-adapter/backend-assembly.d.ts +31 -0
  134. package/lib/types/dsh-adapter/backend-assembly.d.ts.map +1 -0
  135. package/lib/types/dsh-adapter/backend-assembly.js +225 -0
  136. package/lib/types/dsh-adapter/backend-contribution.d.ts +36 -0
  137. package/lib/types/dsh-adapter/backend-contribution.d.ts.map +1 -1
  138. package/lib/types/dsh-adapter/backend-contribution.js +41 -0
  139. package/lib/types/dsh-adapter/backend-registry.d.ts.map +1 -1
  140. package/lib/types/dsh-adapter/backend-registry.js +22 -3
  141. package/lib/types/dsh-adapter/backends.d.ts.map +1 -1
  142. package/lib/types/dsh-adapter/backends.js +4 -5
  143. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  144. package/lib/types/dsh-adapter/bundled-presets.js +60 -3
  145. package/lib/types/dsh-adapter/channel/binding-events.d.ts +1 -0
  146. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  147. package/lib/types/dsh-adapter/channel/binding-events.js +1 -0
  148. package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
  149. package/lib/types/dsh-adapter/channel/command-completions.js +64 -7
  150. package/lib/types/dsh-adapter/channel/compaction.d.ts +7 -2
  151. package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
  152. package/lib/types/dsh-adapter/channel/compaction.js +100 -26
  153. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +3 -0
  154. package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -1
  155. package/lib/types/dsh-adapter/channel/core/binding-feed.js +2 -1
  156. package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -1
  157. package/lib/types/dsh-adapter/channel/core/compose.js +12 -0
  158. package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -1
  159. package/lib/types/dsh-adapter/channel/extensions.js +68 -8
  160. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +6 -0
  161. package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
  162. package/lib/types/dsh-adapter/channel/mode-permission-actions.js +104 -12
  163. package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
  164. package/lib/types/dsh-adapter/channel/model-actions.js +8 -1
  165. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  166. package/lib/types/dsh-adapter/channel/permissions.js +4 -1
  167. package/lib/types/dsh-adapter/channel/projection-helpers.d.ts.map +1 -1
  168. package/lib/types/dsh-adapter/channel/projection-helpers.js +2 -0
  169. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  170. package/lib/types/dsh-adapter/channel/session-metadata.js +4 -3
  171. package/lib/types/dsh-adapter/channel/session-reset.js +2 -2
  172. package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
  173. package/lib/types/dsh-adapter/channel/session-resume.js +7 -0
  174. package/lib/types/dsh-adapter/channel/settings-host.d.ts +3 -0
  175. package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
  176. package/lib/types/dsh-adapter/channel/settings-host.js +135 -5
  177. package/lib/types/dsh-adapter/channel/state.d.ts +6 -0
  178. package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
  179. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  180. package/lib/types/dsh-adapter/channel/subagent-projection.js +18 -6
  181. package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -0
  182. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  183. package/lib/types/dsh-adapter/channel/transcript.js +19 -2
  184. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts +55 -0
  185. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.d.ts.map +1 -0
  186. package/lib/types/dsh-adapter/compat/agent-team-0.2.0.js +96 -0
  187. package/lib/types/dsh-adapter/contract.d.ts +4 -4
  188. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  189. package/lib/types/dsh-adapter/contract.js +5 -5
  190. package/lib/types/dsh-adapter/effect-ledger.d.ts +7 -0
  191. package/lib/types/dsh-adapter/effect-ledger.d.ts.map +1 -1
  192. package/lib/types/dsh-adapter/effect-ledger.js +8 -1
  193. package/lib/types/dsh-adapter/entry-slot.d.ts +3 -1
  194. package/lib/types/dsh-adapter/entry-slot.d.ts.map +1 -1
  195. package/lib/types/dsh-adapter/entry-slot.js +2 -2
  196. package/lib/types/dsh-adapter/fresh-agent.d.ts.map +1 -1
  197. package/lib/types/dsh-adapter/fresh-agent.js +6 -1
  198. package/lib/types/dsh-adapter/host-access.d.ts.map +1 -1
  199. package/lib/types/dsh-adapter/host-access.js +95 -0
  200. package/lib/types/dsh-adapter/host-contract.d.ts +1 -1
  201. package/lib/types/dsh-adapter/host-contract.d.ts.map +1 -1
  202. package/lib/types/dsh-adapter/host-contract.js +3 -2
  203. package/lib/types/dsh-adapter/host-dsh.d.ts +8 -2
  204. package/lib/types/dsh-adapter/host-dsh.d.ts.map +1 -1
  205. package/lib/types/dsh-adapter/host-dsh.js +45 -30
  206. package/lib/types/dsh-adapter/host-entry.js +35 -10
  207. package/lib/types/dsh-adapter/index.d.ts +9 -10
  208. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  209. package/lib/types/dsh-adapter/index.js +8 -6
  210. package/lib/types/dsh-adapter/invariant.d.ts +7 -2
  211. package/lib/types/dsh-adapter/invariant.d.ts.map +1 -1
  212. package/lib/types/dsh-adapter/invariant.js +6 -3
  213. package/lib/types/dsh-adapter/migrate/index.js +2 -2
  214. package/lib/types/dsh-adapter/panels.d.ts.map +1 -1
  215. package/lib/types/dsh-adapter/panels.js +6 -0
  216. package/lib/types/dsh-adapter/plugin-declaration.d.ts +99 -1
  217. package/lib/types/dsh-adapter/plugin-declaration.d.ts.map +1 -1
  218. package/lib/types/dsh-adapter/plugin-declaration.js +132 -2
  219. package/lib/types/dsh-adapter/plugin-feed.d.ts +94 -0
  220. package/lib/types/dsh-adapter/plugin-feed.d.ts.map +1 -0
  221. package/lib/types/dsh-adapter/plugin-feed.js +135 -0
  222. package/lib/types/dsh-adapter/plugin-guard.d.ts +115 -0
  223. package/lib/types/dsh-adapter/plugin-guard.d.ts.map +1 -0
  224. package/lib/types/dsh-adapter/plugin-guard.js +108 -0
  225. package/lib/types/dsh-adapter/plugin-install.d.ts +160 -0
  226. package/lib/types/dsh-adapter/plugin-install.d.ts.map +1 -0
  227. package/lib/types/dsh-adapter/plugin-install.js +545 -0
  228. package/lib/types/dsh-adapter/plugin-manage.d.ts +178 -0
  229. package/lib/types/dsh-adapter/plugin-manage.d.ts.map +1 -0
  230. package/lib/types/dsh-adapter/plugin-manage.js +468 -0
  231. package/lib/types/dsh-adapter/plugin-manager.d.ts +78 -2
  232. package/lib/types/dsh-adapter/plugin-manager.d.ts.map +1 -1
  233. package/lib/types/dsh-adapter/plugin-manager.js +32 -0
  234. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  235. package/lib/types/dsh-adapter/plugin.js +49 -2
  236. package/lib/types/dsh-adapter/plugins-info.d.ts +87 -1
  237. package/lib/types/dsh-adapter/plugins-info.d.ts.map +1 -1
  238. package/lib/types/dsh-adapter/plugins-info.js +131 -26
  239. package/lib/types/dsh-adapter/process-exit.d.ts +1 -1
  240. package/lib/types/dsh-adapter/process-exit.d.ts.map +1 -1
  241. package/lib/types/dsh-adapter/process-exit.js +1 -1
  242. package/lib/types/dsh-adapter/session-projection-store.d.ts +66 -0
  243. package/lib/types/dsh-adapter/session-projection-store.d.ts.map +1 -0
  244. package/lib/types/dsh-adapter/session-projection-store.js +149 -0
  245. package/lib/types/dsh-adapter/settingsEditor.js +2 -2
  246. package/lib/types/dsh-adapter/sideQuestion.d.ts +21 -0
  247. package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
  248. package/lib/types/dsh-adapter/sideQuestion.js +53 -0
  249. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  250. package/lib/types/dsh-adapter/subagents.js +2 -1
  251. package/lib/types/dsh-adapter/team-mode.d.ts +74 -0
  252. package/lib/types/dsh-adapter/team-mode.d.ts.map +1 -0
  253. package/lib/types/dsh-adapter/team-mode.js +188 -0
  254. package/lib/types/dsh-adapter/team-roster.d.ts +67 -0
  255. package/lib/types/dsh-adapter/team-roster.d.ts.map +1 -0
  256. package/lib/types/dsh-adapter/team-roster.js +136 -0
  257. package/lib/types/dsh-adapter/team-tools.d.ts +58 -0
  258. package/lib/types/dsh-adapter/team-tools.d.ts.map +1 -0
  259. package/lib/types/dsh-adapter/team-tools.js +208 -0
  260. package/lib/types/dsh-adapter/types.d.ts +1 -1
  261. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  262. package/lib/types/i18n.d.ts +607 -16
  263. package/lib/types/i18n.d.ts.map +1 -1
  264. package/lib/types/i18n.js +295 -9
  265. package/lib/types/ink/components/ScrollBox.d.ts +9 -0
  266. package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
  267. package/lib/types/ink/components/ScrollBox.js +23 -0
  268. package/lib/types/ink/dom.d.ts.map +1 -1
  269. package/lib/types/kernelPrefs.d.ts +1 -1
  270. package/lib/types/kernelPrefs.d.ts.map +1 -1
  271. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  272. package/lib/types/native-ts/yoga-layout/index.js +8 -1
  273. package/lib/types/permissionPresetLabels.d.ts +25 -0
  274. package/lib/types/permissionPresetLabels.d.ts.map +1 -0
  275. package/lib/types/permissionPresetLabels.js +33 -0
  276. package/lib/types/preset-patch.d.ts +22 -0
  277. package/lib/types/preset-patch.d.ts.map +1 -0
  278. package/lib/types/preset-patch.js +14 -0
  279. package/lib/types/screens/Chat.d.ts +33 -1
  280. package/lib/types/screens/Chat.d.ts.map +1 -1
  281. package/lib/types/screens/Chat.js +301 -9
  282. package/lib/types/screens/Launchpad.d.ts +7 -1
  283. package/lib/types/screens/Launchpad.d.ts.map +1 -1
  284. package/lib/types/screens/Launchpad.js +19 -4
  285. package/lib/types/screens/Settings.d.ts.map +1 -1
  286. package/lib/types/screens/Settings.js +1 -0
  287. package/lib/types/screens/chat/usePluginWriteFlow.d.ts +68 -0
  288. package/lib/types/screens/chat/usePluginWriteFlow.d.ts.map +1 -0
  289. package/lib/types/screens/chat/usePluginWriteFlow.js +92 -0
  290. package/lib/types/screens/chatOverlay.d.ts +19 -1
  291. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  292. package/lib/types/sessionModes.d.ts +5 -3
  293. package/lib/types/sessionModes.d.ts.map +1 -1
  294. package/lib/types/sessionModes.js +9 -3
  295. package/lib/types/tips.js +2 -2
  296. package/lib/types/utils/paths.d.ts +11 -0
  297. package/lib/types/utils/paths.d.ts.map +1 -1
  298. package/lib/types/utils/paths.js +13 -0
  299. package/package.json +126 -120
  300. package/tui-profile/feed/README.md +63 -0
  301. package/tui-profile/feed/first-party.json +10 -0
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { t } from '../i18n.js';
3
+ import { Box, Text } from '../ui.js';
4
+ import { cleanRenderText, NOTICE_CELLS } from '../channel/sanitize.js';
5
+ import { HintLine } from './design-system/HintLine.js';
6
+ import { LoadingState } from './design-system/LoadingState.js';
7
+ import { Pane } from './design-system/Pane.js';
8
+ /** Foreign text on its way to the screen: control sequences stripped, bounded. */
9
+ const clean = (value) => cleanRenderText(value, NOTICE_CELLS);
10
+ /**
11
+ * The target's identity is the subject of the question, and it is foreign text
12
+ * like everything else here: a package name and a module specifier come from
13
+ * somebody else's manifest, so either can carry newlines or thousands of cells.
14
+ * Bounded to what a line can show — at 50 columns an unbounded name buries the
15
+ * title and the key hints, which are exactly what the person needs to answer.
16
+ */
17
+ const TARGET_CELLS = 80;
18
+ /**
19
+ * `/plugin remove | enable | disable`: the pane that asks what the flow cannot
20
+ * answer on its own (Stage C-5).
21
+ *
22
+ * The flow (`dsh-adapter/plugin-manage.ts`) writes every line of the action into
23
+ * the transcript — what it resolved, why it refused, what the service answered —
24
+ * so this pane only carries the one thing a person must decide before the write.
25
+ * Unlike the install pane there is no progress, no cancellation and no retry:
26
+ * each action is a single call that settles once.
27
+ *
28
+ * Presentational only, and the same three parts as its install sibling
29
+ * (`PluginInstallPane`): the pane, the facts that make the question answerable,
30
+ * and the key hints. Keys are handled in Chat (Enter answers, Esc closes).
31
+ */
32
+ export function PluginManagePane({ step, busy }) {
33
+ if (busy) {
34
+ // A write is in flight. Esc closes the pane and the write finishes anyway —
35
+ // the service has no cancellation for these three, and saying "cancelling"
36
+ // here would be a promise nobody can keep.
37
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-manage-pane-title') }), _jsx(Box, { marginTop: 1, children: _jsx(LoadingState, { message: t('plugins-manage-working') }) })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-manage-key-busy') }) })] }));
38
+ }
39
+ if (step.kind === 'confirm') {
40
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('plugins-manage-pane-title') }) }), _jsx(Text, { children: t('plugins-manage-configure', {
41
+ action: t(actionKeyOf(step.target)),
42
+ target: describe(step.target),
43
+ }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [step.question.kind === 'remove' && (_jsx(Text, { children: t('plugins-manage-remove-facts', {
44
+ rows: String(step.target.kind === 'bundle' ? step.target.rows : 0),
45
+ overrides: String(step.target.kind === 'bundle' ? step.target.overrides : 0),
46
+ }) })), step.question.kind === 'trust' && _jsx(Text, { children: t('plugins-manage-trust-facts') }), step.question.kind === 'host-row' && _jsx(Text, { children: t('plugins-manage-host-row-facts') }), step.question.kind === 'team-active' && (_jsxs(_Fragment, { children: [step.question.members > 0 && _jsx(Text, { children: t('plugins-manage-team-active-facts', { members: String(step.question.members) }) }), step.question.unseen > 0 && _jsx(Text, { children: t('plugins-manage-team-unseen-facts', { members: String(step.question.unseen) }) }), _jsx(Text, { children: t('plugins-manage-team-active-stop') })] }))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-manage-key-confirm') }) })] }));
47
+ }
48
+ // `done` never renders: its lines are already in the transcript, so Chat
49
+ // closes the pane instead of leaving an empty box behind.
50
+ return null;
51
+ }
52
+ /** Which verb the title asks about. */
53
+ function actionKeyOf(target) {
54
+ return target.action === 'remove'
55
+ ? 'plugins-manage-action-remove'
56
+ : target.action === 'enable' ? 'plugins-manage-action-enable' : 'plugins-manage-action-disable';
57
+ }
58
+ /**
59
+ * The target as one bounded cell. A bundle is named by its package name; a row
60
+ * by the module it loads, which is what the report listed it as and what a
61
+ * person typed to get here.
62
+ */
63
+ function describe(target) {
64
+ if (target.kind === 'bundle') {
65
+ const version = target.version === undefined ? '' : `@${target.version}`;
66
+ return cleanRenderText(`${target.name}${version}`, TARGET_CELLS);
67
+ }
68
+ return cleanRenderText(target.moduleName, TARGET_CELLS);
69
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AA8BzB,OAAO,KAAK,EAAE,SAAS,IAAI,OAAO,EAAE,MAAM,iCAAiC,CAAA;AAC3E,OAAO,KAAK,EACV,gBAAgB,EAGjB,MAAM,2BAA2B,CAAA;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AAa1E,OAAO,EAIL,KAAK,gBAAgB,EAEtB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAgLjF;gFACgF;AAChF,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GACzC,gBAAgB,EAAE,CAWpB;AAqLD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,IAAI,OAAO,CAAA;IAClB,yFAAyF;IACzF,IAAI,IAAI,MAAM,CAAA;IACd,4EAA4E;IAC5E,aAAa,CAAC,IAAI,SAAS;QAAE,KAAK,EAAE,eAAe,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACtE,KAAK,IAAI,IAAI,CAAA;IACb;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B;;;;;OAKG;IACH,oBAAoB,IAAI,OAAO,CAAA;IAC/B,yEAAyE;IACzE,aAAa,IAAI,OAAO,CAAA;IACxB,2EAA2E;IAC3E,SAAS,IAAI,OAAO,CAAA;IACpB;yEACqE;IACrE,SAAS,IAAI,OAAO,CAAA;CAAC;AAEvB;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,KAAK,OAAO,CAAA;IACrE;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,0EAA0E;IAC1E,QAAQ,EAAE,OAAO,CAAA;IACjB,YAAY,IAAI,IAAI,CAAA;IACpB;;;OAGG;IACH,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,SAAS,gBAAgB,EAAE,GAClC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7B,6EAA6E;IAC7E,eAAe,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB,kEAAkE;IAClE,eAAe,CAAC,IAAI,IAAI,CAAA;IACxB;;;OAGG;IACH,mBAAmB,CAAC,IAAI,IAAI,CAAA;IAC5B;;;;;;;;OAQG;IACH,cAAc,CAAC,IAAI,IAAI,CAAA;IACvB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,4BAA4B,CAAC,EAAE,MAAM,CAAA;IACrC,0EAA0E;IAC1E,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;IACxD;;;;;;;OAOG;IACH,YAAY,CAAC,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAA;IAC7G;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,qBAAqB,CAAC,IAAI,IAAI,CAAA;IAC9B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,eAAe,EACf,SAAiB,EACjB,aAAoB,EACpB,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,4BAA4B,EAC5B,aAAa,EACb,YAAY,EACZ,gBAAwB,EACxB,qBAAqB,EACrB,GAAc,GACf,EAAE,gBAAgB,4BAi4HlB"}
@@ -954,6 +954,7 @@ export function PromptInput({ channel, toastSuppressed, suspended = false, curso
954
954
  // index space: `suggestions` stays the only list selection, Enter dispatch and
955
955
  // clicks read, and the default selection stays the first normal-region row.
956
956
  // The region is marked by colour only — it costs no display row.
957
+ const completionInput = value;
957
958
  const completions = value.startsWith('/') ? channel.commandCompletions(value) : [];
958
959
  const holdOf = (commandLine) => workingHoldOf(commandLine, channel.commandList.find(command => command.name === commandLine.replace(/^\//, '').split(/[\t ]/u)[0])?.skill === true) !== undefined;
959
960
  const normalCompletions = channel.working
@@ -1709,7 +1710,10 @@ export function PromptInput({ channel, toastSuppressed, suspended = false, curso
1709
1710
  editDocked(dockSelectedRef.current);
1710
1711
  return;
1711
1712
  }
1712
- if (overlayOpen) {
1713
+ // A preceding edit in this stdin batch has already updated valueRef, but
1714
+ // the completion rows still belong to the last render. Submit the current
1715
+ // draft through the ordinary path instead of accepting a stale row.
1716
+ if (overlayOpen && value === completionInput) {
1713
1717
  const command = suggestions[selectedCommand];
1714
1718
  if (command) {
1715
1719
  tryRunCommand(command.commandLine);
@@ -2427,7 +2431,7 @@ export function PromptInput({ channel, toastSuppressed, suspended = false, curso
2427
2431
  }
2428
2432
  if (key.tab && overlayOpen) {
2429
2433
  const command = suggestions[selectedCommand];
2430
- if (command) {
2434
+ if (command && value === completionInput) {
2431
2435
  updateFoldBlock(null);
2432
2436
  setInput(command.replacement, command.replacement.length, 'step');
2433
2437
  }
@@ -3809,7 +3813,7 @@ export function PromptInput({ channel, toastSuppressed, suspended = false, curso
3809
3813
  onPick: (index) => {
3810
3814
  const command = suggestions[index];
3811
3815
  if (command)
3812
- tryRunCommand(command.commandLine);
3816
+ tryRunCommand(valueRef.current === completionInput ? command.commandLine : valueRef.current);
3813
3817
  },
3814
3818
  // 滚轮 = 移动选中行(与 ↑/↓ 同路径,窗口跟随)
3815
3819
  onWheelStep: (step) => {
@@ -1,11 +1,23 @@
1
1
  import React from 'react';
2
2
  import type { SubagentState } from '../dsh-adapter/subagents.js';
3
3
  import type { ClickEvent } from '../ink/events/click-event.js';
4
+ import type { TeamMemberStatus } from './teamRoster.js';
4
5
  export interface SubagentCardProps {
5
6
  subagent: SubagentState;
6
7
  focused?: boolean;
7
8
  onClick?(event: ClickEvent): void;
8
9
  variant?: 'default' | 'panel';
10
+ /** Agent Teams: the row is this teammate — its name replaces the
11
+ * description and its member state replaces the run status. */
12
+ teamMember?: {
13
+ readonly name: string;
14
+ readonly status: TeamMemberStatus;
15
+ };
9
16
  }
10
- export declare function SubagentCard({ subagent, focused, onClick, variant }: SubagentCardProps): React.ReactNode;
17
+ /** Status glyph and color of a team member (`·`-style in minimal UI). */
18
+ export declare function teamStatusGlyph(status: TeamMemberStatus, minimalUi: boolean): {
19
+ readonly glyph: string;
20
+ readonly color?: 'warning' | 'subtle' | 'error' | 'accent';
21
+ };
22
+ export declare function SubagentCard({ subagent, focused, onClick, variant, teamMember }: SubagentCardProps): React.ReactNode;
11
23
  //# sourceMappingURL=SubagentCard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAIhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAO9D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,CAAA;IACvB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACjC,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;CAC9B;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAmB,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CAiFpH"}
1
+ {"version":3,"file":"SubagentCard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAIhE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAOvD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,aAAa,CAAA;IACvB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAA;IACjC,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IAC7B;oEACgE;IAChE,UAAU,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;KAAE,CAAA;CAC1E;AAED,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAA;CAAE,CAQpK;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAmB,EAAE,UAAU,EAAE,EAAE,iBAAiB,GAAG,KAAK,CAAC,SAAS,CA2FhI"}
@@ -8,9 +8,21 @@ function formatDuration(ms) {
8
8
  const seconds = Math.floor(ms / 1000);
9
9
  return seconds < 60 ? `${seconds}s` : `${Math.floor(seconds / 60)}m${seconds % 60}s`;
10
10
  }
11
- export function SubagentCard({ subagent, focused, onClick, variant = 'default' }) {
11
+ /** Status glyph and color of a team member (`·`-style in minimal UI). */
12
+ export function teamStatusGlyph(status, minimalUi) {
13
+ switch (status) {
14
+ case 'running': return minimalUi ? { glyph: '·' } : { glyph: '🟡', color: 'warning' };
15
+ case 'idle': return minimalUi ? { glyph: '○' } : { glyph: '🔵', color: 'accent' };
16
+ case 'active': return minimalUi ? { glyph: '◇' } : { glyph: '🟣', color: 'accent' };
17
+ case 'provisioning': return minimalUi ? { glyph: '…' } : { glyph: '⚪', color: 'subtle' };
18
+ case 'failed': return minimalUi ? { glyph: '×' } : { glyph: '🔴', color: 'error' };
19
+ }
20
+ }
21
+ export function SubagentCard({ subagent, focused, onClick, variant = 'default', teamMember }) {
12
22
  const panelMode = variant === 'panel';
13
- const running = subagent.status === 'running' || subagent.status === 'starting';
23
+ const running = teamMember !== undefined
24
+ ? teamMember.status === 'running'
25
+ : subagent.status === 'running' || subagent.status === 'starting';
14
26
  const [clockRef] = useAnimationFrame(running ? 1000 : null);
15
27
  // Unknown rows have no completion time, so they do not get a fabricated duration.
16
28
  const elapsed = running
@@ -25,15 +37,18 @@ export function SubagentCard({ subagent, focused, onClick, variant = 'default' }
25
37
  const [hovered, setHovered] = useState(false);
26
38
  const liveLine = running ? subagent.output[subagent.output.length - 1] : undefined;
27
39
  const minimalUi = isMinimalUiMode();
28
- const glyph = running ? (minimalUi ? '·' : '🟡')
29
- : subagent.status === 'unknown' ? (minimalUi ? '·' : '⚪')
30
- : subagent.status === 'failed' || subagent.status === 'cancelled' ? (minimalUi ? '×' : '🔴')
31
- : (minimalUi ? '✓' : '🟢');
32
- const glyphColor = minimalUi ? undefined
33
- : running ? 'warning'
34
- : subagent.status === 'unknown' ? 'subtle'
35
- : subagent.status === 'failed' || subagent.status === 'cancelled' ? 'error'
36
- : 'success';
40
+ const teamGlyph = teamMember === undefined ? undefined : teamStatusGlyph(teamMember.status, minimalUi);
41
+ const glyph = teamGlyph !== undefined ? teamGlyph.glyph
42
+ : running ? (minimalUi ? '·' : '🟡')
43
+ : subagent.status === 'unknown' ? (minimalUi ? '·' : '⚪')
44
+ : subagent.status === 'failed' || subagent.status === 'cancelled' ? (minimalUi ? '×' : '🔴')
45
+ : (minimalUi ? '✓' : '🟢');
46
+ const glyphColor = teamGlyph !== undefined ? teamGlyph.color
47
+ : minimalUi ? undefined
48
+ : running ? 'warning'
49
+ : subagent.status === 'unknown' ? 'subtle'
50
+ : subagent.status === 'failed' || subagent.status === 'cancelled' ? 'error'
51
+ : 'success';
37
52
  const hoverTint = onClick !== undefined && hovered && !focused;
38
53
  // Keep the description on one row; narrower panels progressively drop metadata.
39
54
  const { columns } = useTerminalSize();
@@ -55,7 +70,7 @@ export function SubagentCard({ subagent, focused, onClick, variant = 'default' }
55
70
  subagent.effort,
56
71
  shownDuration === undefined ? undefined : formatDuration(shownDuration),
57
72
  ].filter(part => part !== undefined && part !== '').join(' · ');
58
- return _jsxs(Box, { ref: clockRef, flexDirection: "column", paddingLeft: 1, marginBottom: panelMode ? 0 : 1, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hoverTint ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexShrink: 0, marginRight: 1, children: _jsx(Text, { color: glyphColor, children: glyph }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { bold: true, color: focused ? 'accent' : undefined, wrap: "truncate-end", children: panelMode ? subagent.description : `${t('subagent-card-prefix')}${subagent.description}` }) }), subagent.mode === 'continuable' && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: focused ? 'accent' : 'warning', children: t('subagent-mode-continuable') }) })), subagent.mode === 'one-shot' && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { dimColor: true, children: t('subagent-mode-one-shot') }) })), !panelMode && meta !== '' && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: meta }) }))] }), panelMode && panelMeta !== '' && _jsx(Box, { paddingLeft: 3, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: panelMeta }) }), panelMode
73
+ return _jsxs(Box, { ref: clockRef, flexDirection: "column", paddingLeft: 1, marginBottom: panelMode ? 0 : 1, onClick: onClick, onMouseEnter: onClick !== undefined ? () => setHovered(true) : undefined, onMouseLeave: onClick !== undefined ? () => setHovered(false) : undefined, backgroundColor: hoverTint ? 'userMessageBackgroundHover' : undefined, children: [_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { flexShrink: 0, marginRight: 1, children: _jsx(Text, { color: glyphColor, children: glyph }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { bold: true, color: focused ? 'accent' : undefined, wrap: "truncate-end", children: teamMember !== undefined ? teamMember.name : panelMode ? subagent.description : `${t('subagent-card-prefix')}${subagent.description}` }) }), teamMember !== undefined && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: focused ? 'accent' : teamGlyph?.color, dimColor: teamMember.status === 'provisioning', children: t(`team-status-${teamMember.status}`) }) })), teamMember === undefined && subagent.mode === 'continuable' && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: focused ? 'accent' : 'warning', children: t('subagent-mode-continuable') }) })), teamMember === undefined && subagent.mode === 'one-shot' && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { dimColor: true, children: t('subagent-mode-one-shot') }) })), !panelMode && meta !== '' && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { dimColor: true, wrap: "truncate-end", children: meta }) }))] }), panelMode && panelMeta !== '' && _jsx(Box, { paddingLeft: 3, children: _jsx(Text, { dimColor: true, wrap: "wrap", children: panelMeta }) }), panelMode
59
74
  ? previewRows.map(row => _jsx(Text, { dimColor: true, wrap: "truncate", children: ` ${row.text}` }, row.key))
60
75
  : liveLine !== undefined && _jsx(Text, { dimColor: true, wrap: "truncate", children: ` │ ${liveLine}` })] });
61
76
  }
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import type { SubagentState } from '../dsh-adapter/subagents.js';
3
3
  import type { SidePanelKeyFlags } from './sidePanel/types.js';
4
4
  import type { AgentMessageView, AgentIdentity } from './messages/agentTeam.js';
5
+ import type { TeamView } from '../adapter/ports/channel-view.js';
5
6
  export interface SubagentDashboardProps {
6
7
  subagents: readonly SubagentState[];
7
8
  /** Optional cross-session agents, kept separate from this session children. */
@@ -15,6 +16,12 @@ export interface SubagentDashboardProps {
15
16
  onOpenView?: (agentId: string) => void;
16
17
  /** 代理↔代理消息流:每张卡下显示最后一条 from → to 摘要。 */
17
18
  messages?: readonly AgentMessageView[];
19
+ /** Agent Teams: present → team mode (members joined with their subagent
20
+ * rows, a read-only task board, the failure banner). */
21
+ team?: TeamView;
22
+ /** The session on screen: inside a teammate the subagent rows are its own
23
+ * children, so the roster is not joined with them. */
24
+ sessionId?: string;
18
25
  /** `panel` 挂在侧栏宿主里(去外层 padding、键盘走 usePanelInput 分发器);
19
26
  * default(缺省)与整屏形态逐字节一致。 */
20
27
  variant?: 'default' | 'panel';
@@ -32,5 +39,5 @@ export declare function ExitButton({ onClick }: {
32
39
  * SubagentDashboard — overlay panel showing all active/recent subagents.
33
40
  * Keyboard: up/down to navigate, Enter to view detail, Esc to close.
34
41
  */
35
- export declare function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenView, messages, variant, focused, visible, }: SubagentDashboardProps): React.ReactNode;
42
+ export declare function SubagentDashboard({ subagents, team, sessionId, peers, onClose, onSelect, onOpenView, messages, variant, focused, visible, }: SubagentDashboardProps): React.ReactNode;
36
43
  //# sourceMappingURL=SubagentDashboard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SubagentDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentDashboard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAMhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAE9E,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAA;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,aAAa,EAAE,CAAA;IACzC;mDAC+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC;0BACsB;IACtB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;IACtC;iCAC6B;IAC7B,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IAC7B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAOjF;AAED,yCAAyC;AACzC,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAWhF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,KAAK,EACL,OAAO,EACP,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAmB,EACnB,OAAc,EACd,OAAc,GACf,EAAE,sBAAsB,GAAG,KAAK,CAAC,SAAS,CA+M1C"}
1
+ {"version":3,"file":"SubagentDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/SubagentDashboard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAMhE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAE7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC9E,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,kCAAkC,CAAA;AAI1E,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,SAAS,aAAa,EAAE,CAAA;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,aAAa,EAAE,CAAA;IACzC;mDAC+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC;0BACsB;IACtB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,wCAAwC;IACxC,QAAQ,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;IACtC;6DACyD;IACzD,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf;2DACuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;iCAC6B;IAC7B,OAAO,CAAC,EAAE,SAAS,GAAG,OAAO,CAAA;IAC7B,+CAA+C;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAOjF;AAED,yCAAyC;AACzC,wBAAgB,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAWhF;AAgED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAAS,EACT,IAAI,EACJ,SAAS,EACT,KAAK,EACL,OAAO,EACP,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAmB,EACnB,OAAc,EACd,OAAc,GACf,EAAE,sBAAsB,GAAG,KAAK,CAAC,SAAS,CAkS1C"}
@@ -1,12 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import { Box, Text, useInput, ScrollBox, useTerminalSize } from '../ui.js';
4
- import { SubagentCard } from './SubagentCard.js';
4
+ import { SubagentCard, teamStatusGlyph } from './SubagentCard.js';
5
5
  import { t } from '../i18n.js';
6
6
  import { Divider } from './design-system/Divider.js';
7
7
  import { isPlainReturnInput } from '../utils/modifiers.js';
8
8
  import { usePanelInput } from './sidePanel/usePanelInput.js';
9
9
  import { AgentMessagesSummary } from './messages/AgentMessageFlow.js';
10
+ import { isTeamTaskBlocked, teamDashboardModel, teamTaskProgress } from './teamRoster.js';
11
+ import { isMinimalUiMode } from '../minimalUiMode.js';
10
12
  /** Accept Ink's Enter flag and the panel dispatcher's normalized alias. */
11
13
  export function isPanelPlainReturn(input, key) {
12
14
  return isPlainReturnInput(input, {
@@ -21,13 +23,29 @@ export function ExitButton({ onClick }) {
21
23
  const [hovered, setHovered] = React.useState(false);
22
24
  return (_jsx(Box, { onClick: onClick, onMouseEnter: () => setHovered(true), onMouseLeave: () => setHovered(false), children: _jsx(Text, { color: hovered ? 'text' : 'subtle', children: ' ✕' }) }));
23
25
  }
26
+ /** A teammate the host has not announced as a subagent yet. */
27
+ function TeamRosterOnlyRow({ row, focused, panelMode, self }) {
28
+ const { glyph, color } = teamStatusGlyph(row.status, isMinimalUiMode());
29
+ return (_jsxs(Box, { flexDirection: "row", paddingLeft: 1, marginBottom: panelMode ? 0 : 1, children: [_jsx(Box, { flexShrink: 0, marginRight: 1, children: _jsx(Text, { color: color, children: glyph }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { bold: true, color: focused ? 'accent' : undefined, children: row.member.name }), self && _jsx(Text, { dimColor: true, children: ' · ' + t('team-self-mark') })] }) }), _jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: focused ? 'accent' : color, dimColor: row.status === 'provisioning', children: t(`team-status-${row.status}`) }) })] }));
30
+ }
31
+ const TASK_GLYPH = {
32
+ pending: { glyph: '○', color: 'subtle' },
33
+ in_progress: { glyph: '◐', color: 'accent' },
34
+ completed: { glyph: '●', color: 'success' },
35
+ };
36
+ /** The team's shared task board, read-only; narrow widths drop the owner. */
37
+ function TeamTaskBoard({ tasks }) {
38
+ const { columns } = useTerminalSize();
39
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, wrap: "truncate-end", children: t('team-tasks-title', teamTaskProgress(tasks)) }), tasks.length === 0 && _jsx(Text, { dimColor: true, children: ' ' + t('team-tasks-empty') }), tasks.map(task => (_jsxs(Box, { flexDirection: "row", paddingLeft: 1, children: [_jsx(Box, { flexShrink: 0, marginRight: 1, children: _jsx(Text, { color: TASK_GLYPH[task.status].color, children: TASK_GLYPH[task.status].glyph }) }), _jsx(Box, { flexGrow: 1, flexShrink: 1, overflow: "hidden", children: _jsx(Text, { dimColor: task.status === 'completed', wrap: "truncate-end", children: task.subject }) }), columns >= 40 && task.ownerName !== undefined && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { dimColor: true, children: '@' + task.ownerName }) })), isTeamTaskBlocked(task) && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: "warning", children: t('team-task-blocked') }) })), task.writeScopeWarnings.length > 0 && (_jsx(Box, { flexShrink: 0, marginLeft: 1, children: _jsx(Text, { color: "warning", children: '⚠' + task.writeScopeWarnings.length }) }))] }, task.id)))] }));
40
+ }
24
41
  /**
25
42
  * SubagentDashboard — overlay panel showing all active/recent subagents.
26
43
  * Keyboard: up/down to navigate, Enter to view detail, Esc to close.
27
44
  */
28
- export function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenView, messages, variant = 'default', focused = true, visible = true, }) {
45
+ export function SubagentDashboard({ subagents, team, sessionId, peers, onClose, onSelect, onOpenView, messages, variant = 'default', focused = true, visible = true, }) {
29
46
  const panelMode = variant === 'panel';
30
- const [focusIndex, setFocusIndex] = React.useState(0);
47
+ // Focus follows the row's key: team mode reorders the rows, and the roster can shrink.
48
+ const [focus, setFocus] = React.useState({ index: 0 });
31
49
  const scrollRef = React.useRef(null);
32
50
  const { rows, columns } = useTerminalSize();
33
51
  // Keep top-level children first when the roster includes nested agents.
@@ -35,6 +53,29 @@ export function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenV
35
53
  const nestedRows = subagents.filter(isNestedSpawn);
36
54
  const flatRows = subagents.filter(row => !isNestedSpawn(row));
37
55
  const ordered = nestedRows.length === 0 ? subagents : [...flatRows, ...nestedRows];
56
+ const model = team === undefined ? undefined : teamDashboardModel(team, subagents, sessionId);
57
+ const others = new Set(model?.others);
58
+ const nested = nestedRows.length;
59
+ const rowEntry = (subagent) => ({ key: subagent.agentId, subagent, nested: nested > 0 && isNestedSpawn(subagent) });
60
+ const entries = model === undefined
61
+ ? ordered.map(rowEntry)
62
+ : [
63
+ ...model.teammates.map(row => ({ key: row.member.id, teamRow: row, nested: false, ...row.subagent === undefined ? {} : { subagent: row.subagent } })),
64
+ ...ordered.filter(row => others.has(row)).map(rowEntry),
65
+ ];
66
+ const othersStart = model === undefined ? -1 : model.teammates.length;
67
+ const focusOf = (state) => {
68
+ const found = state.key === undefined ? -1 : entries.findIndex(entry => entry.key === state.key);
69
+ return found >= 0 ? found : Math.min(state.index, Math.max(0, entries.length - 1));
70
+ };
71
+ const focusIndex = focusOf(focus);
72
+ const moveFocus = (delta) => {
73
+ setFocus((prev) => {
74
+ const index = Math.max(0, Math.min(entries.length - 1, focusOf(prev) + delta));
75
+ const key = entries[index]?.key;
76
+ return key === undefined ? { index } : { index, key };
77
+ });
78
+ };
38
79
  useInput((input, key, event) => {
39
80
  if (panelMode)
40
81
  return;
@@ -45,19 +86,19 @@ export function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenV
45
86
  }
46
87
  if (key.upArrow) {
47
88
  event.stopImmediatePropagation();
48
- setFocusIndex(i => Math.max(0, i - 1));
89
+ moveFocus(-1);
49
90
  scrollRef.current?.scrollBy(-3);
50
91
  return;
51
92
  }
52
93
  if (key.downArrow) {
53
94
  event.stopImmediatePropagation();
54
- setFocusIndex(i => Math.min(ordered.length - 1, i + 1));
95
+ moveFocus(1);
55
96
  scrollRef.current?.scrollBy(3);
56
97
  return;
57
98
  }
58
99
  if (isPlainReturnInput(input, key) && onSelect) {
59
100
  event.stopImmediatePropagation();
60
- const selected = ordered[focusIndex];
101
+ const selected = entries[focusIndex]?.subagent;
61
102
  if (selected)
62
103
  onSelect(selected.agentId);
63
104
  return;
@@ -65,7 +106,7 @@ export function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenV
65
106
  // v = 主屏查看(Enter 仍是详情)。
66
107
  if (input.toLowerCase() === 'v' && onOpenView) {
67
108
  event.stopImmediatePropagation();
68
- const selected = ordered[focusIndex];
109
+ const selected = entries[focusIndex]?.subagent;
69
110
  if (selected)
70
111
  onOpenView(selected.agentId);
71
112
  return;
@@ -78,23 +119,23 @@ export function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenV
78
119
  if (key.escape === true || (key.ctrl === true && input === 'c'))
79
120
  return false;
80
121
  if (key.upArrow === true) {
81
- setFocusIndex(i => Math.max(0, i - 1));
122
+ moveFocus(-1);
82
123
  scrollRef.current?.scrollBy(-3);
83
124
  return true;
84
125
  }
85
126
  if (key.downArrow === true) {
86
- setFocusIndex(i => Math.min(ordered.length - 1, i + 1));
127
+ moveFocus(1);
87
128
  scrollRef.current?.scrollBy(3);
88
129
  return true;
89
130
  }
90
131
  if (isPanelPlainReturn(input, key)) {
91
- const selected = ordered[focusIndex];
132
+ const selected = entries[focusIndex]?.subagent;
92
133
  if (selected !== undefined)
93
134
  onSelect?.(selected.agentId);
94
135
  return true;
95
136
  }
96
137
  if (input.toLowerCase() === 'v' && onOpenView !== undefined) {
97
- const selected = ordered[focusIndex];
138
+ const selected = entries[focusIndex]?.subagent;
98
139
  if (selected !== undefined)
99
140
  onOpenView(selected.agentId);
100
141
  return true;
@@ -105,13 +146,14 @@ export function SubagentDashboard({ subagents, peers, onClose, onSelect, onOpenV
105
146
  const running = subagents.filter(s => s.status === 'running').length;
106
147
  const completed = subagents.filter(s => s.status === 'completed').length;
107
148
  const failed = subagents.filter(s => s.status === 'failed').length;
108
- const nested = nestedRows.length;
149
+ const memberCount = (status) => model?.teammates.filter(row => row.status === status).length ?? 0;
150
+ const teamSep = panelMode ? ' · ' : ' ';
109
151
  // Full-screen keeps its inset; the panel uses one cell on each side.
110
152
  const outer = panelMode
111
153
  ? { paddingLeft: 1, paddingRight: 1, paddingTop: 0 }
112
154
  : { paddingX: 2, paddingY: 1 };
113
- return (_jsxs(Box, { flexDirection: "column", ...outer, children: [!panelMode && _jsx(Divider, { color: "accent", title: t('subagent-dashboard-title') }), _jsxs(Box, { flexDirection: "row", gap: 3, marginTop: panelMode ? 0 : 1, marginBottom: panelMode ? 0 : 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: "accent", children: running }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-running')] })] }), _jsxs(Text, { children: [_jsx(Text, { color: "success", children: completed }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-completed')] })] }), failed > 0 && (_jsxs(Text, { children: [_jsx(Text, { color: "error", children: failed }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-failed')] })] })), nested > 0 && (_jsxs(Text, { children: [_jsx(Text, { color: "accent", children: nested }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-nested')] })] })), _jsx(Box, { flexGrow: 1 }), !panelMode && onClose !== undefined && _jsx(ExitButton, { onClick: onClose })] }), _jsx(Box, { flexDirection: "column", maxHeight: panelMode ? Math.max(6, rows - 4) : Math.max(10, rows - 10), marginTop: panelMode ? 0 : 1, children: _jsx(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: subagents.length === 0 ? (_jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: Math.max(2, Math.floor((rows - 16) / 3)), children: [_jsx(Text, { dimColor: true, children: '○' }), _jsx(Text, { dimColor: true, children: t('subagent-none') }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('subagent-empty-hint') }) })] })) : (ordered.map((subagent, index) => (_jsxs(Box, { flexDirection: "column", children: [nested > 0 && isNestedSpawn(subagent) && (_jsx(Text, { dimColor: true, children: ' ↳ ' + t('subagent-nested-mark') })), _jsx(SubagentCard, { subagent: subagent, variant: panelMode ? 'panel' : 'default', focused: index === focusIndex, onClick: onSelect !== undefined
114
- // Click = view detail, same as Enter on the focused card.
115
- ? () => onSelect(subagent.agentId)
116
- : undefined }), messages !== undefined && messages.length > 0 && (_jsx(AgentMessagesSummary, { messages: messages.filter(message => message.from === subagent.agentId || message.to === subagent.agentId), selfAgentId: subagent.agentId })), onOpenView !== undefined && (!panelMode || index === focusIndex) && (_jsx(Box, { paddingLeft: 1, onClick: () => onOpenView(subagent.agentId), children: _jsx(Text, { color: "subtle", children: `⤢ ${t('agent-view-open-action')}` }) })), !panelMode && index < ordered.length - 1 && (_jsx(Text, { dimColor: true, children: '─'.repeat(Math.max(20, Math.min(72, columns - 6))) }))] }, subagent.agentId)))) }) }), peers !== undefined && (!panelMode || peers.length > 0) && (_jsx(Box, { flexDirection: "column", children: panelMode ? (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: t('agents-peers-title') + ' · ' + peers.length })) : (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: t('agents-peers-title') }), peers.length === 0 ? (_jsx(Text, { dimColor: true, children: ' ' + t('agents-peers-empty') })) : (_jsxs(Box, { flexDirection: "column", children: [peers.map(peer => (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: ' · ' + (peer.name ?? peer.label ?? peer.agentId.slice(0, 8)) + ' · ' + peer.agentId.slice(0, 8) }, peer.agentId))), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: ' ' + t('agents-peers-note') })] }))] })) })), !panelMode && (_jsxs(_Fragment, { children: [_jsx(Divider, { color: "subtle", title: "" }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: onSelect ? t('subagent-dashboard-hint-detail') : t('subagent-dashboard-hint-basic') }) })] }))] }));
155
+ return (_jsxs(Box, { flexDirection: "column", ...outer, children: [!panelMode && _jsx(Divider, { color: "accent", title: t(team === undefined ? 'subagent-dashboard-title' : 'team-dashboard-title') }), _jsxs(Box, { flexDirection: "row", gap: 3, marginTop: panelMode ? 0 : 1, marginBottom: panelMode ? 0 : 1, children: [team !== undefined ? (_jsx(Box, { flexShrink: 1, overflow: "hidden", children: _jsxs(Text, { wrap: "truncate-end", children: [_jsx(Text, { color: "accent", children: memberCount('running') }), _jsx(Text, { dimColor: true, children: ' ' + t('team-status-running') + teamSep }), _jsx(Text, { color: "accent", children: memberCount('idle') }), _jsx(Text, { dimColor: true, children: ' ' + t('team-status-idle') + teamSep }), memberCount('provisioning') > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: memberCount('provisioning') }), _jsx(Text, { dimColor: true, children: ' ' + t('team-status-provisioning') + teamSep })] })), memberCount('active') > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "accent", children: memberCount('active') }), _jsx(Text, { dimColor: true, children: ' ' + t('team-status-active') + teamSep })] })), memberCount('failed') > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { color: "error", children: memberCount('failed') }), _jsx(Text, { dimColor: true, children: ' ' + t('team-status-failed') + teamSep })] })), _jsx(Text, { dimColor: true, children: t('team-tasks-count', teamTaskProgress(team.tasks)) })] }) })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { children: [_jsx(Text, { color: "accent", children: running }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-running')] })] }), _jsxs(Text, { children: [_jsx(Text, { color: "success", children: completed }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-completed')] })] }), failed > 0 && (_jsxs(Text, { children: [_jsx(Text, { color: "error", children: failed }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-failed')] })] })), nested > 0 && (_jsxs(Text, { children: [_jsx(Text, { color: "accent", children: nested }), _jsxs(Text, { dimColor: true, children: [" ", t('subagent-count-nested')] })] }))] })), _jsx(Box, { flexGrow: 1 }), !panelMode && onClose !== undefined && _jsx(ExitButton, { onClick: onClose })] }), team?.failure !== undefined && (_jsx(Text, { color: "error", wrap: "wrap", children: '⚠ ' + t('team-failure', { failure: team.failure }) })), _jsx(Box, { flexDirection: "column", maxHeight: panelMode ? Math.max(6, rows - 4) : Math.max(10, rows - 10), marginTop: panelMode ? 0 : 1, children: _jsxs(ScrollBox, { ref: scrollRef, flexDirection: "column", flexGrow: 1, children: [model !== undefined && (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: t('team-members-title') }), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: ' ◆ ' + t(model.viewedFromLead ? 'team-lead-row' : 'team-lead-row-peer') })] })), model === undefined && subagents.length === 0 ? (_jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: Math.max(2, Math.floor((rows - 16) / 3)), children: [_jsx(Text, { dimColor: true, children: '○' }), _jsx(Text, { dimColor: true, children: t('subagent-none') }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: t('subagent-empty-hint') }) })] })) : (entries.map(({ key, subagent, teamRow, nested: nestedMark }, index) => (_jsxs(Box, { flexDirection: "column", children: [index === othersStart && _jsx(Text, { dimColor: true, children: t('team-others-title') }), nestedMark && (_jsx(Text, { dimColor: true, children: ' ↳ ' + t('subagent-nested-mark') })), subagent === undefined ? (teamRow !== undefined && _jsx(TeamRosterOnlyRow, { row: teamRow, focused: index === focusIndex, panelMode: panelMode, self: teamRow.member.id === sessionId })) : (_jsx(SubagentCard, { subagent: subagent, variant: panelMode ? 'panel' : 'default', focused: index === focusIndex, onClick: onSelect !== undefined
156
+ // Click = view detail, same as Enter on the focused card.
157
+ ? () => onSelect(subagent.agentId)
158
+ : undefined, ...teamRow === undefined ? {} : { teamMember: { name: teamRow.member.name, status: teamRow.status } } })), teamRow?.status === 'failed' && teamRow.member.error !== undefined && (_jsx(Text, { color: "error", wrap: "truncate-end", children: ' │ ' + teamRow.member.error })), teamRow?.status === 'idle' && subagent?.status === 'failed' && (_jsx(Text, { color: "error", wrap: "truncate-end", children: ' │ ' + t('team-last-run-failed', { error: subagent.error ?? '' }).trimEnd() })), subagent !== undefined && messages !== undefined && messages.length > 0 && (_jsx(AgentMessagesSummary, { messages: messages.filter(message => message.from === subagent.agentId || message.to === subagent.agentId), selfAgentId: subagent.agentId })), subagent !== undefined && onOpenView !== undefined && (!panelMode || index === focusIndex) && (_jsx(Box, { paddingLeft: 1, onClick: () => onOpenView(subagent.agentId), children: _jsx(Text, { color: "subtle", children: `⤢ ${t('agent-view-open-action')}` }) })), !panelMode && index < entries.length - 1 && index + 1 !== othersStart && (_jsx(Text, { dimColor: true, children: '─'.repeat(Math.max(20, Math.min(72, columns - 6))) }))] }, key)))), team !== undefined && _jsx(TeamTaskBoard, { tasks: team.tasks })] }) }), peers !== undefined && (!panelMode || peers.length > 0) && (_jsx(Box, { flexDirection: "column", children: panelMode ? (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: t('agents-peers-title') + ' · ' + peers.length })) : (_jsxs(_Fragment, { children: [_jsx(Text, { dimColor: true, children: t('agents-peers-title') }), peers.length === 0 ? (_jsx(Text, { dimColor: true, children: ' ' + t('agents-peers-empty') })) : (_jsxs(Box, { flexDirection: "column", children: [peers.map(peer => (_jsx(Text, { dimColor: true, wrap: "truncate-end", children: ' · ' + (peer.name ?? peer.label ?? peer.agentId.slice(0, 8)) + ' · ' + peer.agentId.slice(0, 8) }, peer.agentId))), _jsx(Text, { dimColor: true, wrap: "truncate-end", children: ' ' + t('agents-peers-note') })] }))] })) })), !panelMode && (_jsxs(_Fragment, { children: [_jsx(Divider, { color: "subtle", title: "" }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: onSelect ? t('subagent-dashboard-hint-detail') : t('subagent-dashboard-hint-basic') }) })] }))] }));
117
159
  }
@@ -1,4 +1,13 @@
1
1
  import type { SplashFont } from './splashFonts.js';
2
+ /**
3
+ * 块体大字的行数:上排 5 + 空 1 + 下排 5。
4
+ *
5
+ * 导出是给回归钉的:`portrait` 立绘槽高(`splashArtRows.ts` 的
6
+ * `PORTRAIT_ART_ROWS`)**等于这个数**——`LogoV2` 把娘立绘钳在与文字列等高的
7
+ * 槽里(`textColumnRows` = 两排大字 + 空行),落地页是 `chrome="minimal"`,
8
+ * 槽高就是大字块的行数。两处一漂移,预算就重新和渲染分叉。
9
+ */
10
+ export declare const BIG_TITLE_ROWS = 11;
2
11
  /** 输入框卡片占的行数:边框 2 + 输入 1(第三版:参数行移出框外)。 */
3
12
  export declare const CARD_ROWS = 3;
4
13
  /** 框下参数行的行数(模型/思考深度/模式/权限全空时整行不画)。 */
@@ -50,7 +59,9 @@ export interface LaunchpadLayout {
50
59
  * @param rows - 内容区行数。
51
60
  * @param options - whale / whaleGirl 对应设置项;font 是当天那款字体(字身宽度
52
61
  * 不同,宽轴阈值也跟着不同);params 是框下有没有参数行(模型/思考深度/模式/
53
- * 权限全拿不到时为 false,成组行矮一行)。
62
+ * 权限全拿不到时为 false,成组行矮一行);`artRows` 是**当天真正上场的立绘**
63
+ * 占的行数(`splashArtRows.ts` 解,缺省按像素鲸鱼 13 行);`cornerRows` 是
64
+ * 右下角铭牌自身的行数(第一行 + 内核数,缺省按老口径 2 行)。
54
65
  * @returns 该尺寸下要渲染的部件。
55
66
  */
56
67
  export declare function resolveLaunchpadLayout(columns: number, rows: number, options: {
@@ -58,5 +69,7 @@ export declare function resolveLaunchpadLayout(columns: number, rows: number, op
58
69
  whaleGirl?: boolean;
59
70
  font: SplashFont;
60
71
  params?: boolean;
72
+ artRows?: number;
73
+ cornerRows?: number;
61
74
  }): LaunchpadLayout;
62
75
  //# sourceMappingURL=launchpadLayout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"launchpadLayout.d.ts","sourceRoot":"","sources":["../../../src/components/launchpadLayout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AA0ClD,0CAA0C;AAC1C,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B,sCAAsC;AACtC,eAAO,MAAM,UAAU,IAAI,CAAA;AAwC3B,iBAAiB;AACjB,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,CAAA;AAErF,yBAAyB;AACzB,MAAM,WAAW,eAAe;IAC9B,gBAAgB;IAChB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,+BAA+B;IAC/B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,gBAAgB;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,4BAA4B;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,6BAA6B;IAC7B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,6BAA6B;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GACnF,eAAe,CA2FjB"}
1
+ {"version":3,"file":"launchpadLayout.d.ts","sourceRoot":"","sources":["../../../src/components/launchpadLayout.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAyClD;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,KAAK,CAAA;AAIhC,0CAA0C;AAC1C,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B,sCAAsC;AACtC,eAAO,MAAM,UAAU,IAAI,CAAA;AA2C3B,iBAAiB;AACjB,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,CAAA;AAErF,yBAAyB;AACzB,MAAM,WAAW,eAAe;IAC9B,gBAAgB;IAChB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,kCAAkC;IAClC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAA;IAC9B,+BAA+B;IAC/B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAA;IAChC,gBAAgB;IAChB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B,4BAA4B;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,0BAA0B;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,6BAA6B;IAC7B,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAA;IAC7B,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,6BAA6B;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,KAAK,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,IAAI,EAAE,UAAU,CAAA;IAChB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,GACA,eAAe,CA6FjB"}
@@ -1,5 +1,6 @@
1
1
  import { bigTextWidth } from './bigfont.js';
2
2
  import { WHALE_BOX_WIDTH } from './splashLayout.js';
3
+ import { WHALE_ART_ROWS } from './splashArtRows.js';
3
4
  /**
4
5
  * 落地页的降级阶梯——两个轴一起解:
5
6
  *
@@ -32,10 +33,21 @@ import { WHALE_BOX_WIDTH } from './splashLayout.js';
32
33
  * 所有列数按**内容区**算(PageMargin 已经把 TerminalSizeContext 收窄);行数
33
34
  * 同理。落地页不自己减页边距。
34
35
  */
35
- /** 鲸鱼/女仆娘立绘(含盒)的行数。 */
36
- const WHALE_ART_ROWS = 13;
37
- /** 块体大字的行数:上排 5 + 空 1 + 下排 5。 */
38
- const BIG_TITLE_ROWS = 11;
36
+ /**
37
+ * 立绘槽的默认行数(像素鲸鱼 13 行)。**真实行数由调用方传 `artRows`**——
38
+ * 槽高随形态变(女仆娘/Claude 娘 11、吉祥物 15),写死 13 会让默认的吉祥物
39
+ * 路径少算 2 行(见 `splashArtRows.ts` 的表与那段修复说明)。
40
+ */
41
+ const DEFAULT_ART_ROWS = WHALE_ART_ROWS;
42
+ /**
43
+ * 块体大字的行数:上排 5 + 空 1 + 下排 5。
44
+ *
45
+ * 导出是给回归钉的:`portrait` 立绘槽高(`splashArtRows.ts` 的
46
+ * `PORTRAIT_ART_ROWS`)**等于这个数**——`LogoV2` 把娘立绘钳在与文字列等高的
47
+ * 槽里(`textColumnRows` = 两排大字 + 空行),落地页是 `chrome="minimal"`,
48
+ * 槽高就是大字块的行数。两处一漂移,预算就重新和渲染分叉。
49
+ */
50
+ export const BIG_TITLE_ROWS = 11;
39
51
  /** 只留文字的档位:一行纯标题。 */
40
52
  const PLAIN_TITLE_ROWS = 1;
41
53
  /** 输入框卡片占的行数:边框 2 + 输入 1(第三版:参数行移出框外)。 */
@@ -73,18 +85,23 @@ const TIP_BLOCK_ROWS = 3;
73
85
  /** 矮屏撤呼吸后的紧档(自身 1 + 留白 1)。 */
74
86
  const TIP_BLOCK_ROWS_TIGHT = 2;
75
87
  /**
76
- * 双角铭牌:自身 2 行 + 上方 1 行留白。自身 2 行是第七版**版本号竖排**带来
77
- * 的——右下角两行(`dsh-tui v…` 在上、`dsh-core v…` 在下),左下目录铭牌仍
78
- * 1 行、与第一行顶对齐。内核版本读不到时右侧只画 1 行(预算按 2 行上限算,
79
- * 矮屏阶梯的取舍顺序不变:先撤装饰、绝不让输入框被挤掉)。
88
+ * 双角铭牌:自身行数 + 上方 1 行留白。自身 = 第一行(`工作目录:分支` 与
89
+ * `dsh-tui v…` 共用底边)+ **一行一个内核**——第八版给右下角扩了内核区,
90
+ * 行数随内核数变,所以**由调用方传 `cornerRows`**;写死 2 行时,装了多个
91
+ * 内核的机器(DSH + Claude + Codex)会少算两行,和立绘槽那处是同一类账
92
+ * 不平(矮屏阶梯以为放得下、实际溢出)。
80
93
  */
81
- const CORNERS_BLOCK_ROWS = 3;
94
+ const CORNERS_TOP_GAP_ROWS = 1;
95
+ /** 铭牌自身行数的老口径(第一行 + 一个内核行):内核数拿不到时的上限估算。 */
96
+ const DEFAULT_CORNER_ROWS = 2;
82
97
  /**
83
98
  * @param columns - 内容区列数。
84
99
  * @param rows - 内容区行数。
85
100
  * @param options - whale / whaleGirl 对应设置项;font 是当天那款字体(字身宽度
86
101
  * 不同,宽轴阈值也跟着不同);params 是框下有没有参数行(模型/思考深度/模式/
87
- * 权限全拿不到时为 false,成组行矮一行)。
102
+ * 权限全拿不到时为 false,成组行矮一行);`artRows` 是**当天真正上场的立绘**
103
+ * 占的行数(`splashArtRows.ts` 解,缺省按像素鲸鱼 13 行);`cornerRows` 是
104
+ * 右下角铭牌自身的行数(第一行 + 内核数,缺省按老口径 2 行)。
88
105
  * @returns 该尺寸下要渲染的部件。
89
106
  */
90
107
  export function resolveLaunchpadLayout(columns, rows, options) {
@@ -100,21 +117,23 @@ export function resolveLaunchpadLayout(columns, rows, options) {
100
117
  const showPlainTitle = !showBigTitle && !showWhale;
101
118
  const showHero = showWhale || showBigTitle || showPlainTitle;
102
119
  // 上下排布时头部 = 立绘 + 间隔 1 + 大字;退化档位取各自实际行数。
103
- const artRows = showWhale ? WHALE_ART_ROWS : 0;
120
+ // 立绘行数按**当天上场的形态**算(鲸鱼 13 / 娘与吉祥物 15),不写死。
121
+ const artRows = showWhale ? (options.artRows ?? DEFAULT_ART_ROWS) : 0;
104
122
  const titleRows = showBigTitle ? BIG_TITLE_ROWS : PLAIN_TITLE_ROWS;
105
123
  const heroRows = showHero ? (artRows > 0 ? artRows + 1 + titleRows : titleRows) : 0;
106
124
  // 头部整块(含根盒 marginTop)实际占的行数:阶梯与 totalRows 都按它算。
107
125
  const heroBlockRows = showHero ? heroRows + HERO_TOP_MARGIN : 0;
108
126
  // 第六版行数预算:输入框(恒 3)+ 框下成组行(参数 1 + 呼吸留白 0/1 +
109
- // 键帽 1 + Tips 3)+ 双角铭牌 2。撤的顺序「从最可省到最不可省」:
110
- // 新增的两处呼吸(词标↔输入框、入口行↔Tips)→ 参数行呼吸留白 → Tips 行
111
- // 本身 → 键帽行 → 立绘(**所有留白永远排在 Tips/入口行之前撤**,
112
- // 绝不让呼吸把输入框挤掉)。
127
+ // 键帽 1 + Tips 3)+ 双角铭牌(自身行数 + 上方留白)。撤的顺序「从最可省
128
+ // 到最不可省」:新增的两处呼吸(词标↔输入框、入口行↔Tips)→ 参数行呼吸
129
+ // 留白 → Tips 行本身 → 键帽行 → 立绘(**所有留白永远排在 Tips/入口行之
130
+ // 前撤**,绝不让呼吸把输入框挤掉)。
113
131
  const paramRows = options.params === true ? PARAM_ROWS : 0;
114
132
  const gapRows = paramRows > 0 ? PARAM_HINTS_GAP_ROWS : 0;
115
133
  const cardRows = CARD_ROWS;
134
+ const cornersBlockRows = (options.cornerRows ?? DEFAULT_CORNER_ROWS) + CORNERS_TOP_GAP_ROWS;
116
135
  const withArt = artRows > 0 ? artRows + 1 : 0;
117
- const core = heroBlockRows + cardRows + paramRows + CORNERS_BLOCK_ROWS;
136
+ const core = heroBlockRows + cardRows + paramRows + cornersBlockRows;
118
137
  // 每一档的总行数。顺序即从最全的往下掉:先试最全的,放不下就往下掉。
119
138
  // full 带 4 个变体(呼吸×参数留白的紧/松组合)、no-tip 带 3 个:
120
139
  // 呼吸在(默认 2/2)→ 撤呼吸(紧档 1/1)→ 撤参数留白,全部都矮于撤 Tips。
@@ -154,7 +173,7 @@ export function resolveLaunchpadLayout(columns, rows, options) {
154
173
  const heroGapRows = keepBreath ? HERO_TO_CARD_GAP : HERO_TO_CARD_GAP_TIGHT;
155
174
  const tipGapRows = keepBreath ? TIP_BLOCK_ROWS - 1 : TIP_BLOCK_ROWS_TIGHT - 1;
156
175
  const total = (showTip ? 1 + tipGapRows : 0) + hintsGapRows + (showHints ? HINTS_ROWS : 0) + heroBlockFinal
157
- + heroGapRows + cardRows + paramRows + CORNERS_BLOCK_ROWS;
176
+ + heroGapRows + cardRows + paramRows + cornersBlockRows;
158
177
  return {
159
178
  stage,
160
179
  // dropArt 只撤立绘——`heroRowsFinal`/`totalRows` 都按「撤立绘、留大字」算,
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ type Props = {
3
+ /** The sending team member's name. */
4
+ sender: string;
5
+ text: string;
6
+ /** Adds the top margin between turns. */
7
+ marginTopOnTurn: boolean;
8
+ /** Message-selection mode highlight. */
9
+ isSelected?: boolean;
10
+ };
11
+ /**
12
+ * An Agent Teams peer message delivered to this session: a `✉ <sender>` line
13
+ * in the agent tint, then the body in plain text with a hanging indent — it
14
+ * reads apart from the human's bold `❯` prompt it shares a log role with.
15
+ * The body wraps in its own flex column, so it fits whatever column hosts it
16
+ * (the main list, a child scene's padded page, a split with the workbench).
17
+ */
18
+ export declare function TeamMessageBubble({ sender, text, marginTopOnTurn, isSelected }: Props): React.ReactNode;
19
+ export {};
20
+ //# sourceMappingURL=TeamMessageBubble.d.ts.map