@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.
- package/README.md +98 -89
- package/bin/hermit.mjs +96 -0
- package/dist-renderer/assets/{ProjectEditorOverlay-DlFQ6mai.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
- package/dist-renderer/assets/{TeamGraphOverlay-D2TPMPGR.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-Cmd0RHLQ.js → _basePickBy-ZOyLWjMK.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-BI_iy8ea.js → _baseUniq-DBb726rt.js} +1 -1
- package/dist-renderer/assets/{arc-NzW2mjTP.js → arc-CdiTaR_R.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Bzq85AYv.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-D1PvYS-b.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-D49RKzPC.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
- package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-fmI_MQmQ.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-Xsv9RCXZ.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-BE1KO8Um.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-tqJ7Mv7f.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-DMD45MVJ.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-DOhGrz-q.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-D8yDgJdD.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-BcsEDu7A.js → chunk-TZMSLE5B-BQEil57G.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-lpzulY5X.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-lpzulY5X.js +1 -0
- package/dist-renderer/assets/clone-CriGymY9.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DlSqGHMX.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-BTT9tSAx.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-Du-U-mK2.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-jFdHeKas.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-DKLNK2bu.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-CZxHgIIo.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-v4XStCD0.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DJjD_BEL.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BNy-jr03.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
- package/dist-renderer/assets/{graph-DDTrn6je.js → graph-CDP_R8ct.js} +1 -1
- package/dist-renderer/assets/{index-BBp78BAu.js → index-BSZdT-g-.js} +1 -1
- package/dist-renderer/assets/{index-eotrJaYy.js → index-BhWvMqsz.js} +1 -1
- package/dist-renderer/assets/{index-D8_B-cfs.js → index-C2_AupSj.js} +1 -1
- package/dist-renderer/assets/{index-BQrwHZ-k.js → index-C5ujiwAR.js} +580 -588
- package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
- package/dist-renderer/assets/{index-CRKQSG9S.js → index-CVNjLwkq.js} +1 -1
- package/dist-renderer/assets/{index-DR6Wz52b.js → index-CwG3se0q.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DqnOsuza.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DTobaO1d.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-HbwVOvWc.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
- package/dist-renderer/assets/{layout--VYmTcw2.js → layout-5nA5wUxO.js} +1 -1
- package/dist-renderer/assets/{linear-BsJh89Mr.js → linear-BtF1i2qN.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-BZqUZePd.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-B1q_nH6P.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-UD8QhSEu.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BA_i7Nw8.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-CMTnX-2d.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-BQXDB615.js → sequenceDiagram-WL72ISMW-CJg-WYyY.js} +1 -1
- package/dist-renderer/assets/{splashScene-D0YB9uxm.js → splashScene-94xWCzLA.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BAsPXy6X.js → stateDiagram-FKZM4ZOC-DWHOoFdv.js} +1 -1
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-CGYZOoMb.js +1 -0
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BdasmVkC.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-BkKQqIui.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-EAlPHOdx.js → xychartDiagram-PRI3JC2R-CCOcGbrD.js} +1 -1
- package/dist-renderer/chat-community-qr.jpg +0 -0
- package/dist-renderer/fonts/Agave-Bold.ttf +0 -0
- package/dist-renderer/fonts/Agave-Regular.ttf +0 -0
- package/dist-renderer/icon.png +0 -0
- package/dist-renderer/icon.rar +0 -0
- package/dist-renderer/index.html +3 -3
- package/package.json +21 -26
- package/src/features/worker-society/core/application/WorkerSocietyService.test.ts +802 -0
- package/src/features/worker-society/core/application/WorkerSocietyService.ts +428 -0
- package/src/features/worker-society/core/application/fakes.ts +101 -0
- package/src/features/worker-society/core/application/ports.ts +70 -0
- package/src/features/worker-society/core/domain/models/society.ts +141 -0
- package/src/features/worker-society/core/domain/policies/societyPolicies.test.ts +739 -0
- package/src/features/worker-society/core/domain/policies/societyPolicies.ts +496 -0
- package/src/features/worker-society/main/adapters/input/societyMcp.test.ts +317 -0
- package/src/features/worker-society/main/adapters/input/societyMcp.ts +257 -0
- package/src/features/worker-society/main/adapters/input/societyRoutes.test.ts +695 -0
- package/src/features/worker-society/main/adapters/input/societyRoutes.ts +194 -0
- package/src/features/worker-society/main/composition/societyComposition.test.ts +74 -0
- package/src/features/worker-society/main/composition/societyComposition.ts +70 -0
- package/src/features/worker-society/main/composition/workerSocietyPlugin.test.ts +69 -0
- package/src/features/worker-society/main/composition/workerSocietyPlugin.ts +67 -0
- package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.test.ts +132 -0
- package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.ts +84 -0
- package/src/features/worker-society/main/infrastructure/fsStores.test.ts +216 -0
- package/src/features/worker-society/main/infrastructure/fsStores.ts +113 -0
- package/src/features/worker-society/main/infrastructure/mergingProfileStore.test.ts +195 -0
- package/src/features/worker-society/main/infrastructure/mergingProfileStore.ts +96 -0
- package/src/features/worker-society/renderer/SocietyGraph.tsx +166 -0
- package/src/features/worker-society/renderer/SocietyNodeLabels.tsx +139 -0
- package/src/features/worker-society/renderer/SocietyNodeOverlay.tsx +339 -0
- package/src/features/worker-society/renderer/SocietyView.tsx +437 -0
- package/src/features/worker-society/renderer/index.ts +11 -0
- package/src/features/worker-society/renderer/societyApi.test.ts +259 -0
- package/src/features/worker-society/renderer/societyApi.ts +144 -0
- package/src/features/worker-society/renderer/societyGraphAdapter.test.ts +321 -0
- package/src/features/worker-society/renderer/societyGraphAdapter.ts +240 -0
- package/src/features/worker-society/renderer/societyOverlayActions.test.ts +57 -0
- package/src/features/worker-society/renderer/societyOverlayActions.ts +49 -0
- package/src/features/worker-society/renderer/societyStore.test.ts +218 -0
- package/src/features/worker-society/renderer/societyStore.ts +146 -0
- package/src/features/worker-society/renderer/societyViewUtils.test.ts +81 -0
- package/src/features/worker-society/renderer/societyViewUtils.ts +68 -0
- package/src/main/ipc/extensions.ts +27 -0
- package/src/main/server.ts +1709 -534
- package/src/main/services/ccConnect/CcConnectBridge.ts +26 -11
- package/src/main/services/ccConnect/CcConnectClient.ts +9 -2
- package/src/main/services/ccConnect/workDirReconcile.test.ts +57 -0
- package/src/main/services/ccConnect/workDirReconcile.ts +36 -0
- package/src/main/services/direct-cli/DirectCliSessionManager.test.ts +397 -0
- package/src/main/services/direct-cli/DirectCliSessionManager.ts +508 -0
- package/src/main/services/direct-cli/DirectCliSessionStore.test.ts +79 -0
- package/src/main/services/direct-cli/DirectCliSessionStore.ts +97 -0
- package/src/main/services/direct-cli/__tests__/directCliMessageId.test.ts +40 -0
- package/src/main/services/direct-cli/directCliMessageId.ts +21 -0
- package/src/main/services/direct-cli/index.ts +17 -0
- package/src/main/services/extensions/capability-packs/CapabilityPackLoaderService.ts +637 -0
- package/src/main/services/extensions/catalog/PluginCatalogService.ts +2 -2
- package/src/main/services/loop-assets/LoopAssetsScannerService.ts +657 -0
- package/src/main/services/runtime/providerAwareCliEnv.ts +33 -5
- package/src/main/services/session-intelligence/LocalSessionScanner.ts +156 -71
- package/src/main/services/session-intelligence/SessionUsageParser.ts +103 -8
- package/src/main/services/session-intelligence/UsageTelemetryService.ts +11 -0
- package/src/main/services/session-intelligence/__tests__/teamSessionListMapper.test.ts +104 -0
- package/src/main/services/session-intelligence/teamSessionListMapper.ts +78 -0
- package/src/main/services/system-manager/AdminLoopInitializer.ts +95 -0
- package/src/main/services/system-manager/BuiltinWorkflowSeeder.ts +679 -74
- package/src/main/services/system-manager/SystemManagerConfigService.ts +19 -1
- package/src/main/services/system-manager/WorkflowPromptService.ts +58 -5
- package/src/main/services/system-manager/__tests__/AdminLoopInitializer.test.ts +129 -0
- package/src/main/services/system-manager/__tests__/SystemManagerConfigService.test.ts +60 -0
- package/src/main/services/teams-mvp/CollaborationBoardService.ts +2 -0
- package/src/main/services/teams-mvp/OpsRunbookContext.ts +60 -0
- package/src/main/services/teams-mvp/TaskDispatchService.test.ts +305 -0
- package/src/main/services/teams-mvp/TaskDispatchService.ts +250 -131
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +12 -2
- package/src/main/services/teams-mvp/TeamWorkspaceService.test.ts +207 -0
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +104 -51
- package/src/main/services/teams-mvp/index.ts +6 -0
- package/src/main/utils/externalPlatformSessionRouting.ts +92 -0
- package/src/main/utils/toolApprovalRules.ts +151 -0
- package/src/renderer/App.tsx +24 -89
- package/src/renderer/api/httpClient.ts +115 -37
- package/src/renderer/api/providers.ts +5 -16
- package/src/renderer/components/chat/CommunityChatView.tsx +81 -0
- package/src/renderer/components/dashboard/DashboardView.tsx +130 -84
- package/src/renderer/components/extensions/ExtensionStoreView.tsx +39 -5
- package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +2 -1
- package/src/renderer/components/extensions/capability-packs/CapabilityPacksPanel.tsx +170 -0
- package/src/renderer/components/layout/PaneContent.tsx +10 -2
- package/src/renderer/components/layout/SortableTab.tsx +4 -0
- package/src/renderer/components/layout/TabBarActions.tsx +13 -16
- package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +4 -135
- package/src/renderer/components/schedules/SchedulesView.tsx +22 -14
- package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +7 -6
- package/src/renderer/components/settings/SettingsTabs.tsx +24 -21
- package/src/renderer/components/settings/SettingsView.tsx +22 -13
- package/src/renderer/components/settings/components/SettingRow.tsx +13 -5
- package/src/renderer/components/settings/components/SettingsSectionCard.tsx +53 -0
- package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +10 -6
- package/src/renderer/components/settings/components/SettingsSelect.tsx +12 -9
- package/src/renderer/components/settings/components/SettingsToggle.tsx +6 -5
- package/src/renderer/components/settings/components/index.ts +1 -0
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +78 -59
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +32 -44
- package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
- package/src/renderer/components/settings/sections/GeneralSection.tsx +216 -186
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +25 -17
- package/src/renderer/components/settings/sections/TaskBusSection.tsx +63 -22
- package/src/renderer/components/sidebar/SidebarSessions.tsx +120 -80
- package/src/renderer/components/sidebar/SidebarTaskItem.tsx +1 -1
- package/src/renderer/components/splash/splashScene.ts +6 -2
- package/src/renderer/components/system-manager/SystemManagerView.tsx +169 -255
- package/src/renderer/components/tasks/TasksView.tsx +63 -37
- package/src/renderer/components/team/CcSessionsSection.tsx +124 -89
- package/src/renderer/components/team/HarnessBrandLogos.tsx +318 -0
- package/src/renderer/components/team/HarnessSelect.tsx +25 -26
- package/src/renderer/components/team/TeamDetailView.tsx +137 -153
- package/src/renderer/components/team/TeamEmptyState.tsx +9 -37
- package/src/renderer/components/team/TeamListView.tsx +143 -30
- package/src/renderer/components/team/__tests__/CcSessionsSection.hasLocalFile.test.tsx +128 -0
- package/src/renderer/components/team/activity/ActivityItem.tsx +21 -9
- package/src/renderer/components/team/activity/ActivityTimeline.tsx +2 -2
- package/src/renderer/components/team/dialogs/AdvancedCliSection.tsx +1 -1
- package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +13 -10
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +156 -83
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +9 -157
- package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +19 -15
- package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +48 -10
- package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +11 -12
- package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +39 -37
- package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +434 -64
- package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +12 -10
- package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +2 -2
- package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.bindProject.test.tsx +399 -0
- package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.chineseRepro.test.tsx +253 -0
- package/src/renderer/components/team/dialogs/platformAllowUtils.ts +91 -0
- package/src/renderer/components/team/dialogs/teammateRuntimeCompatibility.tsx +1 -1
- package/src/renderer/components/team/kanban/KanbanTaskCard.test.tsx +41 -0
- package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +41 -86
- package/src/renderer/components/team/loop-console/LoopCommandComposer.tsx +310 -0
- package/src/renderer/components/team/loop-console/LoopConsolePanel.tsx +372 -0
- package/src/renderer/components/team/loop-console/loopSendIntent.test.ts +85 -0
- package/src/renderer/components/team/loop-console/loopSendIntent.ts +221 -0
- package/src/renderer/components/team/loop-console/useLeadSessionToolActivity.ts +74 -0
- package/src/renderer/components/team/loop-console/useLoopCommandSuggestions.ts +165 -0
- package/src/renderer/components/team/loop-console/useLoopConsoleController.ts +266 -0
- package/src/renderer/components/team/members/LeadModelRow.test.tsx +1 -1
- package/src/renderer/components/team/members/LeadModelRow.tsx +5 -3
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +11 -0
- package/src/renderer/components/team/members/MemberDetailStats.tsx +13 -3
- package/src/renderer/components/team/members/MemberDraftRow.test.tsx +1 -1
- package/src/renderer/components/team/members/MemberDraftRow.tsx +1 -1
- package/src/renderer/components/team/members/MemberMessagesTab.tsx +2 -2
- package/src/renderer/components/team/members/MemberStatsTab.tsx +1 -1
- package/src/renderer/components/team/messages/MessageComposer.tsx +150 -44
- package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +2 -2
- package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -28
- package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +6 -6
- package/src/renderer/components/team/taskLogs/ExactTaskLogCard.tsx +2 -2
- package/src/renderer/components/team/taskLogs/TaskLogStreamSection.tsx +1 -1
- package/src/renderer/components/terminal/TerminalPanel.tsx +2 -3
- package/src/renderer/components/ui/MentionableTextarea.tsx +5 -1
- package/src/renderer/constants/teamColors.ts +5 -5
- package/src/renderer/hooks/useExtensionsTabState.ts +1 -1
- package/src/renderer/hooks/useMentionDetection.ts +5 -1
- package/src/renderer/hooks/useProjectWorkflowCommands.ts +57 -0
- package/src/renderer/hooks/useTeamSuggestions.ts +2 -0
- package/src/renderer/index.css +19 -2
- package/src/renderer/main.tsx +7 -1
- package/src/renderer/store/index.ts +18 -1
- package/src/renderer/store/slices/extensionsSlice.ts +83 -0
- package/src/renderer/store/slices/tabSlice.ts +61 -0
- package/src/renderer/store/slices/teamSlice.ts +138 -9
- package/src/renderer/types/mention.ts +8 -0
- package/src/renderer/types/tabs.ts +3 -1
- package/src/renderer/utils/__tests__/bindProjectSlug.test.ts +69 -0
- package/src/renderer/utils/__tests__/groupTransformer.test.ts +148 -0
- package/src/renderer/utils/__tests__/initialRoute.test.ts +101 -0
- package/src/renderer/utils/__tests__/leadToolActivity.test.ts +124 -0
- package/src/renderer/utils/__tests__/mergeTeamMessages.test.ts +81 -0
- package/src/renderer/utils/__tests__/teamMessageFiltering.test.ts +213 -0
- package/src/renderer/utils/__tests__/teamMessageKey.test.ts +75 -0
- package/src/renderer/utils/__tests__/workflowCommandExecution.test.ts +173 -0
- package/src/renderer/utils/__tests__/workflowCommandSuggestions.test.ts +59 -0
- package/src/renderer/utils/bindProjectSlug.ts +57 -0
- package/src/renderer/utils/capabilityCommandExecution.ts +113 -0
- package/src/renderer/utils/initialRoute.ts +89 -0
- package/src/renderer/utils/leadToolActivity.ts +117 -0
- package/src/renderer/utils/loopShortcutSuggestions.ts +106 -0
- package/src/renderer/utils/mentionSuggestions.ts +1 -1
- package/src/renderer/utils/slashCommandRegistry.ts +231 -0
- package/src/renderer/utils/teamMentionDirective.ts +31 -0
- package/src/renderer/utils/workflowCommandExecution.ts +96 -0
- package/src/renderer/utils/workflowCommandSuggestions.ts +49 -0
- package/src/shared/types/api.ts +79 -4
- package/src/shared/types/ccConnect.ts +1 -0
- package/src/shared/types/extensions/api.ts +19 -0
- package/src/shared/types/extensions/capabilityPack.ts +118 -0
- package/src/shared/types/extensions/index.ts +29 -1
- package/src/shared/types/index.ts +6 -0
- package/src/shared/types/loopAssets.ts +54 -0
- package/src/shared/types/providers.ts +0 -16
- package/src/shared/types/systemManager.ts +26 -1
- package/src/shared/types/team.ts +41 -5
- package/src/shared/types/terminal.ts +2 -36
- package/src/shared/types/worker.test.ts +28 -0
- package/src/shared/types/worker.ts +3 -0
- package/src/shared/utils/__tests__/effortLevels.test.ts +88 -0
- package/src/shared/utils/__tests__/providerBackend.test.ts +88 -0
- package/src/shared/utils/__tests__/providerLaunchArgs.test.ts +220 -0
- package/src/shared/utils/claudeStreamJson.test.ts +187 -0
- package/src/shared/utils/claudeStreamJson.ts +153 -0
- package/src/shared/utils/providerLaunchArgs.ts +217 -0
- package/src/shared/utils/slashCommands.ts +10 -0
- package/src/types/node-pty.d.ts +8 -0
- package/dist-renderer/assets/channel-Ch7JrfUu.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-z9I4AnFy.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-z9I4AnFy.js +0 -1
- package/dist-renderer/assets/clone-Dfi1Jx6l.js +0 -1
- package/dist-renderer/assets/index-iyjkpSus.css +0 -32
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DTUIBfce.js +0 -1
- package/src/main/services/system-manager/SystemManagerPtyService.ts +0 -233
- package/src/renderer/components/common/TerminalPane.tsx +0 -213
- 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.
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
|
@@ -841,6 +896,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
841
896
|
clearProvisioningError={clearProvisioningError}
|
|
842
897
|
existingTeamNames={teams.map((t) => t.teamName)}
|
|
843
898
|
existingBindProjects={teams.map((t) => t.bindProject).filter(Boolean) as string[]}
|
|
899
|
+
existingDisplayNames={teams.map((t) => t.displayName).filter(Boolean) as string[]}
|
|
844
900
|
provisioningTeamNames={provisioningTeamNames}
|
|
845
901
|
activeTeams={activeTeams}
|
|
846
902
|
initialData={copyData ?? undefined}
|
|
@@ -975,7 +1031,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
975
1031
|
{template.members.map((member) => (
|
|
976
1032
|
<span
|
|
977
1033
|
key={member.name}
|
|
978
|
-
className="rounded bg-
|
|
1034
|
+
className="rounded bg-[var(--color-accent-soft)] px-1.5 py-0.5 text-[10px] text-[var(--color-accent)]"
|
|
979
1035
|
>
|
|
980
1036
|
{member.name}
|
|
981
1037
|
{member.role ? ` · ${formatTeamRoleLabel(member.role)}` : ''}
|
|
@@ -1014,10 +1070,10 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1014
1070
|
<Button
|
|
1015
1071
|
variant="outline"
|
|
1016
1072
|
size="sm"
|
|
1017
|
-
className="border-
|
|
1073
|
+
className="border-[var(--color-accent-border)] text-[var(--color-accent)] hover:bg-[var(--color-accent-soft)]"
|
|
1018
1074
|
onClick={() => void openSystemManager()}
|
|
1019
1075
|
>
|
|
1020
|
-
|
|
1076
|
+
Helm Loop
|
|
1021
1077
|
</Button>
|
|
1022
1078
|
<Button
|
|
1023
1079
|
variant="outline"
|
|
@@ -1030,6 +1086,41 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1030
1086
|
</div>
|
|
1031
1087
|
</div>
|
|
1032
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
|
+
|
|
1033
1124
|
{teamsWithProvisioning.length > 0 ? (
|
|
1034
1125
|
<div className="mt-3 flex items-center gap-2">
|
|
1035
1126
|
<div className="relative flex-1">
|
|
@@ -1060,11 +1151,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1060
1151
|
|
|
1061
1152
|
const renderContent = (): React.JSX.Element => {
|
|
1062
1153
|
if (teamsLoading) {
|
|
1063
|
-
return
|
|
1064
|
-
<div className="flex size-full items-center justify-center text-sm text-[var(--color-text-muted)]">
|
|
1065
|
-
正在加载团队...
|
|
1066
|
-
</div>
|
|
1067
|
-
);
|
|
1154
|
+
return <TeamListSkeleton />;
|
|
1068
1155
|
}
|
|
1069
1156
|
|
|
1070
1157
|
if (teamsError) {
|
|
@@ -1134,7 +1221,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1134
1221
|
key={team.teamName}
|
|
1135
1222
|
role="button"
|
|
1136
1223
|
tabIndex={0}
|
|
1137
|
-
className="group relative flex cursor-pointer flex-col overflow-hidden rounded-lg border border-[var(--color-border)] bg-[var(--color-surface)] p-4 transition-
|
|
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"
|
|
1138
1225
|
onClick={
|
|
1139
1226
|
isDeleting ? undefined : () => openTeamTab(team.teamName, team.projectPath)
|
|
1140
1227
|
}
|
|
@@ -1166,14 +1253,12 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1166
1253
|
{team.displayName}
|
|
1167
1254
|
</h3>
|
|
1168
1255
|
{isSystemManager ? (
|
|
1169
|
-
<span className="shrink-0 rounded bg-
|
|
1256
|
+
<span className="shrink-0 rounded bg-[var(--color-accent-soft)] px-1.5 py-px text-[9px] font-medium text-[var(--color-accent)]">
|
|
1170
1257
|
SYS
|
|
1171
1258
|
</span>
|
|
1172
1259
|
) : null}
|
|
1173
1260
|
<StatusBadge status={status} />
|
|
1174
|
-
{team.pendingDelete || team.restartRequired ?
|
|
1175
|
-
<PendingDeleteBadge />
|
|
1176
|
-
) : null}
|
|
1261
|
+
{team.pendingDelete || team.restartRequired ? <PendingDeleteBadge /> : null}
|
|
1177
1262
|
{team.projectPath &&
|
|
1178
1263
|
(() => {
|
|
1179
1264
|
const branch = branchByPath[normalizePath(team.projectPath)];
|
|
@@ -1195,7 +1280,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1195
1280
|
<TooltipTrigger asChild>
|
|
1196
1281
|
<button
|
|
1197
1282
|
type="button"
|
|
1198
|
-
className="rounded p-1 text-[var(--color-text-muted)] opacity-0 transition-opacity hover:bg-[var(--color-surface-raised)] group-hover:opacity-60
|
|
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"
|
|
1199
1284
|
onClick={(e) => handleCopyTeam(team.teamName, e)}
|
|
1200
1285
|
>
|
|
1201
1286
|
<Copy size={13} />
|
|
@@ -1211,7 +1296,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1211
1296
|
<TooltipTrigger asChild>
|
|
1212
1297
|
<button
|
|
1213
1298
|
type="button"
|
|
1214
|
-
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
|
|
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"
|
|
1215
1300
|
onClick={(e) =>
|
|
1216
1301
|
handleDeleteTeam(team.teamName, !!team.pendingCreate, e)
|
|
1217
1302
|
}
|
|
@@ -1231,16 +1316,42 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1231
1316
|
</p>
|
|
1232
1317
|
|
|
1233
1318
|
{/* Row 3: Stats bar */}
|
|
1234
|
-
<div className="mt-2 flex items-center gap-1.5 pl-[42px] text-[10px] tabular-nums">
|
|
1235
|
-
{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) ? (
|
|
1236
1321
|
<>
|
|
1237
|
-
<span className="text-
|
|
1322
|
+
<span className="text-[var(--color-accent)]">
|
|
1323
|
+
{team.stats.sessions} sessions
|
|
1324
|
+
</span>
|
|
1238
1325
|
<span className="text-[var(--color-text-muted)] opacity-30">·</span>
|
|
1239
|
-
<span className="text-
|
|
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>
|
|
1240
1349
|
{team.stats.durationMs > 0 && (
|
|
1241
1350
|
<>
|
|
1242
1351
|
<span className="text-[var(--color-text-muted)] opacity-30">·</span>
|
|
1243
|
-
<span className="text-amber-400">
|
|
1352
|
+
<span className="text-amber-400">
|
|
1353
|
+
{formatDurationShort(team.stats.durationMs)}
|
|
1354
|
+
</span>
|
|
1244
1355
|
</>
|
|
1245
1356
|
)}
|
|
1246
1357
|
</>
|
|
@@ -1250,7 +1361,9 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1250
1361
|
{team.lastActivity && (
|
|
1251
1362
|
<>
|
|
1252
1363
|
<span className="text-[var(--color-text-muted)] opacity-30">·</span>
|
|
1253
|
-
<span className="text-[var(--color-text-muted)]">
|
|
1364
|
+
<span className="text-[var(--color-text-muted)]">
|
|
1365
|
+
{formatRelativeTime(team.lastActivity)}
|
|
1366
|
+
</span>
|
|
1254
1367
|
</>
|
|
1255
1368
|
)}
|
|
1256
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}`,
|
|
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
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
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"
|
|
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"
|
|
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
|
|
863
|
-
<p className="mt-1 text-[11px]"
|
|
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
|
-
|
|
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(
|
|
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 ??
|
|
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
|
|
222
|
-
<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
|
-
|
|
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="
|
|
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>
|