@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
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { buildWorkflowCommandSuggestion } from '../workflowCommandSuggestions';
|
|
4
|
+
|
|
5
|
+
import type { WorkflowPromptSummary } from '@shared/types/systemManager';
|
|
6
|
+
|
|
7
|
+
function prompt(overrides: Partial<WorkflowPromptSummary> = {}): WorkflowPromptSummary {
|
|
8
|
+
return {
|
|
9
|
+
id: 'prompt-loop-scan',
|
|
10
|
+
label: 'Loop Scan',
|
|
11
|
+
filename: 'loop-scan.md',
|
|
12
|
+
path: '/workspace/.claude/commands/loop-scan.md',
|
|
13
|
+
folder: '/workspace/.claude/commands',
|
|
14
|
+
sizeBytes: 100,
|
|
15
|
+
updatedAt: '2026-06-13T00:00:00.000Z',
|
|
16
|
+
...overrides,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('buildWorkflowCommandSuggestion', () => {
|
|
21
|
+
it('derives the command from commandName when present', () => {
|
|
22
|
+
const suggestion = buildWorkflowCommandSuggestion(prompt({ commandName: '/loop-scan' }));
|
|
23
|
+
expect(suggestion.command).toBe('/loop-scan');
|
|
24
|
+
expect(suggestion.name).toBe('loop-scan');
|
|
25
|
+
expect(suggestion.insertText).toBe('loop-scan');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('falls back to the filename when there is no commandName', () => {
|
|
29
|
+
const suggestion = buildWorkflowCommandSuggestion(prompt({ commandName: undefined }));
|
|
30
|
+
expect(suggestion.command).toBe('/loop-scan');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('carries workflowPromptId / workflowPromptFolder for submit-time expansion', () => {
|
|
34
|
+
const suggestion = buildWorkflowCommandSuggestion(prompt());
|
|
35
|
+
expect(suggestion.workflowPromptId).toBe('prompt-loop-scan');
|
|
36
|
+
expect(suggestion.workflowPromptFolder).toBe('/workspace/.claude/commands');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('uses a configurable id prefix', () => {
|
|
40
|
+
expect(buildWorkflowCommandSuggestion(prompt()).id).toBe('workflow:prompt-loop-scan');
|
|
41
|
+
expect(buildWorkflowCommandSuggestion(prompt(), 'team-workflow').id).toBe(
|
|
42
|
+
'team-workflow:prompt-loop-scan'
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('builds a searchable searchText from label/description/category/safety', () => {
|
|
47
|
+
const suggestion = buildWorkflowCommandSuggestion(
|
|
48
|
+
prompt({ description: 'Run loop scan', category: 'loop', safety: 'read-only' })
|
|
49
|
+
);
|
|
50
|
+
expect(suggestion.searchText).toContain('Loop Scan');
|
|
51
|
+
expect(suggestion.searchText).toContain('read-only');
|
|
52
|
+
expect(suggestion.searchText).toContain('/loop-scan');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('falls back to a description from the label', () => {
|
|
56
|
+
const suggestion = buildWorkflowCommandSuggestion(prompt({ description: undefined }));
|
|
57
|
+
expect(suggestion.description).toBe('运行 Loop Scan');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-identifier (bindProject) generation for the create-digital-worker
|
|
3
|
+
* dialog. Extracted from CreateTeamDialog so the slug rules can be unit-tested.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** Validate bindProject: ASCII lowercase alphanumeric, hyphens, underscores. */
|
|
7
|
+
export function isValidBindProject(value: string): boolean {
|
|
8
|
+
return /^[a-z0-9][a-z0-9_-]*$/.test(value);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Reduce a display name to an ASCII slug base (empty when there's no ASCII). */
|
|
12
|
+
function slugBase(displayName: string): string {
|
|
13
|
+
return displayName
|
|
14
|
+
.toLowerCase()
|
|
15
|
+
.normalize('NFKD')
|
|
16
|
+
.replace(/[̀-ͯ]/g, '')
|
|
17
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
18
|
+
.replace(/-+/g, '-')
|
|
19
|
+
.replace(/^-|-$/g, '');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Deterministic 4-char suffix derived from the name. Replaces the old
|
|
24
|
+
* `Math.random()` suffix so the identifier stops reshuffling on every keystroke
|
|
25
|
+
* — same name (+ same collision context) always yields the same candidate.
|
|
26
|
+
*/
|
|
27
|
+
function hashSuffix(input: string): string {
|
|
28
|
+
let hash = 0;
|
|
29
|
+
for (let i = 0; i < input.length; i += 1) {
|
|
30
|
+
hash = (hash * 31 + input.charCodeAt(i)) >>> 0;
|
|
31
|
+
}
|
|
32
|
+
return hash.toString(36).slice(0, 4).padStart(4, '0');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generate a unique ASCII project identifier from a display name.
|
|
37
|
+
*
|
|
38
|
+
* The result is deterministic for a given (name, existing) pair and is
|
|
39
|
+
* guaranteed NOT to collide with any id in `existing`. Together those two
|
|
40
|
+
* properties kill the old flickering false-"已存在" red box: the auto-generated
|
|
41
|
+
* identifier is stable while typing and is never flagged as a duplicate.
|
|
42
|
+
*/
|
|
43
|
+
export function generateBindProject(displayName: string, existing: ReadonlySet<string>): string {
|
|
44
|
+
const trimmed = displayName.trim();
|
|
45
|
+
if (!trimmed) return '';
|
|
46
|
+
const base = slugBase(trimmed) || 'team';
|
|
47
|
+
|
|
48
|
+
// Primary candidate: base + deterministic suffix.
|
|
49
|
+
const candidate = `${base}-${hashSuffix(trimmed)}`;
|
|
50
|
+
if (!existing.has(candidate)) return candidate;
|
|
51
|
+
|
|
52
|
+
// Collision (another worker already took the deterministic id): walk a numeric
|
|
53
|
+
// counter until we find a free slot. Bounded by existing size + 2.
|
|
54
|
+
let counter = 2;
|
|
55
|
+
while (existing.has(`${base}-${counter}`)) counter += 1;
|
|
56
|
+
return `${base}-${counter}`;
|
|
57
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { api } from '@renderer/api';
|
|
2
|
+
import { parseStandaloneSlashCommand } from '@shared/utils/slashCommands';
|
|
3
|
+
|
|
4
|
+
import { resolveSlashCommand } from './slashCommandRegistry';
|
|
5
|
+
|
|
6
|
+
import type { RegisteredSlashCommand, CapabilityScope } from '@shared/types/extensions';
|
|
7
|
+
import type { SlashCommandMeta } from '@shared/types/team';
|
|
8
|
+
|
|
9
|
+
export interface SelectedCapabilityCommandRef {
|
|
10
|
+
commandRef: string;
|
|
11
|
+
command: `/${string}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ResolvedCapabilityCommandInput {
|
|
15
|
+
command: RegisteredSlashCommand;
|
|
16
|
+
raw: string;
|
|
17
|
+
args?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ExpandedCapabilityCommand {
|
|
21
|
+
text: string;
|
|
22
|
+
summary: string;
|
|
23
|
+
slashCommand: SlashCommandMeta;
|
|
24
|
+
registered: RegisteredSlashCommand;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ResolveCapabilityCommandInputOptions {
|
|
28
|
+
shadowedAliases?: ReadonlySet<string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface ResolveCapabilityCommandInputResult {
|
|
32
|
+
status: 'not-found' | 'resolved' | 'conflict';
|
|
33
|
+
resolved?: ResolvedCapabilityCommandInput;
|
|
34
|
+
conflictLabel?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function selectedCommandStillMatches(
|
|
38
|
+
parsedCommand: `/${string}`,
|
|
39
|
+
selected?: SelectedCapabilityCommandRef | null
|
|
40
|
+
): boolean {
|
|
41
|
+
return Boolean(
|
|
42
|
+
selected?.commandRef && selected.command.toLowerCase() === parsedCommand.toLowerCase()
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function appendArgsToPrompt(prompt: string, args?: string): string {
|
|
47
|
+
const trimmedPrompt = prompt.trim();
|
|
48
|
+
const trimmedArgs = args?.trim();
|
|
49
|
+
if (!trimmedArgs) return trimmedPrompt;
|
|
50
|
+
return `${trimmedPrompt}\n\nUser arguments:\n${trimmedArgs}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function resolveCapabilityCommandInput(
|
|
54
|
+
registry: readonly RegisteredSlashCommand[],
|
|
55
|
+
text: string,
|
|
56
|
+
selected?: SelectedCapabilityCommandRef | null,
|
|
57
|
+
options: ResolveCapabilityCommandInputOptions = {}
|
|
58
|
+
): ResolveCapabilityCommandInputResult {
|
|
59
|
+
const parsed = parseStandaloneSlashCommand(text);
|
|
60
|
+
if (!parsed) return { status: 'not-found' };
|
|
61
|
+
|
|
62
|
+
const selectedRef = selectedCommandStillMatches(parsed.command, selected)
|
|
63
|
+
? selected?.commandRef
|
|
64
|
+
: undefined;
|
|
65
|
+
if (!selectedRef && options.shadowedAliases?.has(parsed.name)) {
|
|
66
|
+
return { status: 'not-found' };
|
|
67
|
+
}
|
|
68
|
+
const result = resolveSlashCommand(registry, parsed.command, selectedRef);
|
|
69
|
+
if (result.status === 'resolved' && result.command) {
|
|
70
|
+
return {
|
|
71
|
+
status: 'resolved',
|
|
72
|
+
resolved: {
|
|
73
|
+
command: result.command,
|
|
74
|
+
raw: parsed.raw,
|
|
75
|
+
args: parsed.args,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (result.status === 'conflict') {
|
|
80
|
+
return {
|
|
81
|
+
status: 'conflict',
|
|
82
|
+
conflictLabel: '能力包命令存在冲突,请从菜单选择带 namespace 的命令。',
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return { status: 'not-found' };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function expandCapabilityCommand(
|
|
89
|
+
resolved: ResolvedCapabilityCommandInput,
|
|
90
|
+
scope: CapabilityScope
|
|
91
|
+
): Promise<ExpandedCapabilityCommand> {
|
|
92
|
+
if (!api.capabilityPacks) {
|
|
93
|
+
throw new Error('Capability packs API is unavailable');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const result = await api.capabilityPacks.getCommandPrompt({
|
|
97
|
+
canonicalId: resolved.command.canonicalId,
|
|
98
|
+
scope,
|
|
99
|
+
});
|
|
100
|
+
const command = result.command;
|
|
101
|
+
const slashCommand: SlashCommandMeta = {
|
|
102
|
+
name: command.alias,
|
|
103
|
+
command: command.namespacedSlash,
|
|
104
|
+
args: resolved.args,
|
|
105
|
+
knownDescription: command.command.description ?? command.command.title,
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
text: appendArgsToPrompt(result.prompt, resolved.args),
|
|
109
|
+
summary: command.command.title,
|
|
110
|
+
slashCommand,
|
|
111
|
+
registered: command,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Initial route restoration.
|
|
3
|
+
*
|
|
4
|
+
* Restores the active tab from the URL path SYNCHRONOUSLY, before React's first
|
|
5
|
+
* render (called from main.tsx). Running this pre-render means the store already
|
|
6
|
+
* holds the correct tab on the first paint — there is no blank content area
|
|
7
|
+
* while a post-mount effect catches up, and the fallback view never double-mounts.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { AppState } from '@renderer/store/types';
|
|
11
|
+
|
|
12
|
+
function safeDecodeURIComponent(value: string): string {
|
|
13
|
+
try {
|
|
14
|
+
return decodeURIComponent(value);
|
|
15
|
+
} catch {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Map the current URL path to the matching tab action. Idempotent: every action
|
|
22
|
+
* dedupes against already-open tabs, so calling this more than once (e.g. HMR)
|
|
23
|
+
* is safe.
|
|
24
|
+
*/
|
|
25
|
+
export function restoreInitialRoute(state: AppState, pathname: string): void {
|
|
26
|
+
const segments = pathname
|
|
27
|
+
.split('/')
|
|
28
|
+
.map((segment) => segment.trim())
|
|
29
|
+
.filter((segment) => segment.length > 0)
|
|
30
|
+
.map(safeDecodeURIComponent);
|
|
31
|
+
|
|
32
|
+
if (segments.length === 0) return;
|
|
33
|
+
|
|
34
|
+
const [route, arg1, arg2] = segments;
|
|
35
|
+
switch (route) {
|
|
36
|
+
case 'team':
|
|
37
|
+
if (arg1) state.openTeamTab(arg1);
|
|
38
|
+
break;
|
|
39
|
+
case 'teams':
|
|
40
|
+
state.openTeamsTab();
|
|
41
|
+
break;
|
|
42
|
+
case 'system-manager':
|
|
43
|
+
void state.openSystemManager();
|
|
44
|
+
break;
|
|
45
|
+
case 'settings':
|
|
46
|
+
state.openSettingsTab();
|
|
47
|
+
break;
|
|
48
|
+
case 'extensions':
|
|
49
|
+
state.openExtensionsTab();
|
|
50
|
+
break;
|
|
51
|
+
case 'schedules':
|
|
52
|
+
state.openSchedulesTab();
|
|
53
|
+
break;
|
|
54
|
+
case 'tasks':
|
|
55
|
+
state.openTasksTab();
|
|
56
|
+
break;
|
|
57
|
+
case 'dashboard':
|
|
58
|
+
state.openDashboard();
|
|
59
|
+
break;
|
|
60
|
+
case 'society':
|
|
61
|
+
state.openSocietyTab();
|
|
62
|
+
break;
|
|
63
|
+
case 'session':
|
|
64
|
+
if (arg1 && arg2) {
|
|
65
|
+
state.navigateToSession(arg1, arg2);
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
case 'notifications':
|
|
69
|
+
state.openTab({ type: 'notifications', label: '通知' });
|
|
70
|
+
break;
|
|
71
|
+
case 'graph':
|
|
72
|
+
if (arg1) {
|
|
73
|
+
state.openTab({ type: 'graph', label: arg1, teamName: arg1 });
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case 'report':
|
|
77
|
+
if (arg1 && arg2) {
|
|
78
|
+
state.openTab({
|
|
79
|
+
type: 'report',
|
|
80
|
+
label: 'Session Report',
|
|
81
|
+
projectId: arg1,
|
|
82
|
+
sessionId: arg2,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
default:
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead tool-activity extraction.
|
|
3
|
+
*
|
|
4
|
+
* The Loop console message stream only carries team/group messages — agent tool
|
|
5
|
+
* invocations (Bash/Read/Edit/…) live in the parsed session detail. These helpers
|
|
6
|
+
* flatten recent tool calls out of a parsed session so the console can surface
|
|
7
|
+
* "what the lead agent actually did" alongside the message feed.
|
|
8
|
+
*
|
|
9
|
+
* The input is typed structurally (not as the full `ParsedMessage`) so the pure
|
|
10
|
+
* extraction logic can be unit-tested without constructing an entire parsed
|
|
11
|
+
* session, while still accepting real `ParsedMessage[]` at the call site.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Minimal shape of a single tool call we care about for display. */
|
|
15
|
+
export interface ToolActivityCall {
|
|
16
|
+
name: string;
|
|
17
|
+
input: Record<string, unknown>;
|
|
18
|
+
id?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Minimal message shape carrying tool calls. `ParsedMessage` satisfies this. */
|
|
22
|
+
export interface ToolActivityMessage {
|
|
23
|
+
timestamp: Date | string;
|
|
24
|
+
toolCalls: readonly ToolActivityCall[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** A display-ready tool-activity entry for the Loop console. */
|
|
28
|
+
export interface LeadToolActivity {
|
|
29
|
+
/** Tool name, e.g. "Bash", "Read", "Edit". */
|
|
30
|
+
name: string;
|
|
31
|
+
/** Human-readable preview derived from the tool input. */
|
|
32
|
+
preview: string;
|
|
33
|
+
/** Runtime tool_use identifier when available. */
|
|
34
|
+
toolUseId?: string;
|
|
35
|
+
/** ISO timestamp inherited from the owning message. */
|
|
36
|
+
timestamp: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Build a short human-readable preview from a tool's input args. Mirrors the
|
|
41
|
+
* high-signal fields Claude Code users actually scan for (file paths, commands,
|
|
42
|
+
* patterns) without dumping raw JSON.
|
|
43
|
+
*/
|
|
44
|
+
export function formatToolPreview(name: string, input: Record<string, unknown>): string {
|
|
45
|
+
const str = (value: unknown): string => (typeof value === 'string' ? value : '');
|
|
46
|
+
|
|
47
|
+
switch (name) {
|
|
48
|
+
case 'Bash':
|
|
49
|
+
return str(input.command).trim();
|
|
50
|
+
case 'Read':
|
|
51
|
+
case 'Write':
|
|
52
|
+
case 'Edit':
|
|
53
|
+
case 'MultiEdit':
|
|
54
|
+
case 'NotebookEdit':
|
|
55
|
+
return str(input.file_path).trim();
|
|
56
|
+
case 'Grep':
|
|
57
|
+
case 'Glob': {
|
|
58
|
+
const pattern = str(input.pattern).trim();
|
|
59
|
+
const path = str(input.path).trim();
|
|
60
|
+
return pattern ? (path ? `${pattern} (in ${path})` : pattern) : path;
|
|
61
|
+
}
|
|
62
|
+
case 'Task':
|
|
63
|
+
case 'Agent': {
|
|
64
|
+
const description = str(input.description).trim();
|
|
65
|
+
const subagent = str(input.subagent_type).trim();
|
|
66
|
+
return description || subagent ? `${subagent ? `[${subagent}] ` : ''}${description}` : '';
|
|
67
|
+
}
|
|
68
|
+
case 'WebFetch':
|
|
69
|
+
return str(input.url).trim();
|
|
70
|
+
case 'WebSearch':
|
|
71
|
+
return str(input.query).trim();
|
|
72
|
+
case 'TodoWrite': {
|
|
73
|
+
const todos = Array.isArray(input.todos) ? input.todos : [];
|
|
74
|
+
return todos.length ? `${todos.length} todos` : '';
|
|
75
|
+
}
|
|
76
|
+
default: {
|
|
77
|
+
// Fall back to the first string-valued arg, if any.
|
|
78
|
+
for (const value of Object.values(input)) {
|
|
79
|
+
const text = str(value).trim();
|
|
80
|
+
if (text) return text.length > 80 ? `${text.slice(0, 80)}…` : text;
|
|
81
|
+
}
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Flatten the most recent tool calls from a parsed session, newest first.
|
|
89
|
+
*
|
|
90
|
+
* Tool calls inherit their owning message's timestamp (the wire format does not
|
|
91
|
+
* attach one per call), so ordering is stable at message granularity.
|
|
92
|
+
*/
|
|
93
|
+
export function extractRecentToolActivity(
|
|
94
|
+
messages: readonly ToolActivityMessage[],
|
|
95
|
+
limit: number
|
|
96
|
+
): LeadToolActivity[] {
|
|
97
|
+
if (limit <= 0) return [];
|
|
98
|
+
|
|
99
|
+
const activities: LeadToolActivity[] = [];
|
|
100
|
+
for (const message of messages) {
|
|
101
|
+
const timestamp =
|
|
102
|
+
message.timestamp instanceof Date
|
|
103
|
+
? message.timestamp.toISOString()
|
|
104
|
+
: String(message.timestamp);
|
|
105
|
+
for (const call of message.toolCalls) {
|
|
106
|
+
activities.push({
|
|
107
|
+
name: call.name,
|
|
108
|
+
preview: formatToolPreview(call.name, call.input),
|
|
109
|
+
toolUseId: call.id,
|
|
110
|
+
timestamp,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (activities.length <= limit) return activities.slice().reverse();
|
|
116
|
+
return activities.slice(activities.length - limit).reverse();
|
|
117
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { MentionSuggestion } from '@renderer/types/mention';
|
|
2
|
+
|
|
3
|
+
export interface LoopCommandShortcut {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
command: `/${string}`;
|
|
7
|
+
insertText: string;
|
|
8
|
+
description: string;
|
|
9
|
+
searchText: string;
|
|
10
|
+
category: 'monitoring' | 'summary' | 'hygiene' | 'diagnostic' | 'workflow';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// NOTE: the native `/loop` shortcuts were removed from the command palette —
|
|
14
|
+
// in the team console `/loop` is not a native command (it falls through to a
|
|
15
|
+
// plain lead message and never replies), so offering it caused confusion. The
|
|
16
|
+
// real loop feature will be reintroduced later. Only the `/hermit:*` workflows
|
|
17
|
+
// below remain as quick commands.
|
|
18
|
+
const LOOP_COMMAND_SHORTCUTS: LoopCommandShortcut[] = [
|
|
19
|
+
{
|
|
20
|
+
id: 'ops-workflow:doctor',
|
|
21
|
+
name: 'hermit:doctor',
|
|
22
|
+
command: '/hermit:doctor',
|
|
23
|
+
insertText: 'hermit:doctor 检查 Hermit 安装、运行时、cc-connect、MCP 和常见配置问题',
|
|
24
|
+
description: '诊断 Hermit / runtime / cc-connect 健康状态',
|
|
25
|
+
searchText: 'doctor hermit diagnose health runtime cc-connect mcp 诊断 健康 配置',
|
|
26
|
+
category: 'diagnostic',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'ops-workflow:loop-scan',
|
|
30
|
+
name: 'hermit:loop-scan',
|
|
31
|
+
command: '/hermit:loop-scan',
|
|
32
|
+
insertText: 'hermit:loop-scan 扫描 Loop 资产、推荐循环和可自动化的团队运维动作',
|
|
33
|
+
description: '扫描 Loop assets 和推荐运维循环',
|
|
34
|
+
searchText: 'loop scan hermit assets workflows recommended loops 扫描 推荐 循环',
|
|
35
|
+
category: 'workflow',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: 'ops-workflow:summary',
|
|
39
|
+
name: 'hermit:summary',
|
|
40
|
+
command: '/hermit:summary',
|
|
41
|
+
insertText: 'hermit:summary 总结当前团队进展、阻塞、风险和下一步建议',
|
|
42
|
+
description: '生成团队/会话摘要和下一步建议',
|
|
43
|
+
searchText: 'summary hermit status progress blockers risks next steps 摘要 进展 阻塞 风险',
|
|
44
|
+
category: 'summary',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'ops-workflow:daily-folder-hygiene',
|
|
48
|
+
name: 'hermit:daily-folder-hygiene',
|
|
49
|
+
command: '/hermit:daily-folder-hygiene',
|
|
50
|
+
insertText: 'hermit:daily-folder-hygiene 只读检查临时文件、陈旧报告、脏 worktree 和可清理产物',
|
|
51
|
+
description: '只读检查工作区卫生和可清理项',
|
|
52
|
+
searchText: 'daily folder hygiene hermit temp stale reports dirty worktree cleanup 工作区 清理',
|
|
53
|
+
category: 'hygiene',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'ops-workflow:daily-memory-conflict-check',
|
|
57
|
+
name: 'hermit:daily-memory-conflict-check',
|
|
58
|
+
command: '/hermit:daily-memory-conflict-check',
|
|
59
|
+
insertText:
|
|
60
|
+
'hermit:daily-memory-conflict-check 检查 CLAUDE、AGENTS、memory、settings 的重复或冲突指令',
|
|
61
|
+
description: '检查记忆/配置/指令冲突',
|
|
62
|
+
searchText:
|
|
63
|
+
'daily memory conflict hermit claude agents settings duplicate instructions 记忆 冲突',
|
|
64
|
+
category: 'hygiene',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'ops-workflow:daily-workflow-extraction',
|
|
68
|
+
name: 'hermit:daily-workflow-extraction',
|
|
69
|
+
command: '/hermit:daily-workflow-extraction',
|
|
70
|
+
insertText:
|
|
71
|
+
'hermit:daily-workflow-extraction 从近期工作中提炼可复用 workflow、prompt 和自动化建议',
|
|
72
|
+
description: '提炼可复用 workflow/prompt',
|
|
73
|
+
searchText: 'daily workflow extraction hermit reusable prompt automation 提炼 复用 自动化',
|
|
74
|
+
category: 'workflow',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
id: 'ops-workflow:worktree-scan',
|
|
78
|
+
name: 'hermit:worktree-scan',
|
|
79
|
+
command: '/hermit:worktree-scan',
|
|
80
|
+
insertText: 'hermit:worktree-scan 只读检查脏 worktree、陈旧分支和需要用户确认的清理项',
|
|
81
|
+
description: '只读检查 worktree/分支清理风险',
|
|
82
|
+
searchText: 'worktree scan hermit dirty stale branch cleanup readonly worktree 分支 清理',
|
|
83
|
+
category: 'diagnostic',
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
export function getLoopCommandShortcuts(): LoopCommandShortcut[] {
|
|
88
|
+
return LOOP_COMMAND_SHORTCUTS;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getLoopShortcutMentionSuggestions(): MentionSuggestion[] {
|
|
92
|
+
return LOOP_COMMAND_SHORTCUTS.map((shortcut) => ({
|
|
93
|
+
id: shortcut.id,
|
|
94
|
+
name: shortcut.name,
|
|
95
|
+
type: 'command',
|
|
96
|
+
command: shortcut.command,
|
|
97
|
+
insertText: shortcut.insertText,
|
|
98
|
+
description: shortcut.description,
|
|
99
|
+
subtitle: shortcut.description,
|
|
100
|
+
searchText: `${shortcut.searchText} ${shortcut.category}`,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function getLoopShortcutSuggestions(): MentionSuggestion[] {
|
|
105
|
+
return getLoopShortcutMentionSuggestions();
|
|
106
|
+
}
|
|
@@ -8,7 +8,7 @@ export function getSuggestionTriggerChar(suggestion: MentionSuggestion): '@' | '
|
|
|
8
8
|
|
|
9
9
|
export function getSuggestionInsertionText(suggestion: MentionSuggestion): string {
|
|
10
10
|
if (suggestion.type === 'command' || suggestion.type === 'skill') {
|
|
11
|
-
return suggestion.command?.slice(1) ?? suggestion.
|
|
11
|
+
return suggestion.insertText ?? suggestion.command?.slice(1) ?? suggestion.name;
|
|
12
12
|
}
|
|
13
13
|
return suggestion.insertText ?? suggestion.name;
|
|
14
14
|
}
|