@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
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { PluginInstallStep } from '../dsh-adapter/plugin-install.js';
3
+ /**
4
+ * `/plugin install <spec>`: the pane that asks what the flow cannot answer on
5
+ * its own (Stage C-4).
6
+ *
7
+ * The flow (`dsh-adapter/plugin-install.ts`) writes every line of the install
8
+ * into the transcript as it happens — the inspection, pnpm's phases, the result
9
+ * — so this pane only carries the two things a person must decide before that:
10
+ * gate 1's pre-install notice and gate 3's trust confirmation. It also renders
11
+ * the two "decide and retry" steps (unapproved build scripts, an incompatible
12
+ * version), which are the same kind of question.
13
+ *
14
+ * Presentational only: the step state lives in Chat, keys are handled there
15
+ * (Enter confirms / retries, Esc cancels), exactly like the SDK install wizard.
16
+ */
17
+ export declare function PluginInstallPane({ step, busy }: {
18
+ step: PluginInstallStep;
19
+ busy: boolean;
20
+ }): React.ReactNode;
21
+ //# sourceMappingURL=PluginInstallPane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginInstallPane.d.ts","sourceRoot":"","sources":["../../../src/components/PluginInstallPane.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,iBAAiB,EAAqB,MAAM,kCAAkC,CAAA;AAqB5F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAgF7G"}
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { t } from '../i18n.js';
3
+ import { Box, Text } from '../ui.js';
4
+ import { cleanRenderText, NOTICE_CELLS } from '../channel/sanitize.js';
5
+ import { HintLine } from './design-system/HintLine.js';
6
+ import { LoadingState } from './design-system/LoadingState.js';
7
+ import { Pane } from './design-system/Pane.js';
8
+ /** Foreign text on its way to the screen: control sequences stripped, bounded. */
9
+ const clean = (value) => cleanRenderText(value, NOTICE_CELLS);
10
+ /**
11
+ * The target's identity is the subject of the confirmation, and it is foreign
12
+ * text like everything else here: the name comes from the package's own
13
+ * manifest, so it can carry newlines or thousands of cells. Bounded to what a
14
+ * line can show — at 50 columns an unbounded name buries the title and the key
15
+ * hints, which are exactly what the person needs to answer the question.
16
+ */
17
+ const TARGET_CELLS = 80;
18
+ /**
19
+ * `/plugin install <spec>`: the pane that asks what the flow cannot answer on
20
+ * its own (Stage C-4).
21
+ *
22
+ * The flow (`dsh-adapter/plugin-install.ts`) writes every line of the install
23
+ * into the transcript as it happens — the inspection, pnpm's phases, the result
24
+ * — so this pane only carries the two things a person must decide before that:
25
+ * gate 1's pre-install notice and gate 3's trust confirmation. It also renders
26
+ * the two "decide and retry" steps (unapproved build scripts, an incompatible
27
+ * version), which are the same kind of question.
28
+ *
29
+ * Presentational only: the step state lives in Chat, keys are handled there
30
+ * (Enter confirms / retries, Esc cancels), exactly like the SDK install wizard.
31
+ */
32
+ export function PluginInstallPane({ step, busy }) {
33
+ if (busy) {
34
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsx(Box, { marginTop: 1, children: _jsx(LoadingState, { message: t('plugins-install-installing') }) })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-cancel') }) })] }));
35
+ }
36
+ if (step.kind === 'confirm') {
37
+ const { artifact, trust, notice } = step;
38
+ const spec = artifact.name === undefined
39
+ ? t('plugins-install-unidentified')
40
+ : cleanRenderText(`${artifact.name}${artifact.version === undefined ? '' : `@${artifact.version}`}`, TARGET_CELLS);
41
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }) }), _jsx(Text, { children: t('plugins-install-configure', {
42
+ spec,
43
+ kind: artifact.kind,
44
+ bundle: artifact.bundle === true ? 'bundle' : artifact.bundle === false ? 'not a bundle' : 'unknown',
45
+ }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [trust.kind === 'third-party' && _jsx(Text, { children: t('plugins-install-trust-third-party') }), notice.kind === 'declared' && _jsx(Text, { dimColor: true, children: t('plugins-install-notice-declared') }), notice.kind === 'undeclared' && _jsx(Text, { children: t('plugins-install-notice-undeclared') }), notice.kind === 'invalid' && _jsx(Text, { children: t('plugins-install-notice-invalid', { err: notice.error }) }), notice.kind === 'unjudged' && _jsx(Text, { children: t('plugins-install-notice-unjudged') })] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-confirm') }) })] }));
46
+ }
47
+ if (step.kind === 'build-blocked') {
48
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-builds-title') }), step.builds.map(build => _jsx(Text, { dimColor: true, children: ` ${clean(build)}` }, build))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-builds') }) })] }));
49
+ }
50
+ if (step.kind === 'incompatible') {
51
+ return (_jsxs(Pane, { color: "permission", children: [_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "remember", bold: true, children: t('plugins-install-pane-title') }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-incompatible-title') }), step.packages.map(entry => _jsx(Text, { dimColor: true, children: describe(entry) }, `${entry.name}@${entry.version}`))] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { children: t('plugins-install-exemptions-title') }), exemptionLines(step.exemptions).map((line, index) => _jsx(Text, { dimColor: true, children: line }, index))] })] }), _jsx(Text, { dimColor: true, italic: true, children: _jsx(HintLine, { text: t('plugins-install-key-incompatible') }) })] }));
52
+ }
53
+ // `done` never renders: its lines are already in the transcript, so Chat
54
+ // closes the pane instead of leaving an empty box behind.
55
+ return null;
56
+ }
57
+ /**
58
+ * One package the running host refuses, with the peers it fails.
59
+ *
60
+ * Every field here is foreign text — a package name, a version, a peer range
61
+ * the author wrote — and the pane is a render path like any other, so each one
62
+ * goes through the same sanitizer the rest of the interface uses before it can
63
+ * reach the screen.
64
+ */
65
+ function describe(entry) {
66
+ const peers = Object.entries(entry.peers)
67
+ .map(([name, range]) => `${clean(name)} ${clean(range)}`)
68
+ .join(', ');
69
+ return ` ${clean(entry.name)}@${clean(entry.version)} (running ${clean(entry.runtimeVersion)}${peers === '' ? '' : `; needs ${peers}`})`;
70
+ }
71
+ /**
72
+ * The profile's compatibility file as rows. The file maps `package@version` to
73
+ * the runtime versions exempted for it, and a corrupt one answers warnings
74
+ * instead — both shapes are the person's business here, because this is the
75
+ * step where they decide whether to add another. The file is user-editable and
76
+ * carries whatever somebody typed, so its rows are sanitized too.
77
+ */
78
+ function exemptionLines(exemptions) {
79
+ const rows = Object.entries(exemptions.exemptions)
80
+ .map(([packageVersion, runtimes]) => ` ${clean(packageVersion)} → ${runtimes.map(runtime => clean(runtime)).join(', ')}`);
81
+ if (rows.length === 0 && exemptions.warnings.length === 0)
82
+ return [` ${t('plugins-info-registries-none')}`];
83
+ return [...rows, ...exemptions.warnings.map(warning => ` ${clean(warning)}`)];
84
+ }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { PluginManageStep } from '../dsh-adapter/plugin-manage.js';
3
+ /**
4
+ * `/plugin remove | enable | disable`: the pane that asks what the flow cannot
5
+ * answer on its own (Stage C-5).
6
+ *
7
+ * The flow (`dsh-adapter/plugin-manage.ts`) writes every line of the action into
8
+ * the transcript — what it resolved, why it refused, what the service answered —
9
+ * so this pane only carries the one thing a person must decide before the write.
10
+ * Unlike the install pane there is no progress, no cancellation and no retry:
11
+ * each action is a single call that settles once.
12
+ *
13
+ * Presentational only, and the same three parts as its install sibling
14
+ * (`PluginInstallPane`): the pane, the facts that make the question answerable,
15
+ * and the key hints. Keys are handled in Chat (Enter answers, Esc closes).
16
+ */
17
+ export declare function PluginManagePane({ step, busy }: {
18
+ step: PluginManageStep;
19
+ busy: boolean;
20
+ }): React.ReactNode;
21
+ //# sourceMappingURL=PluginManagePane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginManagePane.d.ts","sourceRoot":"","sources":["../../../src/components/PluginManagePane.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,iCAAiC,CAAA;AAiB3F;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG,KAAK,CAAC,SAAS,CAqD3G"}
@@ -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":"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,4BA63HlB"}
1
+ {"version":3,"file":"PromptInput.d.ts","sourceRoot":"","sources":["../../../src/components/PromptInput.tsx"],"names":[],"mappings":"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"}
@@ -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
  }