@yancyyu/openhermit 1.6.41 → 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-Br0X83Jf.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
  4. package/dist-renderer/assets/{TeamGraphOverlay-DHMTbZPZ.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
  5. package/dist-renderer/assets/{_basePickBy-DzIiX7yH.js → _basePickBy-ZOyLWjMK.js} +1 -1
  6. package/dist-renderer/assets/{_baseUniq-6hZuzTLU.js → _baseUniq-DBb726rt.js} +1 -1
  7. package/dist-renderer/assets/{arc-CXgO6fx_.js → arc-CdiTaR_R.js} +1 -1
  8. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DKWgtDHr.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
  9. package/dist-renderer/assets/{blockDiagram-VD42YOAC-DOMUcC40.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
  10. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-B_k2L7qX.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
  11. package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
  12. package/dist-renderer/assets/{chunk-4BX2VUAB-BeD_ccFy.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
  13. package/dist-renderer/assets/{chunk-55IACEB6-ClZfkA5w.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
  14. package/dist-renderer/assets/{chunk-B4BG7PRW-5XluxXsn.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
  15. package/dist-renderer/assets/{chunk-DI55MBZ5-BzIjjNVm.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
  16. package/dist-renderer/assets/{chunk-FMBD7UC4-HgH3MK_H.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QN33PNHL-WeC5T3Ba.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QZHKN3VN-Cu1ApHfW.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
  19. package/dist-renderer/assets/{chunk-TZMSLE5B-BOhlynJM.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-DGZSihDQ.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
  24. package/dist-renderer/assets/{dagre-6UL2VRFP-CnxwCbku.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
  25. package/dist-renderer/assets/{diagram-PSM6KHXK-DsIhoxdI.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
  26. package/dist-renderer/assets/{diagram-QEK2KX5R-Cmh9KUF5.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
  27. package/dist-renderer/assets/{diagram-S2PKOQOG-CKxV456A.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
  28. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-EnvYjOjc.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
  29. package/dist-renderer/assets/{flowDiagram-NV44I4VS-BmNeWY_A.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
  30. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-D30fyK-u.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
  31. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-CrUNiYg1.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
  32. package/dist-renderer/assets/{graph-CY1gTfTb.js → graph-CDP_R8ct.js} +1 -1
  33. package/dist-renderer/assets/{index-CaEbzwAU.js → index-BSZdT-g-.js} +1 -1
  34. package/dist-renderer/assets/{index-D5K-SjBG.js → index-BhWvMqsz.js} +1 -1
  35. package/dist-renderer/assets/{index-9_hO4N1e.js → index-C2_AupSj.js} +1 -1
  36. package/dist-renderer/assets/{index-59r209c1.js → index-C5ujiwAR.js} +580 -588
  37. package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
  38. package/dist-renderer/assets/{index-DMR9B1UP.js → index-CVNjLwkq.js} +1 -1
  39. package/dist-renderer/assets/{index-BC2hXmg_.js → index-CwG3se0q.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-By_XUlcD.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BM1LJE9m.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-DHIW3aTA.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
  43. package/dist-renderer/assets/{layout-DAKiL_Mo.js → layout-5nA5wUxO.js} +1 -1
  44. package/dist-renderer/assets/{linear-DwOaRYea.js → linear-BtF1i2qN.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-b7bJ2cha.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-DxyL9Zr2.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CR33pHlF.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BAiSRSlh.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-C8JmDjoa.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-c1d0Wi1m.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-nT8BiH2O.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-DpoRepUA.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
  55. package/dist-renderer/assets/{treemap-GDKQZRPO-C41UJeIH.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
  56. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-KMjGARKN.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 +1731 -539
  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 +744 -0
  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 +132 -52
  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 +144 -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 +189 -57
  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 +43 -3
  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-D0XS_akr.js +0 -1
  274. package/dist-renderer/assets/classDiagram-2ON5EDUG-D13Ffs0U.js +0 -1
  275. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-D13Ffs0U.js +0 -1
  276. package/dist-renderer/assets/clone-B1ZrxI1D.js +0 -1
  277. package/dist-renderer/assets/index-iyjkpSus.css +0 -32
  278. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-Dmibmlso.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
@@ -274,6 +274,33 @@ const PendingDeleteBadge = (): React.JSX.Element => (
274
274
  </span>
275
275
  );
276
276
 
277
+ const TeamListSkeleton = (): React.JSX.Element => (
278
+ <div className="grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3">
279
+ {Array.from({ length: 9 }).map((_, index) => (
280
+ <div
281
+ key={index}
282
+ className="rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] p-4"
283
+ >
284
+ <div className="flex items-center gap-2.5">
285
+ <div className="skeleton-shimmer size-8 rounded-md bg-[var(--skeleton-base)]" />
286
+ <div className="min-w-0 flex-1 space-y-2">
287
+ <div className="skeleton-shimmer h-3 w-28 rounded bg-[var(--skeleton-base)]" />
288
+ <div className="skeleton-shimmer h-2.5 w-20 rounded bg-[var(--skeleton-base-dim)]" />
289
+ </div>
290
+ </div>
291
+ <div className="mt-3 space-y-2 pl-[42px]">
292
+ <div className="skeleton-shimmer h-2.5 w-3/4 rounded bg-[var(--skeleton-base-dim)]" />
293
+ <div className="flex gap-2">
294
+ <div className="skeleton-shimmer h-2.5 w-16 rounded bg-[var(--skeleton-base)]" />
295
+ <div className="skeleton-shimmer h-2.5 w-14 rounded bg-[var(--skeleton-base-dim)]" />
296
+ <div className="skeleton-shimmer h-2.5 w-12 rounded bg-[var(--skeleton-base-dim)]" />
297
+ </div>
298
+ </div>
299
+ </div>
300
+ ))}
301
+ </div>
302
+ );
303
+
277
304
  export const TeamListView = (): React.JSX.Element => {
278
305
  const { isLight } = useTheme();
279
306
  const [showCreateDialog, setShowCreateDialog] = useState(false);
@@ -288,6 +315,7 @@ export const TeamListView = (): React.JSX.Element => {
288
315
  const [filter, setFilter] = useState<TeamListFilterState>(EMPTY_TEAM_FILTER);
289
316
  const [deletingTeamName, setDeletingTeamName] = useState<string | null>(null);
290
317
  const [aliveTeams, setAliveTeams] = useState<string[]>([]);
318
+ const [statsWarmupRequested, setStatsWarmupRequested] = useState(false);
291
319
  const {
292
320
  teams,
293
321
  teamsLoading,
@@ -372,6 +400,37 @@ export const TeamListView = (): React.JSX.Element => {
372
400
  return synthetic.length > 0 ? [...teams, ...synthetic] : teams;
373
401
  }, [teams, provisioningTeamNames, provisioningSnapshotByTeam]);
374
402
 
403
+ const teamListStats = useMemo(() => {
404
+ const activeTeams = teamsWithProvisioning.filter((team) => !team.deletedAt);
405
+ const aliveSet = new Set(aliveTeams);
406
+ return activeTeams.reduce(
407
+ (acc, team) => {
408
+ acc.teams += 1;
409
+ if (aliveSet.has(team.teamName)) acc.running += 1;
410
+ acc.sessions += team.stats?.sessions ?? 0;
411
+ acc.messages += team.stats?.messages ?? 0;
412
+ acc.tokens += team.stats?.tokens ?? 0;
413
+ acc.durationMs += team.stats?.durationMs ?? 0;
414
+ return acc;
415
+ },
416
+ { teams: 0, running: 0, sessions: 0, messages: 0, tokens: 0, durationMs: 0 }
417
+ );
418
+ }, [teamsWithProvisioning, aliveTeams]);
419
+
420
+ useEffect(() => {
421
+ if (statsWarmupRequested || teamsLoading || teamsWithProvisioning.length === 0) return;
422
+ if (teamListStats.sessions > 0 || teamListStats.messages > 0 || teamListStats.tokens > 0)
423
+ return;
424
+
425
+ setStatsWarmupRequested(true);
426
+ const firstRefresh = window.setTimeout(() => void fetchTeams(), 1200);
427
+ const secondRefresh = window.setTimeout(() => void fetchTeams(), 3500);
428
+ return () => {
429
+ window.clearTimeout(firstRefresh);
430
+ window.clearTimeout(secondRefresh);
431
+ };
432
+ }, [fetchTeams, statsWarmupRequested, teamListStats, teamsLoading, teamsWithProvisioning.length]);
433
+
375
434
  // Fetch alive teams on mount and when teams list changes
376
435
  useEffect(() => {
377
436
  let cancelled = false;
@@ -453,7 +512,6 @@ export const TeamListView = (): React.JSX.Element => {
453
512
  });
454
513
  }
455
514
 
456
- const aliveSet = new Set(aliveTeams);
457
515
  const matchesCurrentProject = currentProjectPath
458
516
  ? (team: TeamSummary): boolean => teamMatchesProjectSelection(team, currentProjectPath)
459
517
  : null;
@@ -464,24 +522,21 @@ export const TeamListView = (): React.JSX.Element => {
464
522
  const managerB = b.teamName === SYSTEM_MANAGER_TEAM_NAME ? 0 : 1;
465
523
  if (managerA !== managerB) return managerA - managerB;
466
524
 
467
- // 1. Alive (running) teams first
468
- const aliveA = aliveSet.has(a.teamName) ? 0 : 1;
469
- const aliveB = aliveSet.has(b.teamName) ? 0 : 1;
470
- if (aliveA !== aliveB) return aliveA - aliveB;
471
-
472
- // 2. Teams related to the selected project are prioritized next
525
+ // 1. Teams related to the selected project are prioritized next.
473
526
  if (matchesCurrentProject) {
474
527
  const projectA = matchesCurrentProject(a) ? 0 : 1;
475
528
  const projectB = matchesCurrentProject(b) ? 0 : 1;
476
529
  if (projectA !== projectB) return projectA - projectB;
477
530
  }
478
531
 
479
- // 3. Most recently active teams first (stable secondary sort)
532
+ // 2. Most recently active teams first.
480
533
  const tsA = a.lastActivity ? new Date(a.lastActivity).getTime() : 0;
481
534
  const tsB = b.lastActivity ? new Date(b.lastActivity).getTime() : 0;
482
535
  if (tsA !== tsB) return tsB - tsA;
483
536
 
484
- // 4. Fallback: alphabetical by team name for deterministic order
537
+ // 3. Fallback: alphabetical by team name for deterministic order.
538
+ // Runtime liveness is intentionally not part of ordering: aliveTeams is
539
+ // loaded asynchronously after mount, and sorting by it makes cards jump on refresh.
485
540
  return a.teamName.localeCompare(b.teamName);
486
541
  });
487
542
 
@@ -840,6 +895,8 @@ export const TeamListView = (): React.JSX.Element => {
840
895
  provisioningErrorsByTeam={provisioningErrorByTeam}
841
896
  clearProvisioningError={clearProvisioningError}
842
897
  existingTeamNames={teams.map((t) => t.teamName)}
898
+ existingBindProjects={teams.map((t) => t.bindProject).filter(Boolean) as string[]}
899
+ existingDisplayNames={teams.map((t) => t.displayName).filter(Boolean) as string[]}
843
900
  provisioningTeamNames={provisioningTeamNames}
844
901
  activeTeams={activeTeams}
845
902
  initialData={copyData ?? undefined}
@@ -974,7 +1031,7 @@ export const TeamListView = (): React.JSX.Element => {
974
1031
  {template.members.map((member) => (
975
1032
  <span
976
1033
  key={member.name}
977
- className="rounded bg-indigo-500/10 px-1.5 py-0.5 text-[10px] text-indigo-300"
1034
+ className="rounded bg-[var(--color-accent-soft)] px-1.5 py-0.5 text-[10px] text-[var(--color-accent)]"
978
1035
  >
979
1036
  {member.name}
980
1037
  {member.role ? ` · ${formatTeamRoleLabel(member.role)}` : ''}
@@ -1013,10 +1070,10 @@ export const TeamListView = (): React.JSX.Element => {
1013
1070
  <Button
1014
1071
  variant="outline"
1015
1072
  size="sm"
1016
- className="border-cyan-500/30 text-cyan-300 hover:bg-cyan-500/10"
1073
+ className="border-[var(--color-accent-border)] text-[var(--color-accent)] hover:bg-[var(--color-accent-soft)]"
1017
1074
  onClick={() => void openSystemManager()}
1018
1075
  >
1019
- 控制台
1076
+ Helm Loop
1020
1077
  </Button>
1021
1078
  <Button
1022
1079
  variant="outline"
@@ -1029,6 +1086,41 @@ export const TeamListView = (): React.JSX.Element => {
1029
1086
  </div>
1030
1087
  </div>
1031
1088
 
1089
+ {teamsWithProvisioning.length > 0 ? (
1090
+ <div className="mt-3 grid grid-cols-2 gap-2 md:grid-cols-6">
1091
+ {[
1092
+ {
1093
+ label: '数字员工',
1094
+ value: String(teamListStats.teams),
1095
+ tone: 'text-[var(--color-accent)]',
1096
+ },
1097
+ { label: '运行中', value: String(teamListStats.running), tone: 'text-emerald-400' },
1098
+ { label: 'Sessions', value: String(teamListStats.sessions), tone: 'text-sky-400' },
1099
+ { label: 'Messages', value: String(teamListStats.messages), tone: 'text-violet-400' },
1100
+ {
1101
+ label: 'Tokens',
1102
+ value: formatTokensCompact(teamListStats.tokens),
1103
+ tone: 'text-amber-400',
1104
+ },
1105
+ {
1106
+ label: '耗时',
1107
+ value: formatDurationShort(teamListStats.durationMs),
1108
+ tone: 'text-orange-400',
1109
+ },
1110
+ ].map((item) => (
1111
+ <div
1112
+ key={item.label}
1113
+ className="rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] px-3 py-2 duration-200 animate-in fade-in slide-in-from-bottom-1"
1114
+ >
1115
+ <div className={`text-sm font-semibold tabular-nums ${item.tone}`}>{item.value}</div>
1116
+ <div className="mt-0.5 text-[10px] uppercase tracking-wide text-[var(--color-text-muted)]">
1117
+ {item.label}
1118
+ </div>
1119
+ </div>
1120
+ ))}
1121
+ </div>
1122
+ ) : null}
1123
+
1032
1124
  {teamsWithProvisioning.length > 0 ? (
1033
1125
  <div className="mt-3 flex items-center gap-2">
1034
1126
  <div className="relative flex-1">
@@ -1059,11 +1151,7 @@ export const TeamListView = (): React.JSX.Element => {
1059
1151
 
1060
1152
  const renderContent = (): React.JSX.Element => {
1061
1153
  if (teamsLoading) {
1062
- return (
1063
- <div className="flex size-full items-center justify-center text-sm text-[var(--color-text-muted)]">
1064
- 正在加载团队...
1065
- </div>
1066
- );
1154
+ return <TeamListSkeleton />;
1067
1155
  }
1068
1156
 
1069
1157
  if (teamsError) {
@@ -1133,7 +1221,7 @@ export const TeamListView = (): React.JSX.Element => {
1133
1221
  key={team.teamName}
1134
1222
  role="button"
1135
1223
  tabIndex={0}
1136
- className="group relative flex cursor-pointer flex-col overflow-hidden rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] p-4 transition-colors hover:border-[var(--color-border-emphasis)] hover:bg-[var(--color-surface-raised)]"
1224
+ className="group relative flex cursor-pointer flex-col overflow-hidden rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] p-4 transition-all duration-200 animate-in fade-in slide-in-from-bottom-1 hover:-translate-y-0.5 hover:border-[var(--color-border-emphasis)] hover:bg-[var(--color-surface-raised)] hover:shadow-lg"
1137
1225
  onClick={
1138
1226
  isDeleting ? undefined : () => openTeamTab(team.teamName, team.projectPath)
1139
1227
  }
@@ -1165,14 +1253,12 @@ export const TeamListView = (): React.JSX.Element => {
1165
1253
  {team.displayName}
1166
1254
  </h3>
1167
1255
  {isSystemManager ? (
1168
- <span className="shrink-0 rounded bg-cyan-500/15 px-1.5 py-px text-[9px] font-medium text-cyan-400">
1256
+ <span className="shrink-0 rounded bg-[var(--color-accent-soft)] px-1.5 py-px text-[9px] font-medium text-[var(--color-accent)]">
1169
1257
  SYS
1170
1258
  </span>
1171
1259
  ) : null}
1172
1260
  <StatusBadge status={status} />
1173
- {team.pendingDelete || team.restartRequired ? (
1174
- <PendingDeleteBadge />
1175
- ) : null}
1261
+ {team.pendingDelete || team.restartRequired ? <PendingDeleteBadge /> : null}
1176
1262
  {team.projectPath &&
1177
1263
  (() => {
1178
1264
  const branch = branchByPath[normalizePath(team.projectPath)];
@@ -1194,7 +1280,7 @@ export const TeamListView = (): React.JSX.Element => {
1194
1280
  <TooltipTrigger asChild>
1195
1281
  <button
1196
1282
  type="button"
1197
- className="rounded p-1 text-[var(--color-text-muted)] opacity-0 transition-opacity hover:bg-[var(--color-surface-raised)] group-hover:opacity-60 hover:!opacity-100"
1283
+ className="rounded p-1 text-[var(--color-text-muted)] opacity-0 transition-opacity hover:bg-[var(--color-surface-raised)] hover:!opacity-100 group-hover:opacity-60"
1198
1284
  onClick={(e) => handleCopyTeam(team.teamName, e)}
1199
1285
  >
1200
1286
  <Copy size={13} />
@@ -1210,7 +1296,7 @@ export const TeamListView = (): React.JSX.Element => {
1210
1296
  <TooltipTrigger asChild>
1211
1297
  <button
1212
1298
  type="button"
1213
- className="rounded p-1 text-[var(--color-text-muted)] opacity-0 transition-opacity hover:bg-red-500/10 hover:text-red-400 group-hover:opacity-60 hover:!opacity-100"
1299
+ className="rounded p-1 text-[var(--color-text-muted)] opacity-0 transition-opacity hover:bg-red-500/10 hover:text-red-400 hover:!opacity-100 group-hover:opacity-60"
1214
1300
  onClick={(e) =>
1215
1301
  handleDeleteTeam(team.teamName, !!team.pendingCreate, e)
1216
1302
  }
@@ -1230,16 +1316,42 @@ export const TeamListView = (): React.JSX.Element => {
1230
1316
  </p>
1231
1317
 
1232
1318
  {/* Row 3: Stats bar */}
1233
- <div className="mt-2 flex items-center gap-1.5 pl-[42px] text-[10px] tabular-nums">
1234
- {team.stats && team.stats.sessions > 0 ? (
1319
+ <div className="mt-2 flex flex-wrap items-center gap-x-1.5 gap-y-1 pl-[42px] text-[10px] tabular-nums">
1320
+ {team.stats && (team.stats.sessions > 0 || team.stats.messages > 0) ? (
1235
1321
  <>
1236
- <span className="text-indigo-400">{team.stats.sessions} sessions</span>
1322
+ <span className="text-[var(--color-accent)]">
1323
+ {team.stats.sessions} sessions
1324
+ </span>
1237
1325
  <span className="text-[var(--color-text-muted)] opacity-30">·</span>
1238
- <span className="text-emerald-400">{formatTokensCompact(team.stats.tokens)}</span>
1326
+ <span className="text-sky-400">{team.stats.messages} msgs</span>
1327
+ <span className="text-[var(--color-text-muted)] opacity-30">·</span>
1328
+ <span
1329
+ className="text-emerald-400"
1330
+ title={[
1331
+ team.stats.tokensIn !== undefined
1332
+ ? `输入 ${formatTokensCompact(team.stats.tokensIn)}`
1333
+ : null,
1334
+ team.stats.tokensOut !== undefined
1335
+ ? `输出 ${formatTokensCompact(team.stats.tokensOut)}`
1336
+ : null,
1337
+ team.stats.cacheRead !== undefined
1338
+ ? `缓存读 ${formatTokensCompact(team.stats.cacheRead)}`
1339
+ : null,
1340
+ team.stats.cacheCreation !== undefined
1341
+ ? `缓存写 ${formatTokensCompact(team.stats.cacheCreation)}`
1342
+ : null,
1343
+ ]
1344
+ .filter(Boolean)
1345
+ .join(' · ')}
1346
+ >
1347
+ {formatTokensCompact(team.stats.tokens)} tokens
1348
+ </span>
1239
1349
  {team.stats.durationMs > 0 && (
1240
1350
  <>
1241
1351
  <span className="text-[var(--color-text-muted)] opacity-30">·</span>
1242
- <span className="text-amber-400">{formatDurationShort(team.stats.durationMs)}</span>
1352
+ <span className="text-amber-400">
1353
+ {formatDurationShort(team.stats.durationMs)}
1354
+ </span>
1243
1355
  </>
1244
1356
  )}
1245
1357
  </>
@@ -1249,7 +1361,9 @@ export const TeamListView = (): React.JSX.Element => {
1249
1361
  {team.lastActivity && (
1250
1362
  <>
1251
1363
  <span className="text-[var(--color-text-muted)] opacity-30">·</span>
1252
- <span className="text-[var(--color-text-muted)]">{formatRelativeTime(team.lastActivity)}</span>
1364
+ <span className="text-[var(--color-text-muted)]">
1365
+ {formatRelativeTime(team.lastActivity)}
1366
+ </span>
1253
1367
  </>
1254
1368
  )}
1255
1369
  </div>
@@ -0,0 +1,128 @@
1
+ /**
2
+ * CcSessionsSection — cc-only session expand regression (#20).
3
+ *
4
+ * A Feishu listening session with no local Claude JSONL yet is listed so the
5
+ * user sees it is listening. Expanding it must NOT call the local-only detail
6
+ * endpoint (which 404s and surfaces the misleading "会话文件已不存在"). Instead
7
+ * it shows an inline "监听中,暂无本地历史" state.
8
+ */
9
+ import React, { act } from 'react';
10
+ import { createRoot } from 'react-dom/client';
11
+
12
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
13
+
14
+ import type { CcSession } from '@shared/types';
15
+
16
+ import { CcSessionsSection } from '../CcSessionsSection';
17
+
18
+ const getSessionDetail = vi.hoisted(() => vi.fn());
19
+
20
+ vi.mock('@renderer/api', () => ({
21
+ api: {
22
+ teams: {
23
+ getSessionDetail,
24
+ },
25
+ },
26
+ }));
27
+
28
+ function ccOnlySession(overrides: Partial<CcSession> = {}): CcSession {
29
+ return {
30
+ id: 'oc_feishu_only',
31
+ title: 'feishu',
32
+ projectId: 'team-x',
33
+ sessionKey: 'oc_feishu_only',
34
+ platform: 'feishu',
35
+ userName: null,
36
+ chatName: '飞书测试群',
37
+ active: true,
38
+ live: true,
39
+ historyCount: 0,
40
+ createdAt: '2026-06-14T10:00:00Z',
41
+ updatedAt: '2026-06-14T10:00:00Z',
42
+ lastMessage: null,
43
+ hasLocalFile: false,
44
+ ...overrides,
45
+ };
46
+ }
47
+
48
+ async function renderSection(props: {
49
+ sessions: CcSession[];
50
+ loading?: boolean;
51
+ error?: string | null;
52
+ }) {
53
+ vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true);
54
+ const host = document.createElement('div');
55
+ document.body.appendChild(host);
56
+ const root = createRoot(host);
57
+ await act(async () => {
58
+ root.render(
59
+ React.createElement(CcSessionsSection, {
60
+ teamName: 'team-x',
61
+ sessions: props.sessions,
62
+ loading: props.loading ?? false,
63
+ error: props.error ?? null,
64
+ } as never)
65
+ );
66
+ await Promise.resolve();
67
+ });
68
+ return { host, root };
69
+ }
70
+
71
+ describe('CcSessionsSection — cc-only session expand (#20)', () => {
72
+ beforeEach(() => {
73
+ getSessionDetail.mockReset();
74
+ getSessionDetail.mockResolvedValue({
75
+ id: 'oc_feishu_only',
76
+ name: 'feishu',
77
+ sessionKey: 'oc_feishu_only',
78
+ agentType: 'claude-code',
79
+ active: true,
80
+ live: true,
81
+ historyCount: 0,
82
+ createdAt: '2026-06-14T10:00:00Z',
83
+ updatedAt: '2026-06-14T10:00:00Z',
84
+ platform: 'feishu',
85
+ history: [],
86
+ });
87
+ document.body.innerHTML = '';
88
+ });
89
+
90
+ it('shows "监听中" and does NOT fetch local detail for a cc-only session', async () => {
91
+ const { host } = await renderSection({ sessions: [ccOnlySession()] });
92
+
93
+ // The row header is a button carrying the session label.
94
+ const rowButton = Array.from(host.querySelectorAll('button')).find((b) =>
95
+ b.textContent?.includes('飞书测试群')
96
+ );
97
+ expect(rowButton, 'session row rendered').toBeTruthy();
98
+
99
+ await act(async () => {
100
+ rowButton?.click();
101
+ await Promise.resolve();
102
+ await Promise.resolve();
103
+ });
104
+
105
+ expect(host.textContent).toContain('监听中,暂无本地历史');
106
+ expect(host.textContent).not.toContain('会话文件已不存在');
107
+ expect(getSessionDetail).not.toHaveBeenCalled();
108
+ });
109
+
110
+ it('fetches local detail normally for a local-file session', async () => {
111
+ const { host } = await renderSection({ sessions: [ccOnlySession({ hasLocalFile: true })] });
112
+
113
+ const rowButton = Array.from(host.querySelectorAll('button')).find((b) =>
114
+ b.textContent?.includes('飞书测试群')
115
+ );
116
+ expect(rowButton, 'session row rendered').toBeTruthy();
117
+
118
+ await act(async () => {
119
+ rowButton?.click();
120
+ await Promise.resolve();
121
+ await Promise.resolve();
122
+ });
123
+
124
+ // A local-file session must still go through the local detail endpoint.
125
+ expect(getSessionDetail).toHaveBeenCalledTimes(1);
126
+ expect(getSessionDetail).toHaveBeenCalledWith('team-x', 'oc_feishu_only', expect.any(Number));
127
+ });
128
+ });
@@ -100,7 +100,7 @@ function parseQualifiedRecipient(
100
100
  }
101
101
 
102
102
  function buildLeadSourceTooltip(message: InboxMessage, leadLabel: string): string {
103
- const parts = [`发送者:${leadLabel}`, `消息来源:${message.source ?? 'unknown'}`];
103
+ const parts = [`发送者:${leadLabel}`, `动态来源:${message.source ?? 'unknown'}`];
104
104
  if (message.leadSessionId) {
105
105
  parts.push(`Session:${message.leadSessionId}`);
106
106
  }
@@ -1092,6 +1092,11 @@ export const ActivityItem = memo(
1092
1092
  </>
1093
1093
  ) : null;
1094
1094
 
1095
+ const hideExpandedHeaderSummary =
1096
+ isSlashCommandMessage ||
1097
+ !!displayText ||
1098
+ (isSystemMessage && strippedText ? /^\[跨团队任务已启动\]/.test(strippedText) : false);
1099
+
1095
1100
  const summaryContent =
1096
1101
  isSlashCommandResult && message.commandOutput ? (
1097
1102
  <span className="inline-flex min-w-0 items-center gap-1.5">
@@ -1238,7 +1243,7 @@ export const ActivityItem = memo(
1238
1243
  {onExpand && expandItemKey && (
1239
1244
  <button
1240
1245
  type="button"
1241
- aria-label="展开消息"
1246
+ aria-label="展开动态"
1242
1247
  className="absolute right-0 top-1/2 -translate-y-1/2 rounded p-0.5 opacity-0 transition-opacity focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-indigo-500/50 group-hover:opacity-100"
1243
1248
  style={{ color: CARD_ICON_MUTED }}
1244
1249
  onClick={(e) => {
@@ -1321,7 +1326,7 @@ export const ActivityItem = memo(
1321
1326
  {onExpand && expandItemKey && (
1322
1327
  <button
1323
1328
  type="button"
1324
- aria-label="展开消息"
1329
+ aria-label="展开动态"
1325
1330
  className="absolute right-0 top-1/2 -translate-y-1/2 rounded p-0.5 opacity-0 transition-opacity focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-indigo-500/50 group-hover:opacity-100"
1326
1331
  style={{ color: CARD_ICON_MUTED }}
1327
1332
  onClick={(e) => {
@@ -1388,9 +1393,16 @@ export const ActivityItem = memo(
1388
1393
  {messageTypeBadge}
1389
1394
  {statusBadge}
1390
1395
  {recipientBadge}
1391
- <span className="min-w-0 flex-1 truncate text-xs" style={{ color: CARD_TEXT_LIGHT }}>
1392
- {summaryContent}
1393
- </span>
1396
+ {!hideExpandedHeaderSummary ? (
1397
+ <span
1398
+ className="min-w-0 flex-1 truncate text-xs"
1399
+ style={{ color: CARD_TEXT_LIGHT }}
1400
+ >
1401
+ {summaryContent}
1402
+ </span>
1403
+ ) : (
1404
+ <span className="min-w-0 flex-1" />
1405
+ )}
1394
1406
  <div className="relative flex shrink-0 items-center">
1395
1407
  <span
1396
1408
  className={
@@ -1405,7 +1417,7 @@ export const ActivityItem = memo(
1405
1417
  {onExpand && expandItemKey && (
1406
1418
  <button
1407
1419
  type="button"
1408
- aria-label="展开消息"
1420
+ aria-label="展开动态"
1409
1421
  className="absolute right-0 top-1/2 -translate-y-1/2 rounded p-0.5 opacity-0 transition-opacity focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-indigo-500/50 group-hover:opacity-100"
1410
1422
  style={{ color: CARD_ICON_MUTED }}
1411
1423
  onClick={(e) => {
@@ -1530,7 +1542,7 @@ export const ActivityItem = memo(
1530
1542
  <Reply size={14} />
1531
1543
  </button>
1532
1544
  </TooltipTrigger>
1533
- <TooltipContent side="top">回复消息</TooltipContent>
1545
+ <TooltipContent side="top">回复动态</TooltipContent>
1534
1546
  </Tooltip>
1535
1547
  ) : null}
1536
1548
  {onCreateTask ? (
@@ -1548,7 +1560,7 @@ export const ActivityItem = memo(
1548
1560
  <ListPlus size={14} />
1549
1561
  </button>
1550
1562
  </TooltipTrigger>
1551
- <TooltipContent side="top">从消息创建任务</TooltipContent>
1563
+ <TooltipContent side="top">从动态创建任务</TooltipContent>
1552
1564
  </Tooltip>
1553
1565
  ) : null}
1554
1566
  <CopyButton text={displayText} inline />
@@ -859,8 +859,8 @@ export const ActivityTimeline = React.memo(function ActivityTimeline({
859
859
  if (messages.length === 0) {
860
860
  return (
861
861
  <div className="rounded-md border border-[var(--color-border)] p-3 pl-5 text-xs text-[var(--color-text-muted)]">
862
- <p>暂无消息</p>
863
- <p className="mt-1 text-[11px]">向成员发送消息后,这里会显示活动。</p>
862
+ <p>暂无动态</p>
863
+ <p className="mt-1 text-[11px]">向成员派发 Loop 指令后,这里会显示活动。</p>
864
864
  </div>
865
865
  );
866
866
  }
@@ -210,7 +210,7 @@ export const AdvancedCliSection: React.FC<AdvancedCliSectionProps> = ({
210
210
  进程内子 agent
211
211
  </div>
212
212
  <p className="text-[11px] leading-relaxed text-text-muted">
213
- 成员统一在负责人会话内启动,不再依赖 tmux。成员仍会按顺序逐个启动。
213
+ 成员统一在 Loop Lead 会话内启动,不再依赖 tmux。成员仍会按顺序逐个启动。
214
214
  </p>
215
215
  </div>
216
216
 
@@ -91,7 +91,7 @@ export const CreateTaskDialog = ({
91
91
  const [owner, setOwner] = useState<string>(defaultOwner);
92
92
  const [blockedBy, setBlockedBy] = useState<string[]>([]);
93
93
  const [related, setRelated] = useState<string[]>([]);
94
- const [startImmediately, setStartImmediately] = useState(true);
94
+ const [startImmediately, setStartImmediately] = useState(false);
95
95
  const promptDraft = useDraftPersistence({ key: `createTask:${teamName}:prompt` });
96
96
  const [blockedBySearch, setBlockedBySearch] = useState('');
97
97
  const [relatedSearch, setRelatedSearch] = useState('');
@@ -117,7 +117,7 @@ export const CreateTaskDialog = ({
117
117
  setOwner(defaultOwner);
118
118
  setBlockedBy([]);
119
119
  setRelated([]);
120
- setStartImmediately(defaultStartImmediately ?? isTeamAlive);
120
+ setStartImmediately(defaultStartImmediately ?? false);
121
121
  promptDraft.clearDraft();
122
122
  setBlockedBySearch('');
123
123
  setRelatedSearch('');
@@ -184,7 +184,7 @@ export const CreateTaskDialog = ({
184
184
  blockedBy.length > 0 ? blockedBy : undefined,
185
185
  related.length > 0 ? related : undefined,
186
186
  trimmedPrompt || undefined,
187
- startImmediately,
187
+ isTeamAlive ? startImmediately : false,
188
188
  descriptionTaskRefs,
189
189
  promptTaskRefs
190
190
  );
@@ -218,8 +218,10 @@ export const CreateTaskDialog = ({
218
218
  <Dialog open={open} onOpenChange={handleOpenChange}>
219
219
  <DialogContent className="sm:max-w-[580px]">
220
220
  <DialogHeader>
221
- <DialogTitle>创建任务</DialogTitle>
222
- <DialogDescription>任务会创建到团队的 tasks/ 目录,并显示在看板中。</DialogDescription>
221
+ <DialogTitle>创建 Loop 任务</DialogTitle>
222
+ <DialogDescription>
223
+ 任务会创建到 Loop workspace 的 tasks/ 目录,并显示在看板中。
224
+ </DialogDescription>
223
225
  </DialogHeader>
224
226
 
225
227
  {!isTeamAlive ? (
@@ -233,7 +235,8 @@ export const CreateTaskDialog = ({
233
235
  >
234
236
  <AlertTriangle size={14} className="mt-0.5 shrink-0" />
235
237
  <p className="text-xs leading-relaxed">
236
- 数字员工当前未运行:没有本地 Claude/Agent 进程在运行。任务会加入 <strong>待处理</strong>,启动数字员工后即可开始执行。
238
+ Loop runtime 当前未运行:没有本地 Claude/Agent 进程在运行。任务会加入{' '}
239
+ <strong>待处理</strong>,启动 runtime 后即可进入循环。
237
240
  </p>
238
241
  </div>
239
242
  ) : null}
@@ -277,7 +280,7 @@ export const CreateTaskDialog = ({
277
280
  <TiptapEditor
278
281
  content={descriptionDraft.value}
279
282
  onChange={descriptionDraft.setValue}
280
- placeholder="任务详情(支持 Markdown)"
283
+ placeholder="Loop 目标详情(支持 Markdown)"
281
284
  minHeight="100px"
282
285
  maxHeight="200px"
283
286
  toolbar
@@ -286,11 +289,11 @@ export const CreateTaskDialog = ({
286
289
 
287
290
  <div className="grid gap-2">
288
291
  <Label htmlFor="task-prompt" className="label-optional">
289
- 给负责人的提示词(可选)
292
+ 给 Loop Lead 的执行指令(可选)
290
293
  </Label>
291
294
  <MentionableTextarea
292
295
  id="task-prompt"
293
- placeholder="给团队成员的额外执行说明..."
296
+ placeholder="给 Loop worker 的额外执行说明..."
294
297
  value={promptDraft.value}
295
298
  onValueChange={promptDraft.setValue}
296
299
  suggestions={mentionSuggestions}
@@ -468,7 +471,7 @@ export const CreateTaskDialog = ({
468
471
  </div>
469
472
  {!isTeamAlive ? (
470
473
  <p className="text-[10px] text-[var(--color-text-muted)]">
471
- 数字员工当前未运行。请先启动数字员工,才能立即开始任务。
474
+ Loop runtime 当前未运行。请先启动 runtime,才能立即开始循环。
472
475
  </p>
473
476
  ) : null}
474
477
  </div>