@yancyyu/openhermit 1.6.42 → 1.6.43

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 (281) hide show
  1. package/README.md +98 -89
  2. package/bin/hermit.mjs +96 -0
  3. package/dist-renderer/assets/{ProjectEditorOverlay-DlFQ6mai.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
  4. package/dist-renderer/assets/{TeamGraphOverlay-D2TPMPGR.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
  5. package/dist-renderer/assets/{_basePickBy-Cmd0RHLQ.js → _basePickBy-ZOyLWjMK.js} +1 -1
  6. package/dist-renderer/assets/{_baseUniq-BI_iy8ea.js → _baseUniq-DBb726rt.js} +1 -1
  7. package/dist-renderer/assets/{arc-NzW2mjTP.js → arc-CdiTaR_R.js} +1 -1
  8. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Bzq85AYv.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
  9. package/dist-renderer/assets/{blockDiagram-VD42YOAC-D1PvYS-b.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
  10. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-D49RKzPC.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
  11. package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
  12. package/dist-renderer/assets/{chunk-4BX2VUAB-fmI_MQmQ.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
  13. package/dist-renderer/assets/{chunk-55IACEB6-Xsv9RCXZ.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
  14. package/dist-renderer/assets/{chunk-B4BG7PRW-BE1KO8Um.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
  15. package/dist-renderer/assets/{chunk-DI55MBZ5-tqJ7Mv7f.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
  16. package/dist-renderer/assets/{chunk-FMBD7UC4-DMD45MVJ.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QN33PNHL-DOhGrz-q.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QZHKN3VN-D8yDgJdD.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
  19. package/dist-renderer/assets/{chunk-TZMSLE5B-BcsEDu7A.js → chunk-TZMSLE5B-BQEil57G.js} +1 -1
  20. package/dist-renderer/assets/classDiagram-2ON5EDUG-lpzulY5X.js +1 -0
  21. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-lpzulY5X.js +1 -0
  22. package/dist-renderer/assets/clone-CriGymY9.js +1 -0
  23. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DlSqGHMX.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
  24. package/dist-renderer/assets/{dagre-6UL2VRFP-BTT9tSAx.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
  25. package/dist-renderer/assets/{diagram-PSM6KHXK-Du-U-mK2.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
  26. package/dist-renderer/assets/{diagram-QEK2KX5R-jFdHeKas.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
  27. package/dist-renderer/assets/{diagram-S2PKOQOG-DKLNK2bu.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
  28. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-CZxHgIIo.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
  29. package/dist-renderer/assets/{flowDiagram-NV44I4VS-v4XStCD0.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
  30. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DJjD_BEL.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
  31. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BNy-jr03.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
  32. package/dist-renderer/assets/{graph-DDTrn6je.js → graph-CDP_R8ct.js} +1 -1
  33. package/dist-renderer/assets/{index-BBp78BAu.js → index-BSZdT-g-.js} +1 -1
  34. package/dist-renderer/assets/{index-eotrJaYy.js → index-BhWvMqsz.js} +1 -1
  35. package/dist-renderer/assets/{index-D8_B-cfs.js → index-C2_AupSj.js} +1 -1
  36. package/dist-renderer/assets/{index-BQrwHZ-k.js → index-C5ujiwAR.js} +580 -588
  37. package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
  38. package/dist-renderer/assets/{index-CRKQSG9S.js → index-CVNjLwkq.js} +1 -1
  39. package/dist-renderer/assets/{index-DR6Wz52b.js → index-CwG3se0q.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DqnOsuza.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DTobaO1d.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-HbwVOvWc.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
  43. package/dist-renderer/assets/{layout--VYmTcw2.js → layout-5nA5wUxO.js} +1 -1
  44. package/dist-renderer/assets/{linear-BsJh89Mr.js → linear-BtF1i2qN.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-BZqUZePd.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-B1q_nH6P.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-UD8QhSEu.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BA_i7Nw8.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-CMTnX-2d.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-BQXDB615.js → sequenceDiagram-WL72ISMW-CJg-WYyY.js} +1 -1
  51. package/dist-renderer/assets/{splashScene-D0YB9uxm.js → splashScene-94xWCzLA.js} +1 -1
  52. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BAsPXy6X.js → stateDiagram-FKZM4ZOC-DWHOoFdv.js} +1 -1
  53. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-CGYZOoMb.js +1 -0
  54. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BdasmVkC.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
  55. package/dist-renderer/assets/{treemap-GDKQZRPO-BkKQqIui.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
  56. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-EAlPHOdx.js → xychartDiagram-PRI3JC2R-CCOcGbrD.js} +1 -1
  57. package/dist-renderer/chat-community-qr.jpg +0 -0
  58. package/dist-renderer/fonts/Agave-Bold.ttf +0 -0
  59. package/dist-renderer/fonts/Agave-Regular.ttf +0 -0
  60. package/dist-renderer/icon.png +0 -0
  61. package/dist-renderer/icon.rar +0 -0
  62. package/dist-renderer/index.html +3 -3
  63. package/package.json +21 -26
  64. package/src/features/worker-society/core/application/WorkerSocietyService.test.ts +802 -0
  65. package/src/features/worker-society/core/application/WorkerSocietyService.ts +428 -0
  66. package/src/features/worker-society/core/application/fakes.ts +101 -0
  67. package/src/features/worker-society/core/application/ports.ts +70 -0
  68. package/src/features/worker-society/core/domain/models/society.ts +141 -0
  69. package/src/features/worker-society/core/domain/policies/societyPolicies.test.ts +739 -0
  70. package/src/features/worker-society/core/domain/policies/societyPolicies.ts +496 -0
  71. package/src/features/worker-society/main/adapters/input/societyMcp.test.ts +317 -0
  72. package/src/features/worker-society/main/adapters/input/societyMcp.ts +257 -0
  73. package/src/features/worker-society/main/adapters/input/societyRoutes.test.ts +695 -0
  74. package/src/features/worker-society/main/adapters/input/societyRoutes.ts +194 -0
  75. package/src/features/worker-society/main/composition/societyComposition.test.ts +74 -0
  76. package/src/features/worker-society/main/composition/societyComposition.ts +70 -0
  77. package/src/features/worker-society/main/composition/workerSocietyPlugin.test.ts +69 -0
  78. package/src/features/worker-society/main/composition/workerSocietyPlugin.ts +67 -0
  79. package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.test.ts +132 -0
  80. package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.ts +84 -0
  81. package/src/features/worker-society/main/infrastructure/fsStores.test.ts +216 -0
  82. package/src/features/worker-society/main/infrastructure/fsStores.ts +113 -0
  83. package/src/features/worker-society/main/infrastructure/mergingProfileStore.test.ts +195 -0
  84. package/src/features/worker-society/main/infrastructure/mergingProfileStore.ts +96 -0
  85. package/src/features/worker-society/renderer/SocietyGraph.tsx +166 -0
  86. package/src/features/worker-society/renderer/SocietyNodeLabels.tsx +139 -0
  87. package/src/features/worker-society/renderer/SocietyNodeOverlay.tsx +339 -0
  88. package/src/features/worker-society/renderer/SocietyView.tsx +437 -0
  89. package/src/features/worker-society/renderer/index.ts +11 -0
  90. package/src/features/worker-society/renderer/societyApi.test.ts +259 -0
  91. package/src/features/worker-society/renderer/societyApi.ts +144 -0
  92. package/src/features/worker-society/renderer/societyGraphAdapter.test.ts +321 -0
  93. package/src/features/worker-society/renderer/societyGraphAdapter.ts +240 -0
  94. package/src/features/worker-society/renderer/societyOverlayActions.test.ts +57 -0
  95. package/src/features/worker-society/renderer/societyOverlayActions.ts +49 -0
  96. package/src/features/worker-society/renderer/societyStore.test.ts +218 -0
  97. package/src/features/worker-society/renderer/societyStore.ts +146 -0
  98. package/src/features/worker-society/renderer/societyViewUtils.test.ts +81 -0
  99. package/src/features/worker-society/renderer/societyViewUtils.ts +68 -0
  100. package/src/main/ipc/extensions.ts +27 -0
  101. package/src/main/server.ts +1709 -534
  102. package/src/main/services/ccConnect/CcConnectBridge.ts +26 -11
  103. package/src/main/services/ccConnect/CcConnectClient.ts +9 -2
  104. package/src/main/services/ccConnect/workDirReconcile.test.ts +57 -0
  105. package/src/main/services/ccConnect/workDirReconcile.ts +36 -0
  106. package/src/main/services/direct-cli/DirectCliSessionManager.test.ts +397 -0
  107. package/src/main/services/direct-cli/DirectCliSessionManager.ts +508 -0
  108. package/src/main/services/direct-cli/DirectCliSessionStore.test.ts +79 -0
  109. package/src/main/services/direct-cli/DirectCliSessionStore.ts +97 -0
  110. package/src/main/services/direct-cli/__tests__/directCliMessageId.test.ts +40 -0
  111. package/src/main/services/direct-cli/directCliMessageId.ts +21 -0
  112. package/src/main/services/direct-cli/index.ts +17 -0
  113. package/src/main/services/extensions/capability-packs/CapabilityPackLoaderService.ts +637 -0
  114. package/src/main/services/extensions/catalog/PluginCatalogService.ts +2 -2
  115. package/src/main/services/loop-assets/LoopAssetsScannerService.ts +657 -0
  116. package/src/main/services/runtime/providerAwareCliEnv.ts +33 -5
  117. package/src/main/services/session-intelligence/LocalSessionScanner.ts +156 -71
  118. package/src/main/services/session-intelligence/SessionUsageParser.ts +103 -8
  119. package/src/main/services/session-intelligence/UsageTelemetryService.ts +11 -0
  120. package/src/main/services/session-intelligence/__tests__/teamSessionListMapper.test.ts +104 -0
  121. package/src/main/services/session-intelligence/teamSessionListMapper.ts +78 -0
  122. package/src/main/services/system-manager/AdminLoopInitializer.ts +95 -0
  123. package/src/main/services/system-manager/BuiltinWorkflowSeeder.ts +679 -74
  124. package/src/main/services/system-manager/SystemManagerConfigService.ts +19 -1
  125. package/src/main/services/system-manager/WorkflowPromptService.ts +58 -5
  126. package/src/main/services/system-manager/__tests__/AdminLoopInitializer.test.ts +129 -0
  127. package/src/main/services/system-manager/__tests__/SystemManagerConfigService.test.ts +60 -0
  128. package/src/main/services/teams-mvp/CollaborationBoardService.ts +2 -0
  129. package/src/main/services/teams-mvp/OpsRunbookContext.ts +60 -0
  130. package/src/main/services/teams-mvp/TaskDispatchService.test.ts +305 -0
  131. package/src/main/services/teams-mvp/TaskDispatchService.ts +250 -131
  132. package/src/main/services/teams-mvp/TeamProvisioningService.ts +12 -2
  133. package/src/main/services/teams-mvp/TeamWorkspaceService.test.ts +207 -0
  134. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +104 -51
  135. package/src/main/services/teams-mvp/index.ts +6 -0
  136. package/src/main/utils/externalPlatformSessionRouting.ts +92 -0
  137. package/src/main/utils/toolApprovalRules.ts +151 -0
  138. package/src/renderer/App.tsx +24 -89
  139. package/src/renderer/api/httpClient.ts +115 -37
  140. package/src/renderer/api/providers.ts +5 -16
  141. package/src/renderer/components/chat/CommunityChatView.tsx +81 -0
  142. package/src/renderer/components/dashboard/DashboardView.tsx +130 -84
  143. package/src/renderer/components/extensions/ExtensionStoreView.tsx +39 -5
  144. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +2 -1
  145. package/src/renderer/components/extensions/capability-packs/CapabilityPacksPanel.tsx +170 -0
  146. package/src/renderer/components/layout/PaneContent.tsx +10 -2
  147. package/src/renderer/components/layout/SortableTab.tsx +4 -0
  148. package/src/renderer/components/layout/TabBarActions.tsx +13 -16
  149. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +4 -135
  150. package/src/renderer/components/schedules/SchedulesView.tsx +22 -14
  151. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +7 -6
  152. package/src/renderer/components/settings/SettingsTabs.tsx +24 -21
  153. package/src/renderer/components/settings/SettingsView.tsx +22 -13
  154. package/src/renderer/components/settings/components/SettingRow.tsx +13 -5
  155. package/src/renderer/components/settings/components/SettingsSectionCard.tsx +53 -0
  156. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +10 -6
  157. package/src/renderer/components/settings/components/SettingsSelect.tsx +12 -9
  158. package/src/renderer/components/settings/components/SettingsToggle.tsx +6 -5
  159. package/src/renderer/components/settings/components/index.ts +1 -0
  160. package/src/renderer/components/settings/sections/AdvancedSection.tsx +78 -59
  161. package/src/renderer/components/settings/sections/CliStatusSection.tsx +32 -44
  162. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  163. package/src/renderer/components/settings/sections/GeneralSection.tsx +216 -186
  164. package/src/renderer/components/settings/sections/PlatformsSection.tsx +25 -17
  165. package/src/renderer/components/settings/sections/TaskBusSection.tsx +63 -22
  166. package/src/renderer/components/sidebar/SidebarSessions.tsx +120 -80
  167. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +1 -1
  168. package/src/renderer/components/splash/splashScene.ts +6 -2
  169. package/src/renderer/components/system-manager/SystemManagerView.tsx +169 -255
  170. package/src/renderer/components/tasks/TasksView.tsx +63 -37
  171. package/src/renderer/components/team/CcSessionsSection.tsx +124 -89
  172. package/src/renderer/components/team/HarnessBrandLogos.tsx +318 -0
  173. package/src/renderer/components/team/HarnessSelect.tsx +25 -26
  174. package/src/renderer/components/team/TeamDetailView.tsx +137 -153
  175. package/src/renderer/components/team/TeamEmptyState.tsx +9 -37
  176. package/src/renderer/components/team/TeamListView.tsx +143 -30
  177. package/src/renderer/components/team/__tests__/CcSessionsSection.hasLocalFile.test.tsx +128 -0
  178. package/src/renderer/components/team/activity/ActivityItem.tsx +21 -9
  179. package/src/renderer/components/team/activity/ActivityTimeline.tsx +2 -2
  180. package/src/renderer/components/team/dialogs/AdvancedCliSection.tsx +1 -1
  181. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +13 -10
  182. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +156 -83
  183. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +9 -157
  184. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +19 -15
  185. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +48 -10
  186. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +11 -12
  187. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +39 -37
  188. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +434 -64
  189. package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +12 -10
  190. package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +2 -2
  191. package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.bindProject.test.tsx +399 -0
  192. package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.chineseRepro.test.tsx +253 -0
  193. package/src/renderer/components/team/dialogs/platformAllowUtils.ts +91 -0
  194. package/src/renderer/components/team/dialogs/teammateRuntimeCompatibility.tsx +1 -1
  195. package/src/renderer/components/team/kanban/KanbanTaskCard.test.tsx +41 -0
  196. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +41 -86
  197. package/src/renderer/components/team/loop-console/LoopCommandComposer.tsx +310 -0
  198. package/src/renderer/components/team/loop-console/LoopConsolePanel.tsx +372 -0
  199. package/src/renderer/components/team/loop-console/loopSendIntent.test.ts +85 -0
  200. package/src/renderer/components/team/loop-console/loopSendIntent.ts +221 -0
  201. package/src/renderer/components/team/loop-console/useLeadSessionToolActivity.ts +74 -0
  202. package/src/renderer/components/team/loop-console/useLoopCommandSuggestions.ts +165 -0
  203. package/src/renderer/components/team/loop-console/useLoopConsoleController.ts +266 -0
  204. package/src/renderer/components/team/members/LeadModelRow.test.tsx +1 -1
  205. package/src/renderer/components/team/members/LeadModelRow.tsx +5 -3
  206. package/src/renderer/components/team/members/MemberDetailDialog.tsx +11 -0
  207. package/src/renderer/components/team/members/MemberDetailStats.tsx +13 -3
  208. package/src/renderer/components/team/members/MemberDraftRow.test.tsx +1 -1
  209. package/src/renderer/components/team/members/MemberDraftRow.tsx +1 -1
  210. package/src/renderer/components/team/members/MemberMessagesTab.tsx +2 -2
  211. package/src/renderer/components/team/members/MemberStatsTab.tsx +1 -1
  212. package/src/renderer/components/team/messages/MessageComposer.tsx +150 -44
  213. package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +2 -2
  214. package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -28
  215. package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +6 -6
  216. package/src/renderer/components/team/taskLogs/ExactTaskLogCard.tsx +2 -2
  217. package/src/renderer/components/team/taskLogs/TaskLogStreamSection.tsx +1 -1
  218. package/src/renderer/components/terminal/TerminalPanel.tsx +2 -3
  219. package/src/renderer/components/ui/MentionableTextarea.tsx +5 -1
  220. package/src/renderer/constants/teamColors.ts +5 -5
  221. package/src/renderer/hooks/useExtensionsTabState.ts +1 -1
  222. package/src/renderer/hooks/useMentionDetection.ts +5 -1
  223. package/src/renderer/hooks/useProjectWorkflowCommands.ts +57 -0
  224. package/src/renderer/hooks/useTeamSuggestions.ts +2 -0
  225. package/src/renderer/index.css +19 -2
  226. package/src/renderer/main.tsx +7 -1
  227. package/src/renderer/store/index.ts +18 -1
  228. package/src/renderer/store/slices/extensionsSlice.ts +83 -0
  229. package/src/renderer/store/slices/tabSlice.ts +61 -0
  230. package/src/renderer/store/slices/teamSlice.ts +138 -9
  231. package/src/renderer/types/mention.ts +8 -0
  232. package/src/renderer/types/tabs.ts +3 -1
  233. package/src/renderer/utils/__tests__/bindProjectSlug.test.ts +69 -0
  234. package/src/renderer/utils/__tests__/groupTransformer.test.ts +148 -0
  235. package/src/renderer/utils/__tests__/initialRoute.test.ts +101 -0
  236. package/src/renderer/utils/__tests__/leadToolActivity.test.ts +124 -0
  237. package/src/renderer/utils/__tests__/mergeTeamMessages.test.ts +81 -0
  238. package/src/renderer/utils/__tests__/teamMessageFiltering.test.ts +213 -0
  239. package/src/renderer/utils/__tests__/teamMessageKey.test.ts +75 -0
  240. package/src/renderer/utils/__tests__/workflowCommandExecution.test.ts +173 -0
  241. package/src/renderer/utils/__tests__/workflowCommandSuggestions.test.ts +59 -0
  242. package/src/renderer/utils/bindProjectSlug.ts +57 -0
  243. package/src/renderer/utils/capabilityCommandExecution.ts +113 -0
  244. package/src/renderer/utils/initialRoute.ts +89 -0
  245. package/src/renderer/utils/leadToolActivity.ts +117 -0
  246. package/src/renderer/utils/loopShortcutSuggestions.ts +106 -0
  247. package/src/renderer/utils/mentionSuggestions.ts +1 -1
  248. package/src/renderer/utils/slashCommandRegistry.ts +231 -0
  249. package/src/renderer/utils/teamMentionDirective.ts +31 -0
  250. package/src/renderer/utils/workflowCommandExecution.ts +96 -0
  251. package/src/renderer/utils/workflowCommandSuggestions.ts +49 -0
  252. package/src/shared/types/api.ts +79 -4
  253. package/src/shared/types/ccConnect.ts +1 -0
  254. package/src/shared/types/extensions/api.ts +19 -0
  255. package/src/shared/types/extensions/capabilityPack.ts +118 -0
  256. package/src/shared/types/extensions/index.ts +29 -1
  257. package/src/shared/types/index.ts +6 -0
  258. package/src/shared/types/loopAssets.ts +54 -0
  259. package/src/shared/types/providers.ts +0 -16
  260. package/src/shared/types/systemManager.ts +26 -1
  261. package/src/shared/types/team.ts +41 -5
  262. package/src/shared/types/terminal.ts +2 -36
  263. package/src/shared/types/worker.test.ts +28 -0
  264. package/src/shared/types/worker.ts +3 -0
  265. package/src/shared/utils/__tests__/effortLevels.test.ts +88 -0
  266. package/src/shared/utils/__tests__/providerBackend.test.ts +88 -0
  267. package/src/shared/utils/__tests__/providerLaunchArgs.test.ts +220 -0
  268. package/src/shared/utils/claudeStreamJson.test.ts +187 -0
  269. package/src/shared/utils/claudeStreamJson.ts +153 -0
  270. package/src/shared/utils/providerLaunchArgs.ts +217 -0
  271. package/src/shared/utils/slashCommands.ts +10 -0
  272. package/src/types/node-pty.d.ts +8 -0
  273. package/dist-renderer/assets/channel-Ch7JrfUu.js +0 -1
  274. package/dist-renderer/assets/classDiagram-2ON5EDUG-z9I4AnFy.js +0 -1
  275. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-z9I4AnFy.js +0 -1
  276. package/dist-renderer/assets/clone-Dfi1Jx6l.js +0 -1
  277. package/dist-renderer/assets/index-iyjkpSus.css +0 -32
  278. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DTUIBfce.js +0 -1
  279. package/src/main/services/system-manager/SystemManagerPtyService.ts +0 -233
  280. package/src/renderer/components/common/TerminalPane.tsx +0 -213
  281. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +0 -292
@@ -59,12 +59,14 @@ import { isLeadAgentType, isLeadMember } from '@shared/utils/leadDetection';
59
59
  import { deriveTaskDisplayId, formatTaskDisplayLabel } from '@shared/utils/taskIdentity';
60
60
  import {
61
61
  AlertTriangle,
62
+ Bot,
62
63
  Columns3,
63
64
  Download,
64
65
  FolderOpen,
65
66
  GitBranch,
66
67
  History,
67
68
  Link,
69
+ Network,
68
70
  Pencil,
69
71
  Play,
70
72
  Plus,
@@ -92,18 +94,23 @@ import { KanbanSearchInput } from './kanban/KanbanSearchInput';
92
94
  import { TrashDialog } from './kanban/TrashDialog';
93
95
  import { MemberDetailDialog } from './members/MemberDetailDialog';
94
96
 
95
-
96
97
  import type { TeamMessagesPanelMode } from '@renderer/types/teamMessagesPanelMode';
97
98
  import type { ComponentProps } from 'react';
98
99
 
99
- import { TerminalPane, type TerminalPaneRef } from '@renderer/components/common/TerminalPane';
100
-
101
100
  const ProjectEditorOverlay = lazy(() =>
102
101
  import('./editor/ProjectEditorOverlay').then((m) => ({ default: m.ProjectEditorOverlay }))
103
102
  );
103
+ import { LoopConsolePanel } from './loop-console/LoopConsolePanel';
104
104
  import { MemberList } from './members/MemberList';
105
105
  import { MessagesPanel } from './messages/MessagesPanel';
106
- import { CcSessionsSection, buildAllSessionsCsv, buildAllSessionsCsvFilename, downloadTextFile, hasDataRows, isExportPayload } from './CcSessionsSection';
106
+ import {
107
+ CcSessionsSection,
108
+ buildAllSessionsCsv,
109
+ buildAllSessionsCsvFilename,
110
+ downloadTextFile,
111
+ hasDataRows,
112
+ isExportPayload,
113
+ } from './CcSessionsSection';
107
114
  import { ChangeReviewDialog } from './review/ChangeReviewDialog';
108
115
  import {
109
116
  getTeamPendingRepliesState,
@@ -239,7 +246,7 @@ const TeamOfflineStatusBanner = memo(function TeamOfflineStatusBanner({
239
246
  teamName: string;
240
247
  onLaunch: () => void;
241
248
  }): React.JSX.Element {
242
- const message = '数字员工未运行:当前没有本地 Claude/Agent 进程在运行,已有数据和任务仍会保留。';
249
+ const message = 'Agent 未运行:当前没有本地 Claude/Agent 进程在运行,已有状态和任务仍会保留。';
243
250
 
244
251
  return (
245
252
  <div
@@ -261,7 +268,7 @@ const TeamOfflineStatusBanner = memo(function TeamOfflineStatusBanner({
261
268
  onClick={onLaunch}
262
269
  >
263
270
  <Play size={12} />
264
- 启动数字员工
271
+ 启动 Agent
265
272
  </Button>
266
273
  </div>
267
274
  );
@@ -691,7 +698,7 @@ const LeadContextBridge = memo(function LeadContextBridge({
691
698
  </div>
692
699
  <div className="flex flex-1 items-center justify-center p-4">
693
700
  <p className="text-xs text-[var(--color-text-muted)]">
694
- {leadSessionLoading ? '正在加载上下文…' : '打开团队负责人会话后可查看上下文。'}
701
+ {leadSessionLoading ? '正在加载上下文…' : '打开 Lead 会话后可查看上下文。'}
695
702
  </p>
696
703
  </div>
697
704
  </div>
@@ -898,11 +905,6 @@ function getCommandForHarness(harness?: string): string {
898
905
  }
899
906
  }
900
907
 
901
- /** All CcAgentType values run as local CLI agents */
902
- function isLocalHarness(harness?: string): boolean {
903
- return !!harness;
904
- }
905
-
906
908
  export const TeamDetailView = ({
907
909
  teamName,
908
910
  isPaneFocused = false,
@@ -934,11 +936,8 @@ export const TeamDetailView = ({
934
936
  mode: 'launch',
935
937
  });
936
938
  const [editorOpen, setEditorOpen] = useState(false);
937
- const [terminalHeight, setTerminalHeight] = useState(400);
938
939
  const contentRef = useRef<HTMLDivElement>(null);
939
940
  const provisioningBannerRef = useRef<HTMLDivElement>(null);
940
- const terminalPaneRef = useRef<TerminalPaneRef>(null);
941
- const terminalSpawnedForTeamRef = useRef<string | null>(null);
942
941
  const wasProvisioningRef = useRef(false);
943
942
 
944
943
  // Set inert on background content when editor overlay is open (a11y focus trap)
@@ -969,10 +968,7 @@ export const TeamDetailView = ({
969
968
  setSendDialogOpen(true);
970
969
  };
971
970
  const onOpenProfile = (e: Event) => {
972
- const {
973
- teamName: tn,
974
- memberName,
975
- } = (e as CustomEvent).detail ?? {};
971
+ const { teamName: tn, memberName } = (e as CustomEvent).detail ?? {};
976
972
  if (tn !== teamName || !data) return;
977
973
  const member = members.find((m: { name: string }) => m.name === memberName);
978
974
  if (member) {
@@ -998,9 +994,9 @@ export const TeamDetailView = ({
998
994
  const onStartTask = taskAction((taskId) => {
999
995
  void (async () => {
1000
996
  try {
997
+ const task = data?.tasks.find((t: { id: string }) => t.id === taskId);
1001
998
  const result = await startTaskByUser(teamName, taskId);
1002
- if (data?.isAlive) {
1003
- const task = data.tasks.find((t: { id: string }) => t.id === taskId);
999
+ if (data?.isAlive && !task?.dispatchMeta) {
1004
1000
  try {
1005
1001
  if (result.notifiedOwner && task?.owner) {
1006
1002
  await api.teams.processSend(
@@ -1018,6 +1014,8 @@ export const TeamDetailView = ({
1018
1014
  })();
1019
1015
  });
1020
1016
  const onCompleteTask = taskAction((taskId) => {
1017
+ const task = data?.tasks.find((t: { id: string }) => t.id === taskId);
1018
+ if (task?.status === 'in_progress') return;
1021
1019
  void (async () => {
1022
1020
  try {
1023
1021
  await updateTaskStatus(teamName, taskId, 'completed');
@@ -1036,6 +1034,8 @@ export const TeamDetailView = ({
1036
1034
  })();
1037
1035
  });
1038
1036
  const onRequestReviewTask = taskAction((taskId) => {
1037
+ const task = data?.tasks.find((t: { id: string }) => t.id === taskId);
1038
+ if (task?.status === 'in_progress') return;
1039
1039
  void (async () => {
1040
1040
  try {
1041
1041
  await requestReview(teamName, taskId);
@@ -1048,6 +1048,8 @@ export const TeamDetailView = ({
1048
1048
  setRequestChangesTaskId(taskId);
1049
1049
  });
1050
1050
  const onCancelTask = taskAction((taskId) => {
1051
+ const task = data?.tasks.find((t: { id: string }) => t.id === taskId);
1052
+ if (task?.status === 'in_progress') return;
1051
1053
  void (async () => {
1052
1054
  try {
1053
1055
  await updateTaskStatus(teamName, taskId, 'pending');
@@ -1066,7 +1068,11 @@ export const TeamDetailView = ({
1066
1068
  }
1067
1069
  })();
1068
1070
  });
1069
- const onDeleteTaskGraph = taskAction((taskId) => handleDeleteTask(taskId));
1071
+ const onDeleteTaskGraph = taskAction((taskId) => {
1072
+ const task = data?.tasks.find((t: { id: string }) => t.id === taskId);
1073
+ if (task?.status === 'in_progress') return;
1074
+ handleDeleteTask(taskId);
1075
+ });
1070
1076
 
1071
1077
  window.addEventListener('graph:start-task', onStartTask);
1072
1078
  window.addEventListener('graph:complete-task', onCompleteTask);
@@ -1187,6 +1193,8 @@ export const TeamDetailView = ({
1187
1193
  error,
1188
1194
  projects,
1189
1195
  repositoryGroups,
1196
+ fetchSkillsCatalog,
1197
+ mcpFetchInstalled,
1190
1198
  initTabUIState,
1191
1199
  selectTeam,
1192
1200
  updateKanban,
@@ -1229,11 +1237,16 @@ export const TeamDetailView = ({
1229
1237
  pendingReviewRequest,
1230
1238
  setPendingReviewRequest,
1231
1239
  teams,
1240
+ teamSummaryDisplayName,
1232
1241
  fetchTeams,
1242
+ leadActivity,
1243
+ leadContextUpdatedAt,
1233
1244
  } = useStore(
1234
1245
  useShallow((s) => ({
1235
1246
  projects: s.projects,
1236
1247
  repositoryGroups: s.repositoryGroups,
1248
+ fetchSkillsCatalog: s.fetchSkillsCatalog,
1249
+ mcpFetchInstalled: s.mcpFetchInstalled,
1237
1250
  initTabUIState: s.initTabUIState,
1238
1251
  selectTeam: s.selectTeam,
1239
1252
  updateKanban: s.updateKanban,
@@ -1280,7 +1293,10 @@ export const TeamDetailView = ({
1280
1293
  pendingReviewRequest: s.pendingReviewRequest,
1281
1294
  setPendingReviewRequest: s.setPendingReviewRequest,
1282
1295
  teams: s.teams,
1296
+ teamSummaryDisplayName: teamName ? s.teamByName[teamName]?.displayName : undefined,
1283
1297
  fetchTeams: s.fetchTeams,
1298
+ leadActivity: teamName ? s.leadActivityByTeam[teamName] : undefined,
1299
+ leadContextUpdatedAt: teamName ? s.leadContextByTeam[teamName]?.updatedAt : undefined,
1284
1300
  }))
1285
1301
  );
1286
1302
 
@@ -1305,6 +1321,14 @@ export const TeamDetailView = ({
1305
1321
  setTeamPendingRepliesState(teamName, pendingRepliesByMember);
1306
1322
  }, [pendingRepliesByMember, teamName]);
1307
1323
 
1324
+ useEffect(() => {
1325
+ const projectPath = data?.config.projectPath;
1326
+ void fetchSkillsCatalog(projectPath ?? undefined);
1327
+ if (projectPath) {
1328
+ void mcpFetchInstalled(projectPath);
1329
+ }
1330
+ }, [data?.config.projectPath, fetchSkillsCatalog, mcpFetchInstalled]);
1331
+
1308
1332
  useEffect(() => {
1309
1333
  const wasProvisioning = wasProvisioningRef.current;
1310
1334
  wasProvisioningRef.current = isTeamProvisioning;
@@ -1331,24 +1355,6 @@ export const TeamDetailView = ({
1331
1355
  void fetchDeletedTasks(teamName);
1332
1356
  }, [teamName, selectTeam, fetchDeletedTasks]);
1333
1357
 
1334
- // Spawn terminal PTY once per team — imperative, no autoSpawn.
1335
- // TerminalPane lives outside renderBody() so it never unmounts on data refresh.
1336
- // terminalSpawnedForTeamRef guards against re-spawning on data changes.
1337
- useEffect(() => {
1338
- if (!data || !teamName || teamName === SYSTEM_MANAGER_TEAM_NAME) return;
1339
- const cwd = data.config.projectPath || data.config.executionTarget?.cwd || data.workDir || '';
1340
- if (!cwd) return;
1341
- const harness = data.config.agentType || data.harness;
1342
- const spawnKey = `${teamName}:${harness ?? ''}`;
1343
- if (terminalSpawnedForTeamRef.current === spawnKey) return;
1344
- terminalSpawnedForTeamRef.current = spawnKey;
1345
- void terminalPaneRef.current?.spawn({
1346
- command: getCommandForHarness(harness),
1347
- args: [],
1348
- cwd,
1349
- });
1350
- }, [data, teamName]);
1351
-
1352
1358
  // Recovery: after HMR, all mounted TeamDetailView effects re-run simultaneously.
1353
1359
  // With CSS display-toggle (all tabs stay mounted), the last selectTeam() call wins
1354
1360
  // and other tabs get stuck with mismatched data (permanent skeleton).
@@ -1716,21 +1722,8 @@ export const TeamDetailView = ({
1716
1722
  }, []);
1717
1723
 
1718
1724
  const handleRestartTeam = useCallback(() => {
1719
- const cfg = data?.config;
1720
- const harness = cfg?.agentType || data?.harness;
1721
- if (isLocalHarness(harness)) {
1722
- const cwd = cfg?.projectPath || cfg?.executionTarget?.cwd || data?.workDir || '';
1723
- if (cwd) {
1724
- terminalPaneRef.current?.spawn({
1725
- command: getCommandForHarness(harness),
1726
- args: [],
1727
- cwd,
1728
- });
1729
- return;
1730
- }
1731
- }
1732
1725
  openLaunchDialog('relaunch');
1733
- }, [data, openLaunchDialog]);
1726
+ }, [openLaunchDialog]);
1734
1727
 
1735
1728
  const handleStartCcConnectTeam = useCallback(() => {
1736
1729
  void (async () => {
@@ -1924,6 +1917,8 @@ export const TeamDetailView = ({
1924
1917
 
1925
1918
  const handleDeleteTask = useCallback(
1926
1919
  (taskId: string) => {
1920
+ const task = taskMapRef.current.get(taskId);
1921
+ if (task?.status === 'in_progress') return;
1927
1922
  void (async () => {
1928
1923
  const confirmed = await confirm({
1929
1924
  title: '删除任务',
@@ -2054,6 +2049,7 @@ export const TeamDetailView = ({
2054
2049
  pendingRepliesByMember,
2055
2050
  onPendingReplyChange: setPendingRepliesByMember,
2056
2051
  onMemberClick: handleSelectMember,
2052
+ onTaskIdClick: handleTaskIdClick,
2057
2053
  onReplyToMessage: handleReplyToMessage,
2058
2054
  onRestartTeam: handleRestartTeam,
2059
2055
  inlineScrollContainerRef: contentRef,
@@ -2068,6 +2064,7 @@ export const TeamDetailView = ({
2068
2064
  handleReplyToMessage,
2069
2065
  handleRestartTeam,
2070
2066
  handleSelectMember,
2067
+ handleTaskIdClick,
2071
2068
  pendingRepliesByMember,
2072
2069
  teamName,
2073
2070
  timeWindow,
@@ -2133,35 +2130,38 @@ export const TeamDetailView = ({
2133
2130
  const draftTeamSummary = useStore.getState().teamByName[teamName];
2134
2131
  const draftDisplayName = draftTeamSummary?.displayName || teamName;
2135
2132
  const draftCwd = draftTeamSummary?.projectPath || draftTeamSummary?.workDir || '';
2133
+ const draftCommand = getCommandForHarness(draftTeamSummary?.harness);
2136
2134
 
2137
2135
  return (
2138
- <>
2139
- <div className="size-full overflow-auto p-6">
2140
- <div ref={provisioningBannerRef}>
2141
- <TeamProvisioningBanner teamName={teamName} />
2142
- </div>
2143
- <div className="flex items-center gap-3 py-2">
2136
+ <div className="size-full overflow-auto p-6">
2137
+ <div ref={provisioningBannerRef}>
2138
+ <TeamProvisioningBanner teamName={teamName} />
2139
+ </div>
2140
+ <div className="mt-4 rounded-2xl border border-[var(--color-border)] bg-[var(--color-surface-raised)] p-5">
2141
+ <div className="flex flex-wrap items-center gap-3">
2144
2142
  <p className="text-sm font-medium text-text">{draftDisplayName}</p>
2145
2143
  <span className="rounded-full bg-indigo-500/20 px-2 py-0.5 text-[10px] font-medium text-indigo-400">
2146
- {getCommandForHarness()}
2144
+ {draftCommand}
2147
2145
  </span>
2148
2146
  </div>
2149
- <div className="h-[calc(100vh-16rem)] overflow-hidden rounded-lg border border-[var(--color-border-subtle)]">
2150
- <TerminalPane
2151
- ref={terminalPaneRef}
2152
- autoSpawn={
2153
- draftCwd
2154
- ? {
2155
- command: getCommandForHarness(),
2156
- args: [],
2157
- cwd: draftCwd,
2158
- }
2159
- : undefined
2160
- }
2161
- />
2162
- </div>
2147
+ <p className="mt-3 max-w-2xl text-sm leading-6 text-[var(--color-text-secondary)]">
2148
+ 终端不再嵌入页面。需要接管这个工作区时,请在系统终端中打开默认 CLI。
2149
+ </p>
2150
+ <Button
2151
+ size="sm"
2152
+ variant="outline"
2153
+ className="mt-4"
2154
+ disabled={!draftCwd}
2155
+ onClick={() => {
2156
+ if (!draftCwd) return;
2157
+ void api.terminal.openExternal({ command: draftCommand, cwd: draftCwd });
2158
+ }}
2159
+ >
2160
+ <Play size={13} />
2161
+ 在系统终端打开
2162
+ </Button>
2163
2163
  </div>
2164
- </>
2164
+ </div>
2165
2165
  );
2166
2166
  }
2167
2167
 
@@ -2198,6 +2198,11 @@ export const TeamDetailView = ({
2198
2198
  );
2199
2199
  }
2200
2200
 
2201
+ // Prefer the store summary's displayName over data.config.name: for a draft or
2202
+ // partially-provisioned team (no team.json on disk) the server-side getData falls
2203
+ // back to the slug for config.name, but the user-facing name survives in teamByName.
2204
+ const displayTeamName = teamSummaryDisplayName || data.config.name || teamName;
2205
+
2201
2206
  const headerColorSet = data.config.color
2202
2207
  ? getTeamColorSet(data.config.color)
2203
2208
  : nameColorSet(data.config.name);
@@ -2235,17 +2240,19 @@ export const TeamDetailView = ({
2235
2240
  <div className="min-w-0 flex-1">
2236
2241
  <div className="flex items-center gap-2">
2237
2242
  <h2 className="text-base font-semibold text-[var(--color-text)]">
2238
- {data.config.name}
2243
+ {displayTeamName}
2239
2244
  </h2>
2240
- {data.platforms?.filter((pl) => pl.type !== 'bridge').map((pl) => (
2241
- <span
2242
- key={pl.type}
2243
- className="inline-flex items-center gap-1 rounded-full bg-emerald-500/15 px-1.5 py-0.5 text-[10px] font-medium text-emerald-400"
2244
- >
2245
- <span className="size-1.5 rounded-full bg-emerald-400" />
2246
- {pl.type}
2247
- </span>
2248
- ))}
2245
+ {data.platforms
2246
+ ?.filter((pl) => pl.type !== 'bridge')
2247
+ .map((pl) => (
2248
+ <span
2249
+ key={pl.type}
2250
+ className="inline-flex items-center gap-1 rounded-full bg-emerald-500/15 px-1.5 py-0.5 text-[10px] font-medium text-emerald-400"
2251
+ >
2252
+ <span className="size-1.5 rounded-full bg-emerald-400" />
2253
+ {pl.type}
2254
+ </span>
2255
+ ))}
2249
2256
  {isTeamProvisioning && (
2250
2257
  <span className="inline-flex items-center gap-1 rounded-full bg-yellow-500/15 px-1.5 py-0.5 text-[10px] font-medium text-yellow-400">
2251
2258
  <span className="size-1.5 animate-pulse rounded-full bg-yellow-400" />
@@ -2324,22 +2331,18 @@ export const TeamDetailView = ({
2324
2331
  )}
2325
2332
  >
2326
2333
  <div className="flex min-w-0 flex-1 flex-wrap items-center gap-x-3 gap-y-0.5">
2327
- {data.config.projectPath && (
2334
+ {data.teamName && (
2328
2335
  <span className="flex items-center gap-1 text-[11px] text-[var(--color-text-secondary)]">
2329
2336
  <FolderOpen size={11} className="shrink-0 text-[var(--color-text-muted)]" />
2330
2337
  <Tooltip>
2331
2338
  <TooltipTrigger asChild>
2332
- <span className="max-w-60 truncate font-mono">
2333
- {data.config.projectPath
2334
- .replace(/\\/g, '/')
2335
- .split('/')
2336
- .filter(Boolean)
2337
- .pop() ?? data.config.projectPath}
2338
- </span>
2339
+ <span className="max-w-60 truncate font-mono">@{data.teamName}</span>
2339
2340
  </TooltipTrigger>
2340
2341
  <TooltipContent side="bottom">
2341
2342
  <span className="font-mono text-xs">
2342
- {formatProjectPath(data.config.projectPath)}
2343
+ {data.config.projectPath
2344
+ ? formatProjectPath(data.config.projectPath)
2345
+ : data.teamName}
2343
2346
  </span>
2344
2347
  </TooltipContent>
2345
2348
  </Tooltip>
@@ -2417,7 +2420,7 @@ export const TeamDetailView = ({
2417
2420
  title="会话"
2418
2421
  icon={<MessageSquare size={14} />}
2419
2422
  badge={ccSessions.length}
2420
- defaultOpen={ccSessions.length > 0}
2423
+ defaultOpen={false}
2421
2424
  action={
2422
2425
  ccSessions.length > 0 ? (
2423
2426
  <button
@@ -2496,6 +2499,8 @@ export const TeamDetailView = ({
2496
2499
  />
2497
2500
  }
2498
2501
  onRequestReview={(taskId) => {
2502
+ const task = taskMapRef.current.get(taskId);
2503
+ if (task?.status === 'in_progress') return;
2499
2504
  void (async () => {
2500
2505
  try {
2501
2506
  await requestReview(teamName, taskId);
@@ -2532,9 +2537,9 @@ export const TeamDetailView = ({
2532
2537
  onStartTask={(taskId) => {
2533
2538
  void (async () => {
2534
2539
  try {
2540
+ const task = data?.tasks.find((t) => t.id === taskId);
2535
2541
  const result = await startTaskByUser(teamName, taskId);
2536
- if (data?.isAlive) {
2537
- const task = data.tasks.find((t) => t.id === taskId);
2542
+ if (data?.isAlive && !task?.dispatchMeta) {
2538
2543
  try {
2539
2544
  if (result.notifiedOwner && task?.owner) {
2540
2545
  await api.teams.processSend(
@@ -2560,6 +2565,8 @@ export const TeamDetailView = ({
2560
2565
  })();
2561
2566
  }}
2562
2567
  onCompleteTask={(taskId) => {
2568
+ const task = taskMapRef.current.get(taskId);
2569
+ if (task?.status === 'in_progress') return;
2563
2570
  void (async () => {
2564
2571
  try {
2565
2572
  await updateTaskStatus(teamName, taskId, 'completed');
@@ -2572,6 +2579,7 @@ export const TeamDetailView = ({
2572
2579
  void (async () => {
2573
2580
  try {
2574
2581
  const task = data?.tasks.find((t) => t.id === taskId);
2582
+ if (task?.status === 'in_progress') return;
2575
2583
  await updateTaskStatus(teamName, taskId, 'pending');
2576
2584
 
2577
2585
  if (task?.owner) {
@@ -2668,6 +2676,34 @@ export const TeamDetailView = ({
2668
2676
  </CollapsibleTeamSection>
2669
2677
  )}
2670
2678
 
2679
+ <CollapsibleTeamSection
2680
+ sectionId="loop-console"
2681
+ title="指令台"
2682
+ icon={<MessageSquare size={14} />}
2683
+ badge={data.isAlive ? 'online' : 'offline'}
2684
+ defaultOpen
2685
+ >
2686
+ <LoopConsolePanel
2687
+ teamName={teamName}
2688
+ members={activeMembers}
2689
+ tasks={data.tasks}
2690
+ isTeamAlive={data.isAlive}
2691
+ isProvisioning={isTeamProvisioning}
2692
+ leadActivity={leadActivity}
2693
+ leadContextUpdatedAt={leadContextUpdatedAt}
2694
+ currentLeadSessionId={data.config.leadSessionId}
2695
+ leadProjectPath={data.config.projectPath}
2696
+ sessions={ccSessions}
2697
+ pendingRepliesByMember={pendingRepliesByMember}
2698
+ onPendingReplyChange={setPendingRepliesByMember}
2699
+ onMemberClick={handleSelectMember}
2700
+ onTaskClick={handleOpenTask}
2701
+ onReplyToMessage={handleReplyToMessage}
2702
+ onRestartTeam={handleRestartTeam}
2703
+ onTaskIdClick={handleTaskIdClick}
2704
+ />
2705
+ </CollapsibleTeamSection>
2706
+
2671
2707
  <ReviewDialog
2672
2708
  open={requestChangesTaskId !== null}
2673
2709
  teamName={teamName}
@@ -2755,7 +2791,7 @@ export const TeamDetailView = ({
2755
2791
  <DialogHeader>
2756
2792
  <DialogTitle>移除成员</DialogTitle>
2757
2793
  <DialogDescription>
2758
- 确认将 &ldquo;{removeMemberConfirm}&rdquo; 从团队中移除?任务与消息会保留,
2794
+ 确认将 &ldquo;{removeMemberConfirm}&rdquo; 从团队中移除?任务与 动态会保留,
2759
2795
  但该名称将无法再次使用。
2760
2796
  </DialogDescription>
2761
2797
  </DialogHeader>
@@ -2789,7 +2825,7 @@ export const TeamDetailView = ({
2789
2825
  <DialogHeader>
2790
2826
  <DialogTitle>删除团队</DialogTitle>
2791
2827
  <DialogDescription>
2792
- 确认删除团队 &ldquo;{data.config.name}
2828
+ 确认删除团队 &ldquo;{displayTeamName}
2793
2829
  &rdquo;?此操作不可恢复,所有团队数据与任务都将被删除。
2794
2830
  </DialogDescription>
2795
2831
  </DialogHeader>
@@ -2924,59 +2960,7 @@ export const TeamDetailView = ({
2924
2960
  {teamAgentRuntimeWatcher}
2925
2961
  {leadContextWatcher}
2926
2962
  <div className="flex size-full flex-col overflow-hidden">
2927
- <div className="min-h-0 flex-1 overflow-hidden">
2928
- {renderBody()}
2929
- </div>
2930
- {/* Persistent terminal — survives data refreshes because it's outside renderBody() */}
2931
- {teamName && teamName !== SYSTEM_MANAGER_TEAM_NAME && (
2932
- <div className="shrink-0" style={{ height: terminalHeight }}>
2933
- {/* Drag handle */}
2934
- <div
2935
- className="flex cursor-row-resize items-center justify-center border-t border-[var(--color-border)] py-0.5 transition-colors hover:bg-[var(--color-surface-raised)]"
2936
- onMouseDown={(e) => {
2937
- e.preventDefault();
2938
- const startY = e.clientY;
2939
- const startH = terminalHeight;
2940
- const onMove = (ev: MouseEvent) => {
2941
- const delta = startY - ev.clientY; // drag up = grow
2942
- const next = Math.max(120, Math.min(800, startH + delta));
2943
- setTerminalHeight(next);
2944
- };
2945
- const onUp = () => {
2946
- window.removeEventListener('mousemove', onMove);
2947
- window.removeEventListener('mouseup', onUp);
2948
- };
2949
- window.addEventListener('mousemove', onMove);
2950
- window.addEventListener('mouseup', onUp);
2951
- }}
2952
- >
2953
- <div className="h-1 w-8 rounded-full bg-[var(--color-border)]" />
2954
- </div>
2955
- <div className="h-[calc(100%-14px)] overflow-hidden">
2956
- <div className="flex items-center justify-between px-1 pb-1">
2957
- <div className="flex items-center gap-1.5 text-xs font-medium text-[var(--color-text-secondary)]">
2958
- <Terminal size={14} />
2959
- 终端
2960
- </div>
2961
- <button
2962
- type="button"
2963
- className="flex items-center gap-1 rounded px-1 py-0.5 text-[10px] text-[var(--color-text-muted)] transition-colors hover:bg-[var(--color-surface-raised)] hover:text-[var(--color-text-secondary)]"
2964
- onClick={() => {
2965
- const cwd = data?.config.projectPath || data?.config.executionTarget?.cwd || data?.workDir || '';
2966
- const harness = data?.config.agentType || data?.harness;
2967
- void api.terminal.openExternal({ command: getCommandForHarness(harness), cwd });
2968
- }}
2969
- >
2970
- <Play size={10} />
2971
- 外部终端
2972
- </button>
2973
- </div>
2974
- <div className="h-[calc(100%-22px)] overflow-hidden rounded-lg border border-[var(--color-border-subtle)]">
2975
- <TerminalPane ref={terminalPaneRef} />
2976
- </div>
2977
- </div>
2978
- </div>
2979
- )}
2963
+ <div className="min-h-0 flex-1 overflow-hidden">{renderBody()}</div>
2980
2964
  </div>
2981
2965
  {data && teamName !== SYSTEM_MANAGER_TEAM_NAME ? (
2982
2966
  <RuntimeConfigDialog
@@ -1,6 +1,9 @@
1
1
  import { Button } from '@renderer/components/ui/button';
2
+
3
+ import { AGENT_TYPE_LABELS, ALL_AGENT_TYPES } from './HarnessCards';
4
+ import { HarnessIcon } from './HarnessSelect';
5
+
2
6
  import type { CcAgentType } from '@shared/types/ccConnect';
3
- import { ALL_AGENT_TYPES, AGENT_TYPE_LABELS } from './HarnessCards';
4
7
 
5
8
  interface TeamEmptyStateProps {
6
9
  canCreate: boolean;
@@ -31,9 +34,9 @@ export const TeamEmptyState = ({
31
34
  return (
32
35
  <div className="flex size-full flex-col items-center justify-center gap-6 px-6">
33
36
  <div className="text-center">
34
- <p className="text-lg font-medium text-[var(--color-text)]">还没有数字员工</p>
37
+ <p className="text-lg font-medium text-[var(--color-text)]">还没有 Agent runtime</p>
35
38
  <p className="mt-2 text-sm text-[var(--color-text-muted)]">
36
- 选择一种 Agent 类型开始,或创建自定义数字员工。
39
+ 选择一种 Agent 类型启动循环,或创建自定义 runtime。
37
40
  </p>
38
41
  </div>
39
42
 
@@ -51,7 +54,7 @@ export const TeamEmptyState = ({
51
54
  className="flex flex-col items-center gap-1.5 rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] p-3 text-center transition-colors hover:border-[var(--color-border-emphasis)] hover:bg-[var(--color-surface-raised)]"
52
55
  onClick={() => onSelectHarness(type)}
53
56
  >
54
- <span className="text-lg">{getHarnessIcon(type)}</span>
57
+ <HarnessIcon type={type} className="size-6" />
55
58
  <span className="text-xs font-medium text-[var(--color-text)]">
56
59
  {AGENT_TYPE_LABELS[type]}
57
60
  </span>
@@ -71,43 +74,12 @@ export const TeamEmptyState = ({
71
74
  </div>
72
75
 
73
76
  <Button size="sm" disabled={!canCreate} onClick={onCreateTeam}>
74
- 创建自定义数字员工
77
+ 创建自定义 runtime
75
78
  </Button>
76
79
 
77
80
  {!canCreate && (
78
- <p className="text-xs text-[var(--color-text-muted)]">只有本地桌面模式支持创建数字员工。</p>
81
+ <p className="text-xs text-[var(--color-text-muted)]">只有本地桌面模式支持创建 runtime。</p>
79
82
  )}
80
83
  </div>
81
84
  );
82
85
  };
83
-
84
- function getHarnessIcon(type: CcAgentType): string {
85
- switch (type) {
86
- case 'claudecode':
87
- return '🤖';
88
- case 'codex':
89
- return '🔬';
90
- case 'cursor':
91
- return '💻';
92
- case 'gemini':
93
- return '💎';
94
- case 'iflow':
95
- return '🌊';
96
- case 'kimi':
97
- return '🌙';
98
- case 'devin':
99
- return '🧑‍💻';
100
- case 'opencode':
101
- return '🔓';
102
- case 'qoder':
103
- return '⚡';
104
- case 'pi':
105
- return '🥧';
106
- case 'acp':
107
- return '🔗';
108
- case 'tmux':
109
- return '🖥️';
110
- default:
111
- return '📦';
112
- }
113
- }