@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.
- package/README.md +98 -89
- package/bin/hermit.mjs +96 -0
- package/dist-renderer/assets/{ProjectEditorOverlay-Br0X83Jf.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
- package/dist-renderer/assets/{TeamGraphOverlay-DHMTbZPZ.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-DzIiX7yH.js → _basePickBy-ZOyLWjMK.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-6hZuzTLU.js → _baseUniq-DBb726rt.js} +1 -1
- package/dist-renderer/assets/{arc-CXgO6fx_.js → arc-CdiTaR_R.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DKWgtDHr.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-DOMUcC40.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-B_k2L7qX.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
- package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-BeD_ccFy.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-ClZfkA5w.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-5XluxXsn.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-BzIjjNVm.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-HgH3MK_H.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-WeC5T3Ba.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-Cu1ApHfW.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-BOhlynJM.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-DGZSihDQ.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-CnxwCbku.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-DsIhoxdI.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-Cmh9KUF5.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-CKxV456A.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-EnvYjOjc.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-BmNeWY_A.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-D30fyK-u.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-CrUNiYg1.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
- package/dist-renderer/assets/{graph-CY1gTfTb.js → graph-CDP_R8ct.js} +1 -1
- package/dist-renderer/assets/{index-CaEbzwAU.js → index-BSZdT-g-.js} +1 -1
- package/dist-renderer/assets/{index-D5K-SjBG.js → index-BhWvMqsz.js} +1 -1
- package/dist-renderer/assets/{index-9_hO4N1e.js → index-C2_AupSj.js} +1 -1
- package/dist-renderer/assets/{index-59r209c1.js → index-C5ujiwAR.js} +580 -588
- package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
- package/dist-renderer/assets/{index-DMR9B1UP.js → index-CVNjLwkq.js} +1 -1
- package/dist-renderer/assets/{index-BC2hXmg_.js → index-CwG3se0q.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-By_XUlcD.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BM1LJE9m.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-DHIW3aTA.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
- package/dist-renderer/assets/{layout-DAKiL_Mo.js → layout-5nA5wUxO.js} +1 -1
- package/dist-renderer/assets/{linear-DwOaRYea.js → linear-BtF1i2qN.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-b7bJ2cha.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-DxyL9Zr2.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CR33pHlF.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BAiSRSlh.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-C8JmDjoa.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-c1d0Wi1m.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-nT8BiH2O.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-DpoRepUA.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-C41UJeIH.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-KMjGARKN.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 +1731 -539
- 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 +744 -0
- 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 +132 -52
- 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 +144 -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 +189 -57
- 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 +43 -3
- 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-D0XS_akr.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-D13Ffs0U.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-D13Ffs0U.js +0 -1
- package/dist-renderer/assets/clone-B1ZrxI1D.js +0 -1
- package/dist-renderer/assets/index-iyjkpSus.css +0 -32
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-Dmibmlso.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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { Button } from '@renderer/components/ui/button';
|
|
4
|
+
import { downloadTextFile } from '../../team/CcSessionsSection';
|
|
4
5
|
import { SettingRow, SettingsSectionHeader, SettingsToggle } from '../components';
|
|
5
6
|
import type { TaskBusConfig } from '@shared/types/team';
|
|
6
7
|
import {
|
|
@@ -25,14 +26,19 @@ interface TelemetryStatus {
|
|
|
25
26
|
tokensOut: number;
|
|
26
27
|
cacheRead: number;
|
|
27
28
|
cacheCreation: number;
|
|
29
|
+
totalTokens: number;
|
|
28
30
|
activeDays: number;
|
|
29
31
|
hourly: number[];
|
|
30
32
|
projects: Array<{
|
|
31
33
|
cwd: string;
|
|
34
|
+
displayName?: string;
|
|
35
|
+
teamSlug?: string;
|
|
36
|
+
bindProject?: string;
|
|
32
37
|
sessions: number;
|
|
33
38
|
messages: number;
|
|
34
39
|
tokensIn: number;
|
|
35
40
|
tokensOut: number;
|
|
41
|
+
tokensTotal: number;
|
|
36
42
|
}>;
|
|
37
43
|
workSecondsByDay: Record<string, number>;
|
|
38
44
|
}
|
|
@@ -58,20 +64,27 @@ function UsageDashboard({ status }: { status: TelemetryStatus }): React.JSX.Elem
|
|
|
58
64
|
return (
|
|
59
65
|
<div className="space-y-4 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] p-4">
|
|
60
66
|
<div className="flex items-center justify-between">
|
|
61
|
-
<span className="text-xs font-medium text-[var(--color-text-muted)]"
|
|
62
|
-
<span className="text-[10px] text-[var(--color-text-muted)]"
|
|
67
|
+
<span className="text-xs font-medium text-[var(--color-text-muted)]">Loop 使用概览</span>
|
|
68
|
+
<span className="text-[10px] text-[var(--color-text-muted)]">
|
|
69
|
+
累计 Loop 数据(全部历史)
|
|
70
|
+
</span>
|
|
63
71
|
</div>
|
|
64
72
|
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
|
65
73
|
<StatCard
|
|
66
74
|
icon={<MessageSquare size={14} />}
|
|
67
|
-
label="
|
|
75
|
+
label="采集会话"
|
|
68
76
|
value={formatNum(status.sessions)}
|
|
69
77
|
/>
|
|
70
78
|
<StatCard
|
|
71
79
|
icon={<MessageSquare size={14} />}
|
|
72
|
-
label="
|
|
80
|
+
label="Messages"
|
|
73
81
|
value={formatNum(status.messages)}
|
|
74
82
|
/>
|
|
83
|
+
<StatCard
|
|
84
|
+
icon={<Zap size={14} />}
|
|
85
|
+
label="Total Tokens"
|
|
86
|
+
value={formatNum(status.totalTokens)}
|
|
87
|
+
/>
|
|
75
88
|
<StatCard icon={<Zap size={14} />} label="Input" value={formatNum(status.tokensIn)} />
|
|
76
89
|
<StatCard icon={<Zap size={14} />} label="Output" value={formatNum(status.tokensOut)} />
|
|
77
90
|
<StatCard icon={<Calendar size={14} />} label="活跃天" value={String(status.activeDays)} />
|
|
@@ -89,14 +102,16 @@ function UsageDashboard({ status }: { status: TelemetryStatus }): React.JSX.Elem
|
|
|
89
102
|
</div>
|
|
90
103
|
|
|
91
104
|
<div>
|
|
92
|
-
<div className="mb-2 text-xs font-medium text-[var(--color-text-muted)]">
|
|
105
|
+
<div className="mb-2 text-xs font-medium text-[var(--color-text-muted)]">
|
|
106
|
+
24小时 Messages 分布
|
|
107
|
+
</div>
|
|
93
108
|
<div className="flex h-16 items-end gap-0.5">
|
|
94
109
|
{status.hourly.map((count, i) => {
|
|
95
110
|
const pct = (count / maxHourly) * 100;
|
|
96
111
|
return (
|
|
97
112
|
<div
|
|
98
113
|
key={i}
|
|
99
|
-
className="flex-1 rounded-sm bg-
|
|
114
|
+
className="flex-1 rounded-sm bg-[var(--color-accent-muted)] transition-all hover:bg-[var(--color-accent)]"
|
|
100
115
|
style={{ height: `${Math.max(pct, 2)}%` }}
|
|
101
116
|
title={`${i}:00 - ${count} messages`}
|
|
102
117
|
/>
|
|
@@ -142,26 +157,24 @@ function UsageDashboard({ status }: { status: TelemetryStatus }): React.JSX.Elem
|
|
|
142
157
|
|
|
143
158
|
{status.projects.length > 0 && (
|
|
144
159
|
<div>
|
|
145
|
-
<div className="mb-2 text-xs font-medium text-[var(--color-text-muted)]">
|
|
146
|
-
项目排行(累计)
|
|
147
|
-
</div>
|
|
160
|
+
<div className="mb-2 text-xs font-medium text-[var(--color-text-muted)]">项目吞吐</div>
|
|
148
161
|
{/* Header row */}
|
|
149
|
-
<div className="grid grid-cols-[
|
|
150
|
-
<span
|
|
151
|
-
<span className="text-right"
|
|
152
|
-
<span className="text-right">
|
|
162
|
+
<div className="grid grid-cols-[1fr_72px_80px] items-center gap-2 pb-1 text-[10px] text-[var(--color-text-muted)]">
|
|
163
|
+
<span>名称</span>
|
|
164
|
+
<span className="text-right">Messages</span>
|
|
165
|
+
<span className="text-right">Total Tokens</span>
|
|
153
166
|
</div>
|
|
154
167
|
<div className="max-h-40 space-y-1 overflow-y-auto">
|
|
155
168
|
{status.projects.slice(0, 10).map((proj, i) => (
|
|
156
|
-
<div key={i} className="grid grid-cols-[
|
|
169
|
+
<div key={i} className="grid grid-cols-[1fr_72px_80px] items-center gap-2 text-xs">
|
|
157
170
|
<span className="truncate text-[var(--color-text-secondary)]" title={proj.cwd}>
|
|
158
|
-
{proj.cwd.split('/').pop() || proj.cwd}
|
|
171
|
+
{proj.displayName || proj.cwd.split('/').pop() || proj.cwd}
|
|
159
172
|
</span>
|
|
160
173
|
<span className="text-right text-[var(--color-text-muted)]">
|
|
161
174
|
{formatNum(proj.messages)}
|
|
162
175
|
</span>
|
|
163
176
|
<span className="text-right text-[var(--color-text-muted)]">
|
|
164
|
-
{formatNum(proj.
|
|
177
|
+
{formatNum(proj.tokensTotal)}
|
|
165
178
|
</span>
|
|
166
179
|
</div>
|
|
167
180
|
))}
|
|
@@ -207,6 +220,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
207
220
|
const [collaborationEnabled, setCollaborationEnabled] = useState(false);
|
|
208
221
|
const [telemetryPlatform, setTelemetryPlatform] = useState('claudecode');
|
|
209
222
|
const [scanning, setScanning] = useState(false);
|
|
223
|
+
const [exporting, setExporting] = useState(false);
|
|
210
224
|
const [telemetryStatus, setTelemetryStatus] = useState<TelemetryStatus | null>(null);
|
|
211
225
|
|
|
212
226
|
useEffect(() => {
|
|
@@ -377,6 +391,23 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
377
391
|
.finally(() => setScanning(false));
|
|
378
392
|
};
|
|
379
393
|
|
|
394
|
+
const exportTelemetry = () => {
|
|
395
|
+
if (exporting) return;
|
|
396
|
+
setExporting(true);
|
|
397
|
+
fetch('/api/telemetry/export?format=csv')
|
|
398
|
+
.then((r) => r.json())
|
|
399
|
+
.then((payload: { filename?: string; mimeType?: string; content?: string }) => {
|
|
400
|
+
if (payload.filename && payload.mimeType && payload.content !== undefined) {
|
|
401
|
+
downloadTextFile(payload.content, payload.filename, payload.mimeType);
|
|
402
|
+
setMessage('采集数据已导出');
|
|
403
|
+
} else {
|
|
404
|
+
setMessage('导出失败:没有可导出的数据');
|
|
405
|
+
}
|
|
406
|
+
})
|
|
407
|
+
.catch(() => setMessage('导出失败,请稍后重试'))
|
|
408
|
+
.finally(() => setExporting(false));
|
|
409
|
+
};
|
|
410
|
+
|
|
380
411
|
const saveTelemetryPlatform = (nextPlatform = telemetryPlatform) => {
|
|
381
412
|
const config = buildConfig({ telemetryPlatform: nextPlatform });
|
|
382
413
|
fetch('/api/settings/task-bus', {
|
|
@@ -412,7 +443,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
412
443
|
|
|
413
444
|
<SettingRow
|
|
414
445
|
label="数据采集"
|
|
415
|
-
description="扫描本机 ~/.claude/projects
|
|
446
|
+
description="扫描本机 ~/.claude/projects 会话文件,采集 Loop 使用指标;不需要 Redis,也不会上传对话内容"
|
|
416
447
|
>
|
|
417
448
|
<div className="flex items-center gap-2">
|
|
418
449
|
<select
|
|
@@ -422,7 +453,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
422
453
|
setTelemetryPlatform(nextPlatform);
|
|
423
454
|
saveTelemetryPlatform(nextPlatform);
|
|
424
455
|
}}
|
|
425
|
-
className="rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2 py-1 text-xs outline-none focus:border-
|
|
456
|
+
className="rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2 py-1 text-xs outline-none focus:border-[var(--color-accent-border)]"
|
|
426
457
|
>
|
|
427
458
|
<option value="claudecode">Claude Code</option>
|
|
428
459
|
</select>
|
|
@@ -447,6 +478,16 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
447
478
|
{scanning ? <Loader2 size={12} className="animate-spin" /> : <BarChart3 size={12} />}
|
|
448
479
|
{scanning ? '采集中...' : '立即采集'}
|
|
449
480
|
</Button>
|
|
481
|
+
<Button
|
|
482
|
+
size="sm"
|
|
483
|
+
variant="outline"
|
|
484
|
+
onClick={exportTelemetry}
|
|
485
|
+
disabled={exporting || !telemetryStatus}
|
|
486
|
+
className="gap-1.5"
|
|
487
|
+
>
|
|
488
|
+
{exporting ? <Loader2 size={12} className="animate-spin" /> : <BarChart3 size={12} />}
|
|
489
|
+
导出 CSV
|
|
490
|
+
</Button>
|
|
450
491
|
<span className="text-[10px] text-[var(--color-text-muted)]">
|
|
451
492
|
本地扫描,不依赖团队总线或 Redis。{!collectionEnabled ? '开启数据采集后可手动刷新。' : ''}
|
|
452
493
|
</span>
|
|
@@ -457,7 +498,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
457
498
|
<UsageDashboard status={telemetryStatus} />
|
|
458
499
|
) : (
|
|
459
500
|
<div className="rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] p-4 text-xs text-[var(--color-text-muted)]">
|
|
460
|
-
|
|
501
|
+
Loop 使用概览加载中;开启数据采集后会扫描本机 Claude Code 会话文件。
|
|
461
502
|
</div>
|
|
462
503
|
)}
|
|
463
504
|
</div>
|
|
@@ -507,7 +548,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
507
548
|
setHost(e.target.value);
|
|
508
549
|
setConnected(false);
|
|
509
550
|
}}
|
|
510
|
-
className="w-full rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2.5 py-1.5 text-sm outline-none focus:border-
|
|
551
|
+
className="w-full rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2.5 py-1.5 text-sm outline-none focus:border-[var(--color-accent-border)] focus:ring-1 focus:ring-[var(--color-accent-border)]"
|
|
511
552
|
placeholder="127.0.0.1"
|
|
512
553
|
/>
|
|
513
554
|
</div>
|
|
@@ -520,7 +561,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
520
561
|
setPort(Number(e.target.value));
|
|
521
562
|
setConnected(false);
|
|
522
563
|
}}
|
|
523
|
-
className="w-full rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2.5 py-1.5 text-sm outline-none focus:border-
|
|
564
|
+
className="w-full rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2.5 py-1.5 text-sm outline-none focus:border-[var(--color-accent-border)] focus:ring-1 focus:ring-[var(--color-accent-border)]"
|
|
524
565
|
placeholder="6379"
|
|
525
566
|
/>
|
|
526
567
|
</div>
|
|
@@ -534,7 +575,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
534
575
|
setPassword(e.target.value);
|
|
535
576
|
setConnected(false);
|
|
536
577
|
}}
|
|
537
|
-
className="w-full rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2.5 py-1.5 text-sm outline-none focus:border-
|
|
578
|
+
className="w-full rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2.5 py-1.5 text-sm outline-none focus:border-[var(--color-accent-border)] focus:ring-1 focus:ring-[var(--color-accent-border)]"
|
|
538
579
|
placeholder="可选"
|
|
539
580
|
/>
|
|
540
581
|
</div>
|
|
@@ -39,6 +39,18 @@ const PAGE_SIZE = 8;
|
|
|
39
39
|
const REFRESH_INTERVAL_MS = 2000;
|
|
40
40
|
const SESSION_DETAIL_PAGE_SIZE = 50;
|
|
41
41
|
|
|
42
|
+
function sessionExpansionKey(teamName: string, sessionId: string): string {
|
|
43
|
+
return `${teamName}\0${sessionId}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function formatSessionDetailError(error: unknown): string {
|
|
47
|
+
const message = error instanceof Error ? error.message : String(error || '');
|
|
48
|
+
if (/session not found/i.test(message)) {
|
|
49
|
+
return '会话文件已不存在,请刷新会话列表';
|
|
50
|
+
}
|
|
51
|
+
return message || '加载会话历史失败';
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
interface TaggedSession extends CcSession {
|
|
43
55
|
teamName: string;
|
|
44
56
|
teamDisplayName: string;
|
|
@@ -55,11 +67,11 @@ export const SidebarSessions = (): React.JSX.Element => {
|
|
|
55
67
|
const [error, setError] = useState<string | null>(null);
|
|
56
68
|
const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);
|
|
57
69
|
const [searchQuery, setSearchQuery] = useState('');
|
|
58
|
-
const [
|
|
70
|
+
const [cancellingKey, setCancellingKey] = useState<string | null>(null);
|
|
59
71
|
const [exporting, setExporting] = useState(false);
|
|
60
72
|
const [telemetryRows, setTelemetryRows] = useState<ConversationTelemetryRow[]>([]);
|
|
61
73
|
const [loadingTelemetry, setLoadingTelemetry] = useState(false);
|
|
62
|
-
const [
|
|
74
|
+
const [expandedKey, setExpandedKey] = useState<string | null>(null);
|
|
63
75
|
const refreshInFlightRef = useRef(false);
|
|
64
76
|
const needsRefreshRef = useRef(false);
|
|
65
77
|
|
|
@@ -115,7 +127,9 @@ export const SidebarSessions = (): React.JSX.Element => {
|
|
|
115
127
|
if (r.status === 'fulfilled') merged.push(...r.value);
|
|
116
128
|
}
|
|
117
129
|
setAllSessions(merged);
|
|
118
|
-
|
|
130
|
+
setExpandedKey((prev) =>
|
|
131
|
+
prev && merged.some((s) => sessionExpansionKey(s.teamName, s.id) === prev) ? prev : null
|
|
132
|
+
);
|
|
119
133
|
} catch (err) {
|
|
120
134
|
setError(err instanceof Error ? err.message : '加载失败');
|
|
121
135
|
} finally {
|
|
@@ -185,7 +199,7 @@ export const SidebarSessions = (): React.JSX.Element => {
|
|
|
185
199
|
|
|
186
200
|
useEffect(() => {
|
|
187
201
|
setVisibleCount(PAGE_SIZE);
|
|
188
|
-
|
|
202
|
+
setExpandedKey(null);
|
|
189
203
|
}, [scopedTeamName]);
|
|
190
204
|
|
|
191
205
|
useEffect(() => {
|
|
@@ -227,26 +241,28 @@ export const SidebarSessions = (): React.JSX.Element => {
|
|
|
227
241
|
|
|
228
242
|
const handleCancel = useCallback(
|
|
229
243
|
async (teamName: string, sessionId: string) => {
|
|
230
|
-
|
|
244
|
+
const key = sessionExpansionKey(teamName, sessionId);
|
|
245
|
+
setCancellingKey(key);
|
|
231
246
|
try {
|
|
232
247
|
await api.teams.cancelSession(teamName, sessionId);
|
|
233
248
|
// Remove from list immediately
|
|
234
|
-
setAllSessions((prev) => prev.filter((s) => s.id !==
|
|
249
|
+
setAllSessions((prev) => prev.filter((s) => sessionExpansionKey(s.teamName, s.id) !== key));
|
|
235
250
|
// Clear expanded state if this session was expanded
|
|
236
|
-
if (
|
|
237
|
-
|
|
251
|
+
if (expandedKey === key) {
|
|
252
|
+
setExpandedKey(null);
|
|
238
253
|
}
|
|
239
254
|
} catch (err) {
|
|
240
255
|
console.error('Failed to close session:', err);
|
|
241
256
|
} finally {
|
|
242
|
-
|
|
257
|
+
setCancellingKey(null);
|
|
243
258
|
}
|
|
244
259
|
},
|
|
245
|
-
[
|
|
260
|
+
[expandedKey]
|
|
246
261
|
);
|
|
247
262
|
|
|
248
263
|
const handleExpand = useCallback((teamName: string, sessionId: string) => {
|
|
249
|
-
|
|
264
|
+
const key = sessionExpansionKey(teamName, sessionId);
|
|
265
|
+
setExpandedKey((prev) => (prev === key ? null : key));
|
|
250
266
|
}, []);
|
|
251
267
|
|
|
252
268
|
const handleExportAllSessions = useCallback(async () => {
|
|
@@ -425,12 +441,12 @@ export const SidebarSessions = (): React.JSX.Element => {
|
|
|
425
441
|
.filter((s) => s.live)
|
|
426
442
|
.map((s) => (
|
|
427
443
|
<SessionRow
|
|
428
|
-
key={s.id}
|
|
444
|
+
key={sessionExpansionKey(s.teamName, s.id)}
|
|
429
445
|
session={s}
|
|
430
446
|
onCancel={handleCancel}
|
|
431
447
|
onExpand={handleExpand}
|
|
432
|
-
isExpanded={
|
|
433
|
-
cancelling={
|
|
448
|
+
isExpanded={expandedKey === sessionExpansionKey(s.teamName, s.id)}
|
|
449
|
+
cancelling={cancellingKey === sessionExpansionKey(s.teamName, s.id)}
|
|
434
450
|
/>
|
|
435
451
|
))}
|
|
436
452
|
</>
|
|
@@ -446,11 +462,11 @@ export const SidebarSessions = (): React.JSX.Element => {
|
|
|
446
462
|
.filter((s) => !s.live)
|
|
447
463
|
.map((s) => (
|
|
448
464
|
<SessionRow
|
|
449
|
-
key={s.id}
|
|
465
|
+
key={sessionExpansionKey(s.teamName, s.id)}
|
|
450
466
|
session={s}
|
|
451
467
|
onCancel={handleCancel}
|
|
452
468
|
onExpand={handleExpand}
|
|
453
|
-
isExpanded={
|
|
469
|
+
isExpanded={expandedKey === sessionExpansionKey(s.teamName, s.id)}
|
|
454
470
|
cancelling={false}
|
|
455
471
|
/>
|
|
456
472
|
))}
|
|
@@ -492,6 +508,7 @@ const SessionRow = ({
|
|
|
492
508
|
const platformLabel = session.platform === 'bridge' ? 'Bridge' : session.platform;
|
|
493
509
|
const [detail, setDetail] = useState<CcSessionDetail | null>(null);
|
|
494
510
|
const [loadingDetail, setLoadingDetail] = useState(false);
|
|
511
|
+
const [detailError, setDetailError] = useState<string | null>(null);
|
|
495
512
|
const [historyLimit, setHistoryLimit] = useState(SESSION_DETAIL_PAGE_SIZE);
|
|
496
513
|
const [loadingMoreHistory, setLoadingMoreHistory] = useState(false);
|
|
497
514
|
const hasMoreHistory =
|
|
@@ -501,8 +518,9 @@ const SessionRow = ({
|
|
|
501
518
|
|
|
502
519
|
// Fetch detail when expanded
|
|
503
520
|
useEffect(() => {
|
|
504
|
-
if (!isExpanded) {
|
|
521
|
+
if (!isExpanded || session.hasLocalFile === false) {
|
|
505
522
|
setDetail(null);
|
|
523
|
+
setDetailError(null);
|
|
506
524
|
setLoadingDetail(false);
|
|
507
525
|
setLoadingMoreHistory(false);
|
|
508
526
|
setHistoryLimit(SESSION_DETAIL_PAGE_SIZE);
|
|
@@ -510,14 +528,18 @@ const SessionRow = ({
|
|
|
510
528
|
}
|
|
511
529
|
let cancelled = false;
|
|
512
530
|
setLoadingDetail(true);
|
|
531
|
+
setDetailError(null);
|
|
513
532
|
const isIncrementalLoad = historyLimit > SESSION_DETAIL_PAGE_SIZE;
|
|
514
533
|
setLoadingMoreHistory(isIncrementalLoad);
|
|
515
534
|
void (async () => {
|
|
516
535
|
try {
|
|
517
536
|
const d = await api.teams.getSessionDetail(session.teamName, session.id, historyLimit);
|
|
518
537
|
if (!cancelled) setDetail(d);
|
|
519
|
-
} catch {
|
|
520
|
-
if (!cancelled)
|
|
538
|
+
} catch (err) {
|
|
539
|
+
if (!cancelled) {
|
|
540
|
+
setDetail(null);
|
|
541
|
+
setDetailError(formatSessionDetailError(err));
|
|
542
|
+
}
|
|
521
543
|
} finally {
|
|
522
544
|
if (!cancelled) {
|
|
523
545
|
setLoadingDetail(false);
|
|
@@ -534,7 +556,7 @@ const SessionRow = ({
|
|
|
534
556
|
// refetch (no skeleton flash) so newly arrived messages show without needing
|
|
535
557
|
// to collapse and reopen.
|
|
536
558
|
useEffect(() => {
|
|
537
|
-
if (!isExpanded || !session.live) {
|
|
559
|
+
if (!isExpanded || !session.live || session.hasLocalFile === false) {
|
|
538
560
|
return;
|
|
539
561
|
}
|
|
540
562
|
const intervalId = window.setInterval(() => {
|
|
@@ -557,7 +579,7 @@ const SessionRow = ({
|
|
|
557
579
|
// this session's team, refresh the detail right away instead of waiting for
|
|
558
580
|
// the next polling cycle. This makes agent replies appear in <100ms.
|
|
559
581
|
useEffect(() => {
|
|
560
|
-
if (!isExpanded) {
|
|
582
|
+
if (!isExpanded || session.hasLocalFile === false) {
|
|
561
583
|
return;
|
|
562
584
|
}
|
|
563
585
|
const unsubscribe = api.teams.onTeamChange?.((_event, change: TeamChangeEvent) => {
|
|
@@ -591,7 +613,7 @@ const SessionRow = ({
|
|
|
591
613
|
useEffect(() => {
|
|
592
614
|
const wasLive = prevLiveRef.current;
|
|
593
615
|
prevLiveRef.current = session.live;
|
|
594
|
-
if (wasLive && !session.live && isExpanded) {
|
|
616
|
+
if (wasLive && !session.live && isExpanded && session.hasLocalFile !== false) {
|
|
595
617
|
void (async () => {
|
|
596
618
|
try {
|
|
597
619
|
const d = await api.teams.getSessionDetail(session.teamName, session.id, historyLimit);
|
|
@@ -689,69 +711,87 @@ const SessionRow = ({
|
|
|
689
711
|
{/* Inline expanded messages */}
|
|
690
712
|
{isExpanded && (
|
|
691
713
|
<div className="ml-5 border-l-2 border-[var(--color-border)]">
|
|
692
|
-
{
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
/>
|
|
700
|
-
))}
|
|
701
|
-
</div>
|
|
714
|
+
{session.hasLocalFile === false ? (
|
|
715
|
+
// cc-only session (e.g. Feishu listening, no local JSONL yet) —
|
|
716
|
+
// no local history. Avoids the misleading "会话文件已不存在" 404
|
|
717
|
+
// path (#20). Same root cause as CcSessionsSection.
|
|
718
|
+
<div className="flex items-center gap-2 px-3 py-2 text-xs text-[var(--color-text-muted)]">
|
|
719
|
+
<Radio size={13} className="shrink-0 animate-pulse text-emerald-400" />
|
|
720
|
+
<span>监听中,暂无本地历史</span>
|
|
702
721
|
</div>
|
|
703
|
-
)
|
|
704
|
-
{detail && (
|
|
722
|
+
) : (
|
|
705
723
|
<>
|
|
706
|
-
{
|
|
707
|
-
<div className="px-3 py-3
|
|
708
|
-
|
|
724
|
+
{loadingDetail && !detail && (
|
|
725
|
+
<div className="px-3 py-3">
|
|
726
|
+
<div className="space-y-2">
|
|
727
|
+
{[1, 2, 3].map((i) => (
|
|
728
|
+
<div
|
|
729
|
+
key={i}
|
|
730
|
+
className="h-3 animate-pulse rounded bg-[var(--color-surface-raised)]"
|
|
731
|
+
/>
|
|
732
|
+
))}
|
|
733
|
+
</div>
|
|
734
|
+
</div>
|
|
735
|
+
)}
|
|
736
|
+
{detailError && !loadingDetail && (
|
|
737
|
+
<div className="flex items-center gap-2 px-3 py-2 text-xs text-red-400">
|
|
738
|
+
<AlertCircle size={13} className="shrink-0" />
|
|
739
|
+
<span>{detailError}</span>
|
|
740
|
+
</div>
|
|
741
|
+
)}
|
|
742
|
+
{detail && (
|
|
709
743
|
<>
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
744
|
+
{detail.history.length === 0 ? (
|
|
745
|
+
<div className="px-3 py-3 text-xs text-[var(--color-text-muted)]">暂无消息</div>
|
|
746
|
+
) : (
|
|
747
|
+
<>
|
|
748
|
+
<div className="divide-[var(--color-border)]/50 max-h-64 divide-y overflow-y-auto">
|
|
749
|
+
{[...detail.history].reverse().map((msg, i) => (
|
|
750
|
+
<div key={i} className="px-3 py-2 text-[11px]">
|
|
751
|
+
<div className="flex items-center gap-2">
|
|
752
|
+
<span
|
|
753
|
+
className={`shrink-0 text-[10px] font-medium ${
|
|
754
|
+
msg.role === 'user'
|
|
755
|
+
? 'text-indigo-400'
|
|
756
|
+
: 'text-[var(--color-text-muted)]'
|
|
757
|
+
}`}
|
|
758
|
+
>
|
|
759
|
+
{msg.role === 'user' ? '用户' : 'Agent'}
|
|
760
|
+
</span>
|
|
761
|
+
<span className="text-[10px] text-[var(--color-text-muted)] opacity-60">
|
|
762
|
+
{formatMessageTime(msg.timestamp)}
|
|
763
|
+
</span>
|
|
764
|
+
</div>
|
|
765
|
+
<div className="mt-1 whitespace-pre-wrap break-words text-[var(--color-text)]">
|
|
766
|
+
{msg.content.slice(0, 500)}
|
|
767
|
+
{msg.content.length > 500 ? '…' : ''}
|
|
768
|
+
</div>
|
|
769
|
+
</div>
|
|
770
|
+
))}
|
|
771
|
+
</div>
|
|
772
|
+
{hasMoreHistory && (
|
|
773
|
+
<div className="border-[var(--color-border)]/50 border-t px-3 py-2">
|
|
774
|
+
<button
|
|
775
|
+
type="button"
|
|
776
|
+
className="inline-flex items-center gap-1 text-xs text-[var(--color-text-muted)] transition-colors hover:text-[var(--color-text)] disabled:cursor-not-allowed disabled:opacity-50"
|
|
777
|
+
onClick={handleLoadMoreHistory}
|
|
778
|
+
disabled={loadingDetail || loadingMoreHistory}
|
|
720
779
|
>
|
|
721
|
-
{
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
780
|
+
{loadingMoreHistory ? (
|
|
781
|
+
<>
|
|
782
|
+
<Loader2 size={12} className="animate-spin" />
|
|
783
|
+
正在加载更早消息...
|
|
784
|
+
</>
|
|
785
|
+
) : (
|
|
786
|
+
<>
|
|
787
|
+
加载更早消息 (
|
|
788
|
+
{Math.max(detail.historyCount - detail.history.length, 0)} 条)
|
|
789
|
+
</>
|
|
790
|
+
)}
|
|
791
|
+
</button>
|
|
730
792
|
</div>
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
</div>
|
|
734
|
-
{hasMoreHistory && (
|
|
735
|
-
<div className="border-[var(--color-border)]/50 border-t px-3 py-2">
|
|
736
|
-
<button
|
|
737
|
-
type="button"
|
|
738
|
-
className="inline-flex items-center gap-1 text-xs text-[var(--color-text-muted)] transition-colors hover:text-[var(--color-text)] disabled:cursor-not-allowed disabled:opacity-50"
|
|
739
|
-
onClick={handleLoadMoreHistory}
|
|
740
|
-
disabled={loadingDetail || loadingMoreHistory}
|
|
741
|
-
>
|
|
742
|
-
{loadingMoreHistory ? (
|
|
743
|
-
<>
|
|
744
|
-
<Loader2 size={12} className="animate-spin" />
|
|
745
|
-
正在加载更早消息...
|
|
746
|
-
</>
|
|
747
|
-
) : (
|
|
748
|
-
<>
|
|
749
|
-
加载更早消息 ({Math.max(detail.historyCount - detail.history.length, 0)}{' '}
|
|
750
|
-
条)
|
|
751
|
-
</>
|
|
752
|
-
)}
|
|
753
|
-
</button>
|
|
754
|
-
</div>
|
|
793
|
+
)}
|
|
794
|
+
</>
|
|
755
795
|
)}
|
|
756
796
|
</>
|
|
757
797
|
)}
|
|
@@ -145,7 +145,7 @@ export const SidebarTaskItem = ({
|
|
|
145
145
|
|
|
146
146
|
const showTeamRow = showTeamName && !hideTeamName;
|
|
147
147
|
const unreadBackgroundClass =
|
|
148
|
-
unreadCount > 0 ? (isLight ? 'bg-
|
|
148
|
+
unreadCount > 0 ? (isLight ? 'bg-blue-500/[0.03]' : 'bg-blue-500/[0.05]') : '';
|
|
149
149
|
|
|
150
150
|
return (
|
|
151
151
|
<button
|
|
@@ -21,8 +21,11 @@ declare global {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// Version is injected at build time from package.json (vite.web.config.ts define),
|
|
25
|
+
// the same source the Settings page and Sentry use — so the splash version always
|
|
26
|
+
// tracks the real release instead of a stale hardcoded literal.
|
|
24
27
|
const BOOT_LINES = [
|
|
25
|
-
|
|
28
|
+
`🦀 hermit v${__APP_VERSION__}`,
|
|
26
29
|
'connecting harness…',
|
|
27
30
|
'loading team configs…',
|
|
28
31
|
'scanning session history…',
|
|
@@ -96,7 +99,8 @@ export function startSplashScene(
|
|
|
96
99
|
if (!line) return;
|
|
97
100
|
|
|
98
101
|
const lineEl = document.createElement('div');
|
|
99
|
-
lineEl.style.cssText =
|
|
102
|
+
lineEl.style.cssText =
|
|
103
|
+
'opacity: 0; transform: translateY(4px); transition: opacity 0.3s, transform 0.3s;';
|
|
100
104
|
|
|
101
105
|
if (lineIndex === 0) {
|
|
102
106
|
// First line — brand with crab
|