@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
|
@@ -8,12 +8,24 @@ import type {
|
|
|
8
8
|
SystemManagerStatus,
|
|
9
9
|
} from '@shared/types/systemManager';
|
|
10
10
|
|
|
11
|
+
import { getGlobalHermitWorkflowDir } from './BuiltinWorkflowSeeder';
|
|
12
|
+
|
|
11
13
|
const CONFIG_FILE = 'system-manager.json';
|
|
12
14
|
|
|
13
15
|
function hermitHome(): string {
|
|
14
16
|
return process.env.HERMIT_HOME || path.join(os.homedir(), '.hermit');
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Canonical, isolated runtime path for the Helm Loop. Dedicated (never shared
|
|
21
|
+
* with another team/project) so the admin agent can bootstrap its own CLAUDE.md
|
|
22
|
+
* here without colliding with project work. Single source of truth — reused by
|
|
23
|
+
* `getSystemManagerWorkDir` (runtime) and `getStatus` (UI scope display).
|
|
24
|
+
*/
|
|
25
|
+
export function adminWorkDir(): string {
|
|
26
|
+
return path.join(hermitHome(), 'admin-workspace');
|
|
27
|
+
}
|
|
28
|
+
|
|
17
29
|
function expandHome(input: string): string {
|
|
18
30
|
const normalized = input.trim().replace(/^~/, '~');
|
|
19
31
|
if (normalized === '~') return os.homedir();
|
|
@@ -62,6 +74,7 @@ export class SystemManagerConfigService {
|
|
|
62
74
|
schemaVersion: 1,
|
|
63
75
|
selectedWorkDir,
|
|
64
76
|
...(workflowFolder ? { workflowFolder } : {}),
|
|
77
|
+
...(parsed.adminInitialized ? { adminInitialized: true } : {}),
|
|
65
78
|
updatedAt:
|
|
66
79
|
typeof parsed.updatedAt === 'string' ? parsed.updatedAt : new Date().toISOString(),
|
|
67
80
|
};
|
|
@@ -92,6 +105,9 @@ export class SystemManagerConfigService {
|
|
|
92
105
|
} else if (typeof patch.workflowFolder === 'string') {
|
|
93
106
|
next.workflowFolder = await this.normalizeDirectory(patch.workflowFolder, 'workflowFolder');
|
|
94
107
|
}
|
|
108
|
+
if (typeof patch.adminInitialized === 'boolean') {
|
|
109
|
+
next.adminInitialized = patch.adminInitialized;
|
|
110
|
+
}
|
|
95
111
|
|
|
96
112
|
await mkdir(path.dirname(this.configPath), { recursive: true });
|
|
97
113
|
await writeFile(this.configPath, JSON.stringify(next, null, 2), 'utf-8');
|
|
@@ -102,10 +118,12 @@ export class SystemManagerConfigService {
|
|
|
102
118
|
const config = await this.getConfig();
|
|
103
119
|
const hasClaude = await commandExists('claude');
|
|
104
120
|
return {
|
|
105
|
-
displayName: '
|
|
121
|
+
displayName: 'Helm Loop',
|
|
122
|
+
adminWorkDir: adminWorkDir(),
|
|
106
123
|
defaultWorkDir: this.defaultWorkDir,
|
|
107
124
|
selectedWorkDir: config.selectedWorkDir,
|
|
108
125
|
...(config.workflowFolder ? { workflowFolder: config.workflowFolder } : {}),
|
|
126
|
+
globalHermitWorkflowFolder: getGlobalHermitWorkflowDir(),
|
|
109
127
|
claudeCommand: 'claude',
|
|
110
128
|
localStatus: hasClaude ? 'ready' : 'missing-claude',
|
|
111
129
|
...(hasClaude ? {} : { error: '未在 PATH 中找到 claude 命令' }),
|
|
@@ -9,6 +9,11 @@ import type {
|
|
|
9
9
|
WorkflowPromptSummary,
|
|
10
10
|
} from '@shared/types/systemManager';
|
|
11
11
|
|
|
12
|
+
import {
|
|
13
|
+
getBuiltinWorkflowByFilename,
|
|
14
|
+
type BuiltinWorkflowDefinition,
|
|
15
|
+
} from './BuiltinWorkflowSeeder';
|
|
16
|
+
|
|
12
17
|
const SUPPORTED_EXTENSIONS = new Set(['.md', '.txt', '.prompt', '.workflow']);
|
|
13
18
|
const MAX_PROMPT_BYTES = 256 * 1024;
|
|
14
19
|
|
|
@@ -27,17 +32,49 @@ function labelFromFilename(filename: string): string {
|
|
|
27
32
|
return path.basename(filename, path.extname(filename)).replace(/[-_]+/g, ' ').trim() || filename;
|
|
28
33
|
}
|
|
29
34
|
|
|
35
|
+
function getClaudeCommandRoot(folder: string): string | null {
|
|
36
|
+
const normalized = path.normalize(folder);
|
|
37
|
+
const commandsSuffix = path.join('.claude', 'commands');
|
|
38
|
+
if (normalized.endsWith(commandsSuffix)) return normalized;
|
|
39
|
+
const parent = path.dirname(normalized);
|
|
40
|
+
return parent.endsWith(commandsSuffix) ? parent : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function commandNameFromRelativePath(relativePath: string): `/${string}` {
|
|
44
|
+
const withoutExt = relativePath.slice(0, -path.extname(relativePath).length);
|
|
45
|
+
const commandName = withoutExt.split(path.sep).filter(Boolean).join(':');
|
|
46
|
+
return `/${commandName}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function applyBuiltinMetadata(
|
|
50
|
+
summary: WorkflowPromptSummary,
|
|
51
|
+
builtin: BuiltinWorkflowDefinition | undefined
|
|
52
|
+
): WorkflowPromptSummary {
|
|
53
|
+
if (!builtin) return summary;
|
|
54
|
+
return {
|
|
55
|
+
...summary,
|
|
56
|
+
label: builtin.label,
|
|
57
|
+
commandName: summary.commandName ?? builtin.commandName,
|
|
58
|
+
description: builtin.description,
|
|
59
|
+
category: builtin.category,
|
|
60
|
+
safety: builtin.safety,
|
|
61
|
+
builtin: true,
|
|
62
|
+
order: builtin.order,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
30
66
|
export class WorkflowPromptService {
|
|
31
67
|
async list(folderInput: string): Promise<WorkflowPromptListResponse> {
|
|
32
68
|
const folder = path.resolve(expandHome(folderInput));
|
|
33
69
|
const folderStat = await stat(folder);
|
|
34
70
|
if (!folderStat.isDirectory()) {
|
|
35
|
-
throw new Error(`
|
|
71
|
+
throw new Error(`Loop command folder 不是有效目录: ${folder}`);
|
|
36
72
|
}
|
|
37
73
|
|
|
38
74
|
const warnings: string[] = [];
|
|
39
75
|
const prompts: WorkflowPromptSummary[] = [];
|
|
40
76
|
const entries = await readdir(folder, { withFileTypes: true });
|
|
77
|
+
const commandRoot = getClaudeCommandRoot(folder);
|
|
41
78
|
|
|
42
79
|
for (const entry of entries) {
|
|
43
80
|
if (!entry.isFile() || entry.name.startsWith('.')) continue;
|
|
@@ -49,17 +86,33 @@ export class WorkflowPromptService {
|
|
|
49
86
|
warnings.push(`${entry.name} 超过 256 KiB,已跳过`);
|
|
50
87
|
continue;
|
|
51
88
|
}
|
|
52
|
-
|
|
89
|
+
|
|
90
|
+
const relativeCommandPath = commandRoot ? path.relative(commandRoot, filePath) : entry.name;
|
|
91
|
+
const commandName = commandRoot
|
|
92
|
+
? commandNameFromRelativePath(relativeCommandPath)
|
|
93
|
+
: undefined;
|
|
94
|
+
const builtin = commandRoot ? getBuiltinWorkflowByFilename(entry.name) : undefined;
|
|
95
|
+
const summary: WorkflowPromptSummary = {
|
|
53
96
|
id: promptId(filePath),
|
|
54
97
|
label: labelFromFilename(entry.name),
|
|
55
98
|
filename: entry.name,
|
|
56
99
|
path: filePath,
|
|
100
|
+
folder,
|
|
57
101
|
sizeBytes: fileStat.size,
|
|
58
102
|
updatedAt: fileStat.mtime.toISOString(),
|
|
59
|
-
|
|
103
|
+
source: commandRoot ? 'claude-command' : 'workflow-folder',
|
|
104
|
+
commandName,
|
|
105
|
+
safety: commandRoot ? 'unknown' : undefined,
|
|
106
|
+
};
|
|
107
|
+
prompts.push(applyBuiltinMetadata(summary, builtin));
|
|
60
108
|
}
|
|
61
109
|
|
|
62
|
-
prompts.sort((a, b) =>
|
|
110
|
+
prompts.sort((a, b) => {
|
|
111
|
+
const orderA = a.order ?? Number.MAX_SAFE_INTEGER;
|
|
112
|
+
const orderB = b.order ?? Number.MAX_SAFE_INTEGER;
|
|
113
|
+
if (orderA !== orderB) return orderA - orderB;
|
|
114
|
+
return a.filename.localeCompare(b.filename);
|
|
115
|
+
});
|
|
63
116
|
return { folder, prompts, warnings };
|
|
64
117
|
}
|
|
65
118
|
|
|
@@ -67,7 +120,7 @@ export class WorkflowPromptService {
|
|
|
67
120
|
const list = await this.list(folderInput);
|
|
68
121
|
const prompt = list.prompts.find((item) => item.id === id || item.filename === id);
|
|
69
122
|
if (!prompt) {
|
|
70
|
-
throw new Error(`未找到 workflow: ${id}`);
|
|
123
|
+
throw new Error(`未找到 Loop workflow: ${id}`);
|
|
71
124
|
}
|
|
72
125
|
const content = await readFile(prompt.path, 'utf-8');
|
|
73
126
|
return { prompt, content };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ADMIN_INIT_MESSAGE_ID,
|
|
5
|
+
buildAdminInitMessage,
|
|
6
|
+
ensureAdminLoopInitialized,
|
|
7
|
+
htmlToPlainText,
|
|
8
|
+
type AdminLoopInitDeps,
|
|
9
|
+
} from '../AdminLoopInitializer';
|
|
10
|
+
import type { SystemManagerConfig, SystemManagerConfigPatch } from '@shared/types/systemManager';
|
|
11
|
+
|
|
12
|
+
interface Recorder {
|
|
13
|
+
getConfig: ReturnType<typeof vi.fn>;
|
|
14
|
+
updateConfig: ReturnType<typeof vi.fn>;
|
|
15
|
+
fetchGuide: ReturnType<typeof vi.fn>;
|
|
16
|
+
dispatch: ReturnType<typeof vi.fn>;
|
|
17
|
+
log: ReturnType<typeof vi.fn>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function makeDeps(overrides?: Partial<Recorder>): Recorder & AdminLoopInitDeps {
|
|
21
|
+
const r: Recorder = {
|
|
22
|
+
getConfig: vi.fn(async () => ({ schemaVersion: 1, selectedWorkDir: '/x', updatedAt: 't' })),
|
|
23
|
+
updateConfig: vi.fn(
|
|
24
|
+
async (patch: SystemManagerConfigPatch) =>
|
|
25
|
+
({
|
|
26
|
+
schemaVersion: 1,
|
|
27
|
+
selectedWorkDir: '/x',
|
|
28
|
+
updatedAt: 't',
|
|
29
|
+
...patch,
|
|
30
|
+
}) as SystemManagerConfig
|
|
31
|
+
),
|
|
32
|
+
fetchGuide: vi.fn(async () => ({ statusCode: 200, body: '<p>hello manual</p>' })),
|
|
33
|
+
dispatch: vi.fn(async () => undefined),
|
|
34
|
+
log: vi.fn(),
|
|
35
|
+
...overrides,
|
|
36
|
+
};
|
|
37
|
+
return r as Recorder & AdminLoopInitDeps;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe('htmlToPlainText', () => {
|
|
41
|
+
it('strips script/style and tags, decodes entities, collapses whitespace', () => {
|
|
42
|
+
const html =
|
|
43
|
+
'<style>.x{}</style><script>alert(1)</script><h1>Title</h1><p>a &b</p><!--c-->';
|
|
44
|
+
expect(htmlToPlainText(html)).toBe('Title\na &b');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('returns empty string for whitespace-only input', () => {
|
|
48
|
+
expect(htmlToPlainText(' \n ')).toBe('');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('buildAdminInitMessage', () => {
|
|
53
|
+
it('wraps the guide text with the bootstrap instructions', () => {
|
|
54
|
+
const msg = buildAdminInitMessage('MANUAL_BODY');
|
|
55
|
+
expect(msg).toContain('Helm Loop 初始化');
|
|
56
|
+
expect(msg).toContain('MANUAL_BODY');
|
|
57
|
+
expect(msg).toContain('/workers');
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('ensureAdminLoopInitialized', () => {
|
|
62
|
+
afterEach(() => vi.clearAllMocks());
|
|
63
|
+
|
|
64
|
+
it('is idempotent: skips fetch + dispatch + updateConfig when already initialized', async () => {
|
|
65
|
+
const deps = makeDeps({
|
|
66
|
+
getConfig: vi.fn(async () => ({
|
|
67
|
+
schemaVersion: 1,
|
|
68
|
+
selectedWorkDir: '/x',
|
|
69
|
+
updatedAt: 't',
|
|
70
|
+
adminInitialized: true,
|
|
71
|
+
})),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
await ensureAdminLoopInitialized(deps);
|
|
75
|
+
|
|
76
|
+
expect(deps.fetchGuide).not.toHaveBeenCalled();
|
|
77
|
+
expect(deps.dispatch).not.toHaveBeenCalled();
|
|
78
|
+
expect(deps.updateConfig).not.toHaveBeenCalled();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('does NOT set the marker when the guide fetch rejects', async () => {
|
|
82
|
+
const deps = makeDeps({
|
|
83
|
+
fetchGuide: vi.fn(async () => {
|
|
84
|
+
throw new Error('network down');
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
await ensureAdminLoopInitialized(deps);
|
|
89
|
+
|
|
90
|
+
expect(deps.dispatch).not.toHaveBeenCalled();
|
|
91
|
+
expect(deps.updateConfig).not.toHaveBeenCalled();
|
|
92
|
+
expect(deps.log).toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('does NOT set the marker on non-2xx status', async () => {
|
|
96
|
+
const deps = makeDeps({
|
|
97
|
+
fetchGuide: vi.fn(async () => ({ statusCode: 503, body: 'unavailable' })),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
await ensureAdminLoopInitialized(deps);
|
|
101
|
+
|
|
102
|
+
expect(deps.dispatch).not.toHaveBeenCalled();
|
|
103
|
+
expect(deps.updateConfig).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('does NOT set the marker when the body is empty', async () => {
|
|
107
|
+
const deps = makeDeps({
|
|
108
|
+
fetchGuide: vi.fn(async () => ({ statusCode: 200, body: '<script>x</script>' })),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
await ensureAdminLoopInitialized(deps);
|
|
112
|
+
|
|
113
|
+
expect(deps.dispatch).not.toHaveBeenCalled();
|
|
114
|
+
expect(deps.updateConfig).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('on success dispatches the wrapped guide and sets adminInitialized=true', async () => {
|
|
118
|
+
const deps = makeDeps();
|
|
119
|
+
|
|
120
|
+
await ensureAdminLoopInitialized(deps);
|
|
121
|
+
|
|
122
|
+
expect(deps.fetchGuide).toHaveBeenCalledTimes(1);
|
|
123
|
+
expect(deps.dispatch).toHaveBeenCalledWith({
|
|
124
|
+
text: buildAdminInitMessage('hello manual'),
|
|
125
|
+
messageId: ADMIN_INIT_MESSAGE_ID,
|
|
126
|
+
});
|
|
127
|
+
expect(deps.updateConfig).toHaveBeenCalledWith({ adminInitialized: true });
|
|
128
|
+
});
|
|
129
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
import { SystemManagerConfigService, adminWorkDir } from '../SystemManagerConfigService';
|
|
7
|
+
|
|
8
|
+
const PREV_HERMIT_HOME = process.env.HERMIT_HOME;
|
|
9
|
+
let workdir: string;
|
|
10
|
+
|
|
11
|
+
beforeAll(async () => {
|
|
12
|
+
workdir = await mkdtemp(path.join(tmpdir(), 'hermit-admin-cfg-'));
|
|
13
|
+
process.env.HERMIT_HOME = workdir;
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
if (PREV_HERMIT_HOME === undefined) delete process.env.HERMIT_HOME;
|
|
18
|
+
else process.env.HERMIT_HOME = PREV_HERMIT_HOME;
|
|
19
|
+
void rm(workdir, { recursive: true, force: true });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('adminWorkDir', () => {
|
|
23
|
+
it('points at <hermit-home>/admin-workspace', () => {
|
|
24
|
+
expect(adminWorkDir()).toBe(path.join(workdir, 'admin-workspace'));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('SystemManagerConfigService.adminInitialized', () => {
|
|
29
|
+
it('round-trips the marker and persists it across instances', async () => {
|
|
30
|
+
const svc = new SystemManagerConfigService(workdir);
|
|
31
|
+
|
|
32
|
+
expect((await svc.getConfig()).adminInitialized).toBeUndefined();
|
|
33
|
+
|
|
34
|
+
await svc.updateConfig({ adminInitialized: true });
|
|
35
|
+
expect((await svc.getConfig()).adminInitialized).toBe(true);
|
|
36
|
+
|
|
37
|
+
// A fresh instance reads the same file → marker survives a restart.
|
|
38
|
+
const reopened = new SystemManagerConfigService(workdir);
|
|
39
|
+
expect((await reopened.getConfig()).adminInitialized).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('preserves adminInitialized when patching an unrelated field', async () => {
|
|
43
|
+
const svc = new SystemManagerConfigService(workdir);
|
|
44
|
+
await svc.updateConfig({ adminInitialized: true });
|
|
45
|
+
await svc.updateConfig({ selectedWorkDir: workdir });
|
|
46
|
+
|
|
47
|
+
const config = await svc.getConfig();
|
|
48
|
+
expect(config.selectedWorkDir).toBe(workdir);
|
|
49
|
+
expect(config.adminInitialized).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('SystemManagerConfigService.getStatus', () => {
|
|
54
|
+
it('reports the Helm Loop identity and the admin workDir', async () => {
|
|
55
|
+
const svc = new SystemManagerConfigService(workdir);
|
|
56
|
+
const status = await svc.getStatus();
|
|
57
|
+
expect(status.displayName).toBe('Helm Loop');
|
|
58
|
+
expect(status.adminWorkDir).toBe(path.join(workdir, 'admin-workspace'));
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -50,8 +50,10 @@ function normalizeTask(task: CollabTask): CollabTask {
|
|
|
50
50
|
function eventTypeForStatus(status: CollabTaskStatus): CollabTaskEventType {
|
|
51
51
|
switch (status) {
|
|
52
52
|
case 'pending_accept':
|
|
53
|
+
case 'received':
|
|
53
54
|
return 'task_sent';
|
|
54
55
|
case 'accepted':
|
|
56
|
+
case 'in_progress':
|
|
55
57
|
return 'task_accepted';
|
|
56
58
|
case 'delivered':
|
|
57
59
|
return 'task_delivered';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compact Hermit operations context injected into managed agent instructions.
|
|
3
|
+
*
|
|
4
|
+
* Keep this short: agents need the stable runbook boundary and pointers, not the
|
|
5
|
+
* full public guide copied into every session.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export const HERMIT_OPS_GUIDE_URL = 'https://yancyuu.github.io/Hermit/';
|
|
9
|
+
|
|
10
|
+
const OPS_CONTEXT_BEGIN = '<!-- hermit:ops-runbook-context:start -->';
|
|
11
|
+
const OPS_CONTEXT_END = '<!-- hermit:ops-runbook-context:end -->';
|
|
12
|
+
|
|
13
|
+
const OPS_RUNBOOK_CONTEXT = `## Hermit Ops Runbook Context
|
|
14
|
+
|
|
15
|
+
Public operations guide: ${HERMIT_OPS_GUIDE_URL}
|
|
16
|
+
Local canonical docs: README.md, docs/README.md, docs/team-management/README.md
|
|
17
|
+
|
|
18
|
+
Hermit/openHermit is a local-first Loop Engineering control plane. Use /teams as the
|
|
19
|
+
main operations surface and treat ~/.hermit/ as the default local data directory.
|
|
20
|
+
Hermit coordinates teams, tasks, message routing, channel allowlists, audit trails,
|
|
21
|
+
and Loop workflows; actual runtime execution is delegated to the local Agent CLI /
|
|
22
|
+
cc-connect Bridge / Management API.
|
|
23
|
+
|
|
24
|
+
Common ops workflows to suggest or use when appropriate. Hermit preinstalls them as
|
|
25
|
+
user-level Claude commands under ~/.claude/commands/hermit/ so every team can run
|
|
26
|
+
the same namespaced commands from its own cwd:
|
|
27
|
+
- /hermit:doctor — diagnose install/runtime/config health.
|
|
28
|
+
- /hermit:loop-scan — inspect Loop assets and recommended recurring loops.
|
|
29
|
+
- /hermit:summary — summarize team/session status and next actions.
|
|
30
|
+
- /hermit:daily-folder-hygiene — check temporary files, stale reports, and workspace clutter.
|
|
31
|
+
- /hermit:daily-memory-conflict-check — check CLAUDE/AGENTS/memory/settings conflicts.
|
|
32
|
+
- /hermit:daily-workflow-extraction — extract reusable prompts/workflows from recent work.
|
|
33
|
+
- /hermit:worktree-scan — inspect dirty or stale worktrees before cleanup decisions.
|
|
34
|
+
|
|
35
|
+
Safety boundary for operations workflows:
|
|
36
|
+
- Default to read-only diagnosis. Do not modify, delete, move, format, commit, push,
|
|
37
|
+
publish, deploy, or run destructive commands unless the user explicitly approves.
|
|
38
|
+
- Explain the purpose before commands; prefer read-only commands for diagnostics.
|
|
39
|
+
- Do not expose secrets, tokens, cookies, private keys, or full sensitive paths.
|
|
40
|
+
- If a fix is needed, report recommendations, verification steps, and an optional
|
|
41
|
+
patch plan before applying changes.
|
|
42
|
+
- Treat the public guide and local docs as operational references; verify against
|
|
43
|
+
the current repository/config before making exact claims.`;
|
|
44
|
+
|
|
45
|
+
export function buildHermitOpsRunbookContext(): string {
|
|
46
|
+
return `${OPS_CONTEXT_BEGIN}\n\n${OPS_RUNBOOK_CONTEXT}\n\n${OPS_CONTEXT_END}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function removeHermitOpsRunbookContext(content: string): string {
|
|
50
|
+
return content
|
|
51
|
+
.replace(new RegExp(`\\n{0,2}${OPS_CONTEXT_BEGIN}[\\s\\S]*?${OPS_CONTEXT_END}\\n?`, 'g'), '\n')
|
|
52
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
53
|
+
.trimEnd();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function buildMemberWorkflowWithOpsContext(memberWorkflow?: string): string {
|
|
57
|
+
const workflow = removeHermitOpsRunbookContext(memberWorkflow ?? '').trim();
|
|
58
|
+
const context = buildHermitOpsRunbookContext();
|
|
59
|
+
return workflow ? `${workflow}\n\n${context}` : context;
|
|
60
|
+
}
|