@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.
Files changed (281) hide show
  1. package/README.md +98 -89
  2. package/bin/hermit.mjs +96 -0
  3. package/dist-renderer/assets/{ProjectEditorOverlay-DlFQ6mai.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
  4. package/dist-renderer/assets/{TeamGraphOverlay-D2TPMPGR.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
  5. package/dist-renderer/assets/{_basePickBy-Cmd0RHLQ.js → _basePickBy-ZOyLWjMK.js} +1 -1
  6. package/dist-renderer/assets/{_baseUniq-BI_iy8ea.js → _baseUniq-DBb726rt.js} +1 -1
  7. package/dist-renderer/assets/{arc-NzW2mjTP.js → arc-CdiTaR_R.js} +1 -1
  8. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Bzq85AYv.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
  9. package/dist-renderer/assets/{blockDiagram-VD42YOAC-D1PvYS-b.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
  10. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-D49RKzPC.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
  11. package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
  12. package/dist-renderer/assets/{chunk-4BX2VUAB-fmI_MQmQ.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
  13. package/dist-renderer/assets/{chunk-55IACEB6-Xsv9RCXZ.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
  14. package/dist-renderer/assets/{chunk-B4BG7PRW-BE1KO8Um.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
  15. package/dist-renderer/assets/{chunk-DI55MBZ5-tqJ7Mv7f.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
  16. package/dist-renderer/assets/{chunk-FMBD7UC4-DMD45MVJ.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QN33PNHL-DOhGrz-q.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QZHKN3VN-D8yDgJdD.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
  19. package/dist-renderer/assets/{chunk-TZMSLE5B-BcsEDu7A.js → chunk-TZMSLE5B-BQEil57G.js} +1 -1
  20. package/dist-renderer/assets/classDiagram-2ON5EDUG-lpzulY5X.js +1 -0
  21. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-lpzulY5X.js +1 -0
  22. package/dist-renderer/assets/clone-CriGymY9.js +1 -0
  23. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DlSqGHMX.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
  24. package/dist-renderer/assets/{dagre-6UL2VRFP-BTT9tSAx.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
  25. package/dist-renderer/assets/{diagram-PSM6KHXK-Du-U-mK2.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
  26. package/dist-renderer/assets/{diagram-QEK2KX5R-jFdHeKas.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
  27. package/dist-renderer/assets/{diagram-S2PKOQOG-DKLNK2bu.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
  28. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-CZxHgIIo.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
  29. package/dist-renderer/assets/{flowDiagram-NV44I4VS-v4XStCD0.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
  30. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DJjD_BEL.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
  31. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BNy-jr03.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
  32. package/dist-renderer/assets/{graph-DDTrn6je.js → graph-CDP_R8ct.js} +1 -1
  33. package/dist-renderer/assets/{index-BBp78BAu.js → index-BSZdT-g-.js} +1 -1
  34. package/dist-renderer/assets/{index-eotrJaYy.js → index-BhWvMqsz.js} +1 -1
  35. package/dist-renderer/assets/{index-D8_B-cfs.js → index-C2_AupSj.js} +1 -1
  36. package/dist-renderer/assets/{index-BQrwHZ-k.js → index-C5ujiwAR.js} +580 -588
  37. package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
  38. package/dist-renderer/assets/{index-CRKQSG9S.js → index-CVNjLwkq.js} +1 -1
  39. package/dist-renderer/assets/{index-DR6Wz52b.js → index-CwG3se0q.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DqnOsuza.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DTobaO1d.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-HbwVOvWc.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
  43. package/dist-renderer/assets/{layout--VYmTcw2.js → layout-5nA5wUxO.js} +1 -1
  44. package/dist-renderer/assets/{linear-BsJh89Mr.js → linear-BtF1i2qN.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-BZqUZePd.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-B1q_nH6P.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-UD8QhSEu.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BA_i7Nw8.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-CMTnX-2d.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-BQXDB615.js → sequenceDiagram-WL72ISMW-CJg-WYyY.js} +1 -1
  51. package/dist-renderer/assets/{splashScene-D0YB9uxm.js → splashScene-94xWCzLA.js} +1 -1
  52. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BAsPXy6X.js → stateDiagram-FKZM4ZOC-DWHOoFdv.js} +1 -1
  53. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-CGYZOoMb.js +1 -0
  54. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BdasmVkC.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
  55. package/dist-renderer/assets/{treemap-GDKQZRPO-BkKQqIui.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
  56. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-EAlPHOdx.js → xychartDiagram-PRI3JC2R-CCOcGbrD.js} +1 -1
  57. package/dist-renderer/chat-community-qr.jpg +0 -0
  58. package/dist-renderer/fonts/Agave-Bold.ttf +0 -0
  59. package/dist-renderer/fonts/Agave-Regular.ttf +0 -0
  60. package/dist-renderer/icon.png +0 -0
  61. package/dist-renderer/icon.rar +0 -0
  62. package/dist-renderer/index.html +3 -3
  63. package/package.json +21 -26
  64. package/src/features/worker-society/core/application/WorkerSocietyService.test.ts +802 -0
  65. package/src/features/worker-society/core/application/WorkerSocietyService.ts +428 -0
  66. package/src/features/worker-society/core/application/fakes.ts +101 -0
  67. package/src/features/worker-society/core/application/ports.ts +70 -0
  68. package/src/features/worker-society/core/domain/models/society.ts +141 -0
  69. package/src/features/worker-society/core/domain/policies/societyPolicies.test.ts +739 -0
  70. package/src/features/worker-society/core/domain/policies/societyPolicies.ts +496 -0
  71. package/src/features/worker-society/main/adapters/input/societyMcp.test.ts +317 -0
  72. package/src/features/worker-society/main/adapters/input/societyMcp.ts +257 -0
  73. package/src/features/worker-society/main/adapters/input/societyRoutes.test.ts +695 -0
  74. package/src/features/worker-society/main/adapters/input/societyRoutes.ts +194 -0
  75. package/src/features/worker-society/main/composition/societyComposition.test.ts +74 -0
  76. package/src/features/worker-society/main/composition/societyComposition.ts +70 -0
  77. package/src/features/worker-society/main/composition/workerSocietyPlugin.test.ts +69 -0
  78. package/src/features/worker-society/main/composition/workerSocietyPlugin.ts +67 -0
  79. package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.test.ts +132 -0
  80. package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.ts +84 -0
  81. package/src/features/worker-society/main/infrastructure/fsStores.test.ts +216 -0
  82. package/src/features/worker-society/main/infrastructure/fsStores.ts +113 -0
  83. package/src/features/worker-society/main/infrastructure/mergingProfileStore.test.ts +195 -0
  84. package/src/features/worker-society/main/infrastructure/mergingProfileStore.ts +96 -0
  85. package/src/features/worker-society/renderer/SocietyGraph.tsx +166 -0
  86. package/src/features/worker-society/renderer/SocietyNodeLabels.tsx +139 -0
  87. package/src/features/worker-society/renderer/SocietyNodeOverlay.tsx +339 -0
  88. package/src/features/worker-society/renderer/SocietyView.tsx +437 -0
  89. package/src/features/worker-society/renderer/index.ts +11 -0
  90. package/src/features/worker-society/renderer/societyApi.test.ts +259 -0
  91. package/src/features/worker-society/renderer/societyApi.ts +144 -0
  92. package/src/features/worker-society/renderer/societyGraphAdapter.test.ts +321 -0
  93. package/src/features/worker-society/renderer/societyGraphAdapter.ts +240 -0
  94. package/src/features/worker-society/renderer/societyOverlayActions.test.ts +57 -0
  95. package/src/features/worker-society/renderer/societyOverlayActions.ts +49 -0
  96. package/src/features/worker-society/renderer/societyStore.test.ts +218 -0
  97. package/src/features/worker-society/renderer/societyStore.ts +146 -0
  98. package/src/features/worker-society/renderer/societyViewUtils.test.ts +81 -0
  99. package/src/features/worker-society/renderer/societyViewUtils.ts +68 -0
  100. package/src/main/ipc/extensions.ts +27 -0
  101. package/src/main/server.ts +1709 -534
  102. package/src/main/services/ccConnect/CcConnectBridge.ts +26 -11
  103. package/src/main/services/ccConnect/CcConnectClient.ts +9 -2
  104. package/src/main/services/ccConnect/workDirReconcile.test.ts +57 -0
  105. package/src/main/services/ccConnect/workDirReconcile.ts +36 -0
  106. package/src/main/services/direct-cli/DirectCliSessionManager.test.ts +397 -0
  107. package/src/main/services/direct-cli/DirectCliSessionManager.ts +508 -0
  108. package/src/main/services/direct-cli/DirectCliSessionStore.test.ts +79 -0
  109. package/src/main/services/direct-cli/DirectCliSessionStore.ts +97 -0
  110. package/src/main/services/direct-cli/__tests__/directCliMessageId.test.ts +40 -0
  111. package/src/main/services/direct-cli/directCliMessageId.ts +21 -0
  112. package/src/main/services/direct-cli/index.ts +17 -0
  113. package/src/main/services/extensions/capability-packs/CapabilityPackLoaderService.ts +637 -0
  114. package/src/main/services/extensions/catalog/PluginCatalogService.ts +2 -2
  115. package/src/main/services/loop-assets/LoopAssetsScannerService.ts +657 -0
  116. package/src/main/services/runtime/providerAwareCliEnv.ts +33 -5
  117. package/src/main/services/session-intelligence/LocalSessionScanner.ts +156 -71
  118. package/src/main/services/session-intelligence/SessionUsageParser.ts +103 -8
  119. package/src/main/services/session-intelligence/UsageTelemetryService.ts +11 -0
  120. package/src/main/services/session-intelligence/__tests__/teamSessionListMapper.test.ts +104 -0
  121. package/src/main/services/session-intelligence/teamSessionListMapper.ts +78 -0
  122. package/src/main/services/system-manager/AdminLoopInitializer.ts +95 -0
  123. package/src/main/services/system-manager/BuiltinWorkflowSeeder.ts +679 -74
  124. package/src/main/services/system-manager/SystemManagerConfigService.ts +19 -1
  125. package/src/main/services/system-manager/WorkflowPromptService.ts +58 -5
  126. package/src/main/services/system-manager/__tests__/AdminLoopInitializer.test.ts +129 -0
  127. package/src/main/services/system-manager/__tests__/SystemManagerConfigService.test.ts +60 -0
  128. package/src/main/services/teams-mvp/CollaborationBoardService.ts +2 -0
  129. package/src/main/services/teams-mvp/OpsRunbookContext.ts +60 -0
  130. package/src/main/services/teams-mvp/TaskDispatchService.test.ts +305 -0
  131. package/src/main/services/teams-mvp/TaskDispatchService.ts +250 -131
  132. package/src/main/services/teams-mvp/TeamProvisioningService.ts +12 -2
  133. package/src/main/services/teams-mvp/TeamWorkspaceService.test.ts +207 -0
  134. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +104 -51
  135. package/src/main/services/teams-mvp/index.ts +6 -0
  136. package/src/main/utils/externalPlatformSessionRouting.ts +92 -0
  137. package/src/main/utils/toolApprovalRules.ts +151 -0
  138. package/src/renderer/App.tsx +24 -89
  139. package/src/renderer/api/httpClient.ts +115 -37
  140. package/src/renderer/api/providers.ts +5 -16
  141. package/src/renderer/components/chat/CommunityChatView.tsx +81 -0
  142. package/src/renderer/components/dashboard/DashboardView.tsx +130 -84
  143. package/src/renderer/components/extensions/ExtensionStoreView.tsx +39 -5
  144. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +2 -1
  145. package/src/renderer/components/extensions/capability-packs/CapabilityPacksPanel.tsx +170 -0
  146. package/src/renderer/components/layout/PaneContent.tsx +10 -2
  147. package/src/renderer/components/layout/SortableTab.tsx +4 -0
  148. package/src/renderer/components/layout/TabBarActions.tsx +13 -16
  149. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +4 -135
  150. package/src/renderer/components/schedules/SchedulesView.tsx +22 -14
  151. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +7 -6
  152. package/src/renderer/components/settings/SettingsTabs.tsx +24 -21
  153. package/src/renderer/components/settings/SettingsView.tsx +22 -13
  154. package/src/renderer/components/settings/components/SettingRow.tsx +13 -5
  155. package/src/renderer/components/settings/components/SettingsSectionCard.tsx +53 -0
  156. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +10 -6
  157. package/src/renderer/components/settings/components/SettingsSelect.tsx +12 -9
  158. package/src/renderer/components/settings/components/SettingsToggle.tsx +6 -5
  159. package/src/renderer/components/settings/components/index.ts +1 -0
  160. package/src/renderer/components/settings/sections/AdvancedSection.tsx +78 -59
  161. package/src/renderer/components/settings/sections/CliStatusSection.tsx +32 -44
  162. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  163. package/src/renderer/components/settings/sections/GeneralSection.tsx +216 -186
  164. package/src/renderer/components/settings/sections/PlatformsSection.tsx +25 -17
  165. package/src/renderer/components/settings/sections/TaskBusSection.tsx +63 -22
  166. package/src/renderer/components/sidebar/SidebarSessions.tsx +120 -80
  167. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +1 -1
  168. package/src/renderer/components/splash/splashScene.ts +6 -2
  169. package/src/renderer/components/system-manager/SystemManagerView.tsx +169 -255
  170. package/src/renderer/components/tasks/TasksView.tsx +63 -37
  171. package/src/renderer/components/team/CcSessionsSection.tsx +124 -89
  172. package/src/renderer/components/team/HarnessBrandLogos.tsx +318 -0
  173. package/src/renderer/components/team/HarnessSelect.tsx +25 -26
  174. package/src/renderer/components/team/TeamDetailView.tsx +137 -153
  175. package/src/renderer/components/team/TeamEmptyState.tsx +9 -37
  176. package/src/renderer/components/team/TeamListView.tsx +143 -30
  177. package/src/renderer/components/team/__tests__/CcSessionsSection.hasLocalFile.test.tsx +128 -0
  178. package/src/renderer/components/team/activity/ActivityItem.tsx +21 -9
  179. package/src/renderer/components/team/activity/ActivityTimeline.tsx +2 -2
  180. package/src/renderer/components/team/dialogs/AdvancedCliSection.tsx +1 -1
  181. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +13 -10
  182. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +156 -83
  183. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +9 -157
  184. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +19 -15
  185. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +48 -10
  186. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +11 -12
  187. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +39 -37
  188. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +434 -64
  189. package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +12 -10
  190. package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +2 -2
  191. package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.bindProject.test.tsx +399 -0
  192. package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.chineseRepro.test.tsx +253 -0
  193. package/src/renderer/components/team/dialogs/platformAllowUtils.ts +91 -0
  194. package/src/renderer/components/team/dialogs/teammateRuntimeCompatibility.tsx +1 -1
  195. package/src/renderer/components/team/kanban/KanbanTaskCard.test.tsx +41 -0
  196. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +41 -86
  197. package/src/renderer/components/team/loop-console/LoopCommandComposer.tsx +310 -0
  198. package/src/renderer/components/team/loop-console/LoopConsolePanel.tsx +372 -0
  199. package/src/renderer/components/team/loop-console/loopSendIntent.test.ts +85 -0
  200. package/src/renderer/components/team/loop-console/loopSendIntent.ts +221 -0
  201. package/src/renderer/components/team/loop-console/useLeadSessionToolActivity.ts +74 -0
  202. package/src/renderer/components/team/loop-console/useLoopCommandSuggestions.ts +165 -0
  203. package/src/renderer/components/team/loop-console/useLoopConsoleController.ts +266 -0
  204. package/src/renderer/components/team/members/LeadModelRow.test.tsx +1 -1
  205. package/src/renderer/components/team/members/LeadModelRow.tsx +5 -3
  206. package/src/renderer/components/team/members/MemberDetailDialog.tsx +11 -0
  207. package/src/renderer/components/team/members/MemberDetailStats.tsx +13 -3
  208. package/src/renderer/components/team/members/MemberDraftRow.test.tsx +1 -1
  209. package/src/renderer/components/team/members/MemberDraftRow.tsx +1 -1
  210. package/src/renderer/components/team/members/MemberMessagesTab.tsx +2 -2
  211. package/src/renderer/components/team/members/MemberStatsTab.tsx +1 -1
  212. package/src/renderer/components/team/messages/MessageComposer.tsx +150 -44
  213. package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +2 -2
  214. package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -28
  215. package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +6 -6
  216. package/src/renderer/components/team/taskLogs/ExactTaskLogCard.tsx +2 -2
  217. package/src/renderer/components/team/taskLogs/TaskLogStreamSection.tsx +1 -1
  218. package/src/renderer/components/terminal/TerminalPanel.tsx +2 -3
  219. package/src/renderer/components/ui/MentionableTextarea.tsx +5 -1
  220. package/src/renderer/constants/teamColors.ts +5 -5
  221. package/src/renderer/hooks/useExtensionsTabState.ts +1 -1
  222. package/src/renderer/hooks/useMentionDetection.ts +5 -1
  223. package/src/renderer/hooks/useProjectWorkflowCommands.ts +57 -0
  224. package/src/renderer/hooks/useTeamSuggestions.ts +2 -0
  225. package/src/renderer/index.css +19 -2
  226. package/src/renderer/main.tsx +7 -1
  227. package/src/renderer/store/index.ts +18 -1
  228. package/src/renderer/store/slices/extensionsSlice.ts +83 -0
  229. package/src/renderer/store/slices/tabSlice.ts +61 -0
  230. package/src/renderer/store/slices/teamSlice.ts +138 -9
  231. package/src/renderer/types/mention.ts +8 -0
  232. package/src/renderer/types/tabs.ts +3 -1
  233. package/src/renderer/utils/__tests__/bindProjectSlug.test.ts +69 -0
  234. package/src/renderer/utils/__tests__/groupTransformer.test.ts +148 -0
  235. package/src/renderer/utils/__tests__/initialRoute.test.ts +101 -0
  236. package/src/renderer/utils/__tests__/leadToolActivity.test.ts +124 -0
  237. package/src/renderer/utils/__tests__/mergeTeamMessages.test.ts +81 -0
  238. package/src/renderer/utils/__tests__/teamMessageFiltering.test.ts +213 -0
  239. package/src/renderer/utils/__tests__/teamMessageKey.test.ts +75 -0
  240. package/src/renderer/utils/__tests__/workflowCommandExecution.test.ts +173 -0
  241. package/src/renderer/utils/__tests__/workflowCommandSuggestions.test.ts +59 -0
  242. package/src/renderer/utils/bindProjectSlug.ts +57 -0
  243. package/src/renderer/utils/capabilityCommandExecution.ts +113 -0
  244. package/src/renderer/utils/initialRoute.ts +89 -0
  245. package/src/renderer/utils/leadToolActivity.ts +117 -0
  246. package/src/renderer/utils/loopShortcutSuggestions.ts +106 -0
  247. package/src/renderer/utils/mentionSuggestions.ts +1 -1
  248. package/src/renderer/utils/slashCommandRegistry.ts +231 -0
  249. package/src/renderer/utils/teamMentionDirective.ts +31 -0
  250. package/src/renderer/utils/workflowCommandExecution.ts +96 -0
  251. package/src/renderer/utils/workflowCommandSuggestions.ts +49 -0
  252. package/src/shared/types/api.ts +79 -4
  253. package/src/shared/types/ccConnect.ts +1 -0
  254. package/src/shared/types/extensions/api.ts +19 -0
  255. package/src/shared/types/extensions/capabilityPack.ts +118 -0
  256. package/src/shared/types/extensions/index.ts +29 -1
  257. package/src/shared/types/index.ts +6 -0
  258. package/src/shared/types/loopAssets.ts +54 -0
  259. package/src/shared/types/providers.ts +0 -16
  260. package/src/shared/types/systemManager.ts +26 -1
  261. package/src/shared/types/team.ts +41 -5
  262. package/src/shared/types/terminal.ts +2 -36
  263. package/src/shared/types/worker.test.ts +28 -0
  264. package/src/shared/types/worker.ts +3 -0
  265. package/src/shared/utils/__tests__/effortLevels.test.ts +88 -0
  266. package/src/shared/utils/__tests__/providerBackend.test.ts +88 -0
  267. package/src/shared/utils/__tests__/providerLaunchArgs.test.ts +220 -0
  268. package/src/shared/utils/claudeStreamJson.test.ts +187 -0
  269. package/src/shared/utils/claudeStreamJson.ts +153 -0
  270. package/src/shared/utils/providerLaunchArgs.ts +217 -0
  271. package/src/shared/utils/slashCommands.ts +10 -0
  272. package/src/types/node-pty.d.ts +8 -0
  273. package/dist-renderer/assets/channel-Ch7JrfUu.js +0 -1
  274. package/dist-renderer/assets/classDiagram-2ON5EDUG-z9I4AnFy.js +0 -1
  275. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-z9I4AnFy.js +0 -1
  276. package/dist-renderer/assets/clone-Dfi1Jx6l.js +0 -1
  277. package/dist-renderer/assets/index-iyjkpSus.css +0 -32
  278. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DTUIBfce.js +0 -1
  279. package/src/main/services/system-manager/SystemManagerPtyService.ts +0 -233
  280. package/src/renderer/components/common/TerminalPane.tsx +0 -213
  281. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +0 -292
@@ -0,0 +1,657 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { access, readdir, readFile, stat } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { promisify } from 'node:util';
6
+
7
+ import type {
8
+ LoopAssetAction,
9
+ LoopAssetCategoryKey,
10
+ LoopAssetCategorySnapshot,
11
+ LoopAssetsSnapshot,
12
+ LoopAssetStatus,
13
+ LoopAssetSourceRef,
14
+ } from '@shared/types/loopAssets';
15
+
16
+ const execFileAsync = promisify(execFile);
17
+ const MAX_DETAILS = 6;
18
+ const MAX_SOURCES = 12;
19
+
20
+ interface ScanTeamInput {
21
+ teamName: string;
22
+ displayName?: string;
23
+ bindProject?: string;
24
+ workDir: string;
25
+ teamRoot?: string;
26
+ memberCount?: number;
27
+ taskCount?: number;
28
+ messageCount?: number;
29
+ platforms?: { type: string; connected?: boolean }[];
30
+ }
31
+
32
+ interface AssetDraft {
33
+ key: LoopAssetCategoryKey;
34
+ title: string;
35
+ subtitle: string;
36
+ details: string[];
37
+ gap: string;
38
+ sources: LoopAssetSourceRef[];
39
+ actions: LoopAssetAction[];
40
+ warnings?: string[];
41
+ status?: LoopAssetStatus;
42
+ }
43
+
44
+ async function exists(filePath: string): Promise<boolean> {
45
+ try {
46
+ await access(filePath);
47
+ return true;
48
+ } catch {
49
+ return false;
50
+ }
51
+ }
52
+
53
+ async function safeReadDir(dir: string): Promise<string[]> {
54
+ try {
55
+ return await readdir(dir);
56
+ } catch {
57
+ return [];
58
+ }
59
+ }
60
+
61
+ async function safeReadJson(filePath: string): Promise<{ value?: unknown; warning?: string }> {
62
+ try {
63
+ const raw = await readFile(filePath, 'utf8');
64
+ return { value: JSON.parse(raw) as unknown };
65
+ } catch (err) {
66
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') return {};
67
+ return { warning: `${path.basename(filePath)} 读取失败或 JSON 无效` };
68
+ }
69
+ }
70
+
71
+ function compact(items: string[]): string[] {
72
+ return [...new Set(items.map((item) => item.trim()).filter(Boolean))].slice(0, MAX_DETAILS);
73
+ }
74
+
75
+ function compactSources(items: LoopAssetSourceRef[]): LoopAssetSourceRef[] {
76
+ const seen = new Set<string>();
77
+ const out: LoopAssetSourceRef[] = [];
78
+ for (const item of items) {
79
+ const key = `${item.scope}:${item.kind ?? ''}:${item.path ?? item.label}`;
80
+ if (seen.has(key)) continue;
81
+ seen.add(key);
82
+ out.push(item);
83
+ if (out.length >= MAX_SOURCES) break;
84
+ }
85
+ return out;
86
+ }
87
+
88
+ function category(draft: AssetDraft): LoopAssetCategorySnapshot {
89
+ const count = draft.sources.length || draft.details.length;
90
+ const status = draft.status ?? (count > 0 ? 'partial' : 'missing');
91
+ return {
92
+ key: draft.key,
93
+ title: draft.title,
94
+ subtitle: draft.subtitle,
95
+ status,
96
+ count,
97
+ details: compact(draft.details),
98
+ gap: draft.gap,
99
+ sources: compactSources(draft.sources),
100
+ actions: draft.actions,
101
+ warnings: draft.warnings?.length ? compact(draft.warnings) : undefined,
102
+ };
103
+ }
104
+
105
+ function statusFromCount(count: number, readyAt = 1): LoopAssetStatus {
106
+ if (count >= readyAt) return 'ready';
107
+ if (count > 0) return 'partial';
108
+ return 'missing';
109
+ }
110
+
111
+ function userHome(...segments: string[]): string {
112
+ return path.join(os.homedir(), ...segments);
113
+ }
114
+
115
+ function source(
116
+ label: string,
117
+ filePath: string,
118
+ scope: LoopAssetSourceRef['scope'],
119
+ kind: string
120
+ ): LoopAssetSourceRef {
121
+ return { label, path: filePath, scope, kind };
122
+ }
123
+
124
+ function action(
125
+ id: string,
126
+ label: string,
127
+ kind: LoopAssetAction['kind'],
128
+ target?: string,
129
+ payload?: Record<string, unknown>
130
+ ): LoopAssetAction {
131
+ return { id, label, kind, target, payload };
132
+ }
133
+
134
+ export class LoopAssetsScannerService {
135
+ async scanTeam(input: ScanTeamInput): Promise<LoopAssetsSnapshot> {
136
+ const warnings: string[] = [];
137
+ const workDir = input.workDir.trim();
138
+
139
+ if (!workDir) {
140
+ const categories = this.emptyCategories('项目缺少 workDir,无法扫描文件资产');
141
+ return {
142
+ teamName: input.teamName,
143
+ displayName: input.displayName,
144
+ bindProject: input.bindProject,
145
+ workDir,
146
+ lifecycle: 'unknown',
147
+ healthScore: 0,
148
+ scannedAt: new Date().toISOString(),
149
+ categories,
150
+ warnings: ['项目缺少 workDir'],
151
+ };
152
+ }
153
+
154
+ const projectExists = await exists(workDir);
155
+ if (!projectExists) warnings.push('项目目录不存在或不可访问');
156
+
157
+ const [automations, worktrees, skills, subagents, state] = await Promise.all([
158
+ this.scanAutomations(workDir),
159
+ this.scanWorktrees(workDir),
160
+ this.scanSkillsAndMcp(workDir),
161
+ this.scanSubagents(workDir, input.memberCount ?? 0),
162
+ this.scanState(workDir, input),
163
+ ]);
164
+
165
+ const categories = [automations, worktrees, skills, subagents, state];
166
+ const readyOrPartial = categories.filter(
167
+ (item) => item.status === 'ready' || item.status === 'partial'
168
+ ).length;
169
+ const ready = categories.filter((item) => item.status === 'ready').length;
170
+ const categoryWarnings = categories.reduce(
171
+ (count, item) => count + (item.warnings?.length ?? 0),
172
+ 0
173
+ );
174
+ const lifecycle = !projectExists
175
+ ? 'unknown'
176
+ : ready >= 4 && categoryWarnings === 0
177
+ ? 'ready'
178
+ : readyOrPartial >= Math.ceil(categories.length / 2)
179
+ ? 'active'
180
+ : 'missing-assets';
181
+
182
+ return {
183
+ teamName: input.teamName,
184
+ displayName: input.displayName,
185
+ bindProject: input.bindProject,
186
+ workDir,
187
+ lifecycle,
188
+ healthScore: Math.round(
189
+ (ready * 100 + (readyOrPartial - ready) * 50) / Math.max(categories.length, 1)
190
+ ),
191
+ scannedAt: new Date().toISOString(),
192
+ categories,
193
+ warnings: warnings.length ? warnings : undefined,
194
+ };
195
+ }
196
+
197
+ private emptyCategories(gap: string): LoopAssetCategorySnapshot[] {
198
+ return [
199
+ category({
200
+ key: 'automations',
201
+ title: 'Automations',
202
+ subtitle: '心跳与自动执行',
203
+ details: [],
204
+ gap,
205
+ sources: [],
206
+ actions: this.automationActions(),
207
+ }),
208
+ category({
209
+ key: 'worktrees',
210
+ title: 'Worktrees',
211
+ subtitle: '并行隔离工作区',
212
+ details: [],
213
+ gap,
214
+ sources: [],
215
+ actions: this.worktreeActions(),
216
+ }),
217
+ category({
218
+ key: 'skills',
219
+ title: 'Skills/MCP',
220
+ subtitle: '可复用知识与工具连接',
221
+ details: [],
222
+ gap,
223
+ sources: [],
224
+ actions: this.skillActions(),
225
+ }),
226
+ category({
227
+ key: 'subagents',
228
+ title: 'Sub-agents',
229
+ subtitle: '角色化分工验证',
230
+ details: [],
231
+ gap,
232
+ sources: [],
233
+ actions: this.subagentActions(),
234
+ }),
235
+ category({
236
+ key: 'state',
237
+ title: 'State',
238
+ subtitle: '跨运行记忆与恢复',
239
+ details: [],
240
+ gap,
241
+ sources: [],
242
+ actions: this.stateActions(),
243
+ }),
244
+ ];
245
+ }
246
+
247
+ private async scanAutomations(workDir: string): Promise<LoopAssetCategorySnapshot> {
248
+ const details: string[] = [];
249
+ const sources: LoopAssetSourceRef[] = [];
250
+ const warnings: string[] = [];
251
+
252
+ const workflowDir = path.join(workDir, '.github', 'workflows');
253
+ const workflows = (await safeReadDir(workflowDir)).filter((name) => /\.ya?ml$/i.test(name));
254
+ if (workflows.length) {
255
+ details.push(`${workflows.length} GitHub Actions`);
256
+ workflows
257
+ .slice(0, 4)
258
+ .forEach((name) =>
259
+ sources.push(source(name, path.join(workflowDir, name), 'project', 'github-action'))
260
+ );
261
+ }
262
+
263
+ const commandsDir = path.join(workDir, '.claude', 'commands');
264
+ const commands = (await safeReadDir(commandsDir)).filter((name) =>
265
+ /\.(md|txt|prompt|workflow)$/i.test(name)
266
+ );
267
+ if (commands.length) {
268
+ details.push(`${commands.length} Claude commands`);
269
+ commands
270
+ .slice(0, 4)
271
+ .forEach((name) =>
272
+ sources.push(
273
+ source(
274
+ `/${path.basename(name, path.extname(name))}`,
275
+ path.join(commandsDir, name),
276
+ 'project',
277
+ 'claude-command'
278
+ )
279
+ )
280
+ );
281
+ }
282
+
283
+ const packageJsonPath = path.join(workDir, 'package.json');
284
+ const packageJson = await safeReadJson(packageJsonPath);
285
+ if (packageJson.warning) warnings.push(packageJson.warning);
286
+ if (packageJson.value && typeof packageJson.value === 'object') {
287
+ const scripts = (packageJson.value as { scripts?: Record<string, unknown> }).scripts;
288
+ const scriptNames =
289
+ scripts && typeof scripts === 'object'
290
+ ? Object.keys(scripts).filter((name) =>
291
+ /^(dev|test|build|check|lint|verify|watch|loop|goal|ci)/i.test(name)
292
+ )
293
+ : [];
294
+ if (scriptNames.length) {
295
+ details.push(`package scripts: ${scriptNames.slice(0, 4).join(', ')}`);
296
+ sources.push(source('package.json scripts', packageJsonPath, 'project', 'package-scripts'));
297
+ }
298
+ }
299
+
300
+ const settingsPaths = [
301
+ path.join(workDir, '.claude', 'settings.json'),
302
+ path.join(workDir, '.claude', 'settings.local.json'),
303
+ ];
304
+ for (const settingsPath of settingsPaths) {
305
+ const parsed = await safeReadJson(settingsPath);
306
+ if (parsed.warning) warnings.push(parsed.warning);
307
+ if (parsed.value && typeof parsed.value === 'object' && 'hooks' in parsed.value) {
308
+ details.push(`${path.basename(settingsPath)} hooks`);
309
+ sources.push(source(path.basename(settingsPath), settingsPath, 'project', 'hooks'));
310
+ }
311
+ }
312
+
313
+ const status =
314
+ workflows.length || commands.length || sources.some((item) => item.kind === 'hooks')
315
+ ? 'ready'
316
+ : sources.length
317
+ ? 'partial'
318
+ : 'missing';
319
+
320
+ return category({
321
+ key: 'automations',
322
+ title: 'Automations',
323
+ subtitle: '心跳、计划任务和自动执行入口',
324
+ status,
325
+ details,
326
+ gap:
327
+ status === 'missing'
328
+ ? '缺少 heartbeat:添加 /loop、schedule、hook 或 CI。'
329
+ : '补齐自动验证与停止条件,避免只会运行不会收敛。',
330
+ sources,
331
+ actions: this.automationActions(),
332
+ warnings,
333
+ });
334
+ }
335
+
336
+ private async scanWorktrees(workDir: string): Promise<LoopAssetCategorySnapshot> {
337
+ const details: string[] = [];
338
+ const sources: LoopAssetSourceRef[] = [];
339
+ const warnings: string[] = [];
340
+
341
+ try {
342
+ const { stdout } = await execFileAsync(
343
+ 'git',
344
+ ['-C', workDir, 'worktree', 'list', '--porcelain'],
345
+ { timeout: 3000 }
346
+ );
347
+ const worktreeLines = stdout.split('\n').filter((line) => line.startsWith('worktree '));
348
+ const extraWorktrees = Math.max(worktreeLines.length - 1, 0);
349
+ if (extraWorktrees > 0) {
350
+ details.push(`${extraWorktrees} registered worktrees`);
351
+ worktreeLines.slice(1, 5).forEach((line) => {
352
+ const wt = line.replace(/^worktree\s+/, '').trim();
353
+ sources.push(source(path.basename(wt), wt, 'project', 'git-worktree'));
354
+ });
355
+ }
356
+ } catch {
357
+ warnings.push('git worktree 扫描不可用或当前目录不是 git 仓库');
358
+ }
359
+
360
+ const claudeWorktreesDir = path.join(workDir, '.claude', 'worktrees');
361
+ const claudeWorktrees = await safeReadDir(claudeWorktreesDir);
362
+ if (claudeWorktrees.length) {
363
+ details.push(`${claudeWorktrees.length} .claude worktrees`);
364
+ sources.push(source('.claude/worktrees', claudeWorktreesDir, 'project', 'agent-worktrees'));
365
+ }
366
+
367
+ const status = statusFromCount(sources.length);
368
+ return category({
369
+ key: 'worktrees',
370
+ title: 'Worktrees',
371
+ subtitle: '并行 Agent 的隔离工作区',
372
+ status,
373
+ details,
374
+ gap:
375
+ status === 'missing'
376
+ ? '并行 Agent 容易互相踩文件;为高风险任务启用 worktree 隔离。'
377
+ : '关注陈旧/脏 worktree,避免审查带宽成为瓶颈。',
378
+ sources,
379
+ actions: this.worktreeActions(),
380
+ warnings,
381
+ });
382
+ }
383
+
384
+ private async scanSkillsAndMcp(workDir: string): Promise<LoopAssetCategorySnapshot> {
385
+ const details: string[] = [];
386
+ const sources: LoopAssetSourceRef[] = [];
387
+ const warnings: string[] = [];
388
+ const projectSkillRoots = [
389
+ path.join(workDir, '.claude', 'skills'),
390
+ path.join(workDir, '.hermit', 'skills'),
391
+ ];
392
+ const userSkillRoot = userHome('.claude', 'skills');
393
+
394
+ let projectSkills = 0;
395
+ let richSkills = 0;
396
+ for (const root of projectSkillRoots) {
397
+ const entries = await safeReadDir(root);
398
+ for (const entry of entries) {
399
+ const skillDir = path.join(root, entry);
400
+ if (!(await exists(path.join(skillDir, 'SKILL.md')))) continue;
401
+ projectSkills++;
402
+ const hasRichAssets =
403
+ (await exists(path.join(skillDir, 'scripts'))) ||
404
+ (await exists(path.join(skillDir, 'references'))) ||
405
+ (await exists(path.join(skillDir, 'assets')));
406
+ if (hasRichAssets) richSkills++;
407
+ sources.push(source(entry, skillDir, 'project', 'skill'));
408
+ }
409
+ }
410
+
411
+ let userSkills = 0;
412
+ for (const entry of await safeReadDir(userSkillRoot)) {
413
+ if (await exists(path.join(userSkillRoot, entry, 'SKILL.md'))) userSkills++;
414
+ }
415
+ if (projectSkills) details.push(`${projectSkills} project skills`);
416
+ if (richSkills) details.push(`${richSkills} with scripts/references/assets`);
417
+ if (userSkills) details.push(`${userSkills} user skills available`);
418
+
419
+ const mcpFiles = [
420
+ path.join(workDir, '.mcp.json'),
421
+ path.join(workDir, '.cursor', 'mcp.json'),
422
+ path.join(workDir, '.claude', 'settings.json'),
423
+ path.join(workDir, '.claude', 'settings.local.json'),
424
+ ];
425
+
426
+ for (const filePath of mcpFiles) {
427
+ const parsed = await safeReadJson(filePath);
428
+ if (parsed.warning) warnings.push(parsed.warning);
429
+ if (!parsed.value || typeof parsed.value !== 'object') continue;
430
+ const record = parsed.value as Record<string, unknown>;
431
+ const mcpServers =
432
+ record.mcpServers && typeof record.mcpServers === 'object'
433
+ ? Object.keys(record.mcpServers as Record<string, unknown>)
434
+ : record.mcp && typeof record.mcp === 'object'
435
+ ? Object.keys(record.mcp as Record<string, unknown>)
436
+ : [];
437
+ if (mcpServers.length) {
438
+ details.push(`${mcpServers.length} MCP servers in ${path.basename(filePath)}`);
439
+ sources.push(source(path.basename(filePath), filePath, 'project', 'mcp'));
440
+ }
441
+ if ('enabledPlugins' in record || 'plugins' in record) {
442
+ details.push(`plugins configured in ${path.basename(filePath)}`);
443
+ sources.push(source(path.basename(filePath), filePath, 'project', 'plugins'));
444
+ }
445
+ }
446
+
447
+ const hasExecutableTooling = sources.some(
448
+ (item) => item.kind === 'mcp' || item.kind === 'plugins'
449
+ );
450
+ const status: LoopAssetStatus =
451
+ projectSkills > 0 && (richSkills > 0 || hasExecutableTooling)
452
+ ? 'ready'
453
+ : projectSkills > 0 || userSkills > 0 || sources.length > 0
454
+ ? 'partial'
455
+ : 'missing';
456
+ return category({
457
+ key: 'skills',
458
+ title: 'Skills/MCP',
459
+ subtitle: '可复用项目知识与可执行工具',
460
+ status,
461
+ details,
462
+ gap:
463
+ status === 'missing'
464
+ ? '把重复的项目意图沉淀成 .claude/skills/<name>/SKILL.md,并配置 MCP/插件工具。'
465
+ : '为关键 skill 增加 scripts/references/assets,并确认 MCP/插件权限最小化。',
466
+ sources,
467
+ actions: this.skillActions(),
468
+ warnings,
469
+ });
470
+ }
471
+
472
+ private async scanSubagents(
473
+ workDir: string,
474
+ memberCount: number
475
+ ): Promise<LoopAssetCategorySnapshot> {
476
+ const details: string[] = [];
477
+ const sources: LoopAssetSourceRef[] = [];
478
+ const agentDir = path.join(workDir, '.claude', 'agents');
479
+ const projectAgents = (await safeReadDir(agentDir)).filter((name) =>
480
+ /\.(md|json|toml|yaml|yml)$/i.test(name)
481
+ );
482
+ if (projectAgents.length) {
483
+ details.push(`${projectAgents.length} project agents`);
484
+ projectAgents
485
+ .slice(0, 4)
486
+ .forEach((name) =>
487
+ sources.push(source(name, path.join(agentDir, name), 'project', 'subagent'))
488
+ );
489
+ }
490
+ if (memberCount > 0) {
491
+ details.push(`${memberCount} Hermit team members`);
492
+ sources.push({ label: 'Hermit team members', scope: 'team', kind: 'team-members' });
493
+ }
494
+
495
+ const hasVerifier = projectAgents.some((name) =>
496
+ /verifier|review|reviewer|qa|test/i.test(name)
497
+ );
498
+ if (projectAgents.length && !hasVerifier) details.push('verifier role not detected');
499
+ const status: LoopAssetStatus =
500
+ hasVerifier || memberCount > 1
501
+ ? 'ready'
502
+ : projectAgents.length > 0 || memberCount === 1
503
+ ? 'warning'
504
+ : 'missing';
505
+ return category({
506
+ key: 'subagents',
507
+ title: 'Sub-agents',
508
+ subtitle: '实现、探索、验证分工',
509
+ status,
510
+ details,
511
+ gap:
512
+ status === 'missing'
513
+ ? '添加 verifier/reviewer/researcher 角色,避免写代码的 Agent 自评。'
514
+ : hasVerifier || memberCount > 1
515
+ ? '保持验证者和实现者分离,并把验收证据写回状态/看板。'
516
+ : '已发现 Agent 资产但缺少 verifier/reviewer/QA;补一个独立验证角色。',
517
+ sources,
518
+ actions: this.subagentActions(),
519
+ });
520
+ }
521
+
522
+ private async scanState(
523
+ workDir: string,
524
+ input: ScanTeamInput
525
+ ): Promise<LoopAssetCategorySnapshot> {
526
+ const details: string[] = [];
527
+ const sources: LoopAssetSourceRef[] = [];
528
+ const statePaths = [
529
+ path.join(workDir, '.omc', 'state'),
530
+ path.join(workDir, '.omc', 'sessions'),
531
+ path.join(workDir, '.omc', 'plans'),
532
+ path.join(workDir, '.omc', 'logs'),
533
+ path.join(workDir, 'reports'),
534
+ path.join(workDir, 'plans'),
535
+ ];
536
+ for (const dir of statePaths) {
537
+ const entries = await safeReadDir(dir);
538
+ if (entries.length) {
539
+ details.push(`${path.relative(workDir, dir)} (${entries.length})`);
540
+ sources.push(source(path.relative(workDir, dir), dir, 'project', 'state-dir'));
541
+ }
542
+ }
543
+ for (const filename of ['CLAUDE.md', 'AGENTS.md']) {
544
+ const filePath = path.join(workDir, filename);
545
+ if (await exists(filePath)) {
546
+ details.push(filename);
547
+ sources.push(source(filename, filePath, 'project', 'instructions'));
548
+ }
549
+ }
550
+ if (input.taskCount != null && input.taskCount > 0) {
551
+ details.push(`${input.taskCount} Hermit tasks`);
552
+ sources.push({
553
+ label: 'Hermit task board',
554
+ path: input.teamRoot,
555
+ scope: 'team',
556
+ kind: 'task-board',
557
+ });
558
+ }
559
+ if (input.messageCount != null && input.messageCount > 0) {
560
+ details.push(`${input.messageCount} team messages`);
561
+ sources.push({
562
+ label: 'Hermit messages',
563
+ path: input.teamRoot,
564
+ scope: 'team',
565
+ kind: 'messages',
566
+ });
567
+ }
568
+
569
+ const status = sources.some((item) => item.kind === 'state-dir' || item.kind === 'task-board')
570
+ ? 'ready'
571
+ : statusFromCount(sources.length);
572
+ return category({
573
+ key: 'state',
574
+ title: 'State',
575
+ subtitle: '跨运行记忆、看板和恢复层',
576
+ status,
577
+ details,
578
+ gap:
579
+ status === 'missing'
580
+ ? '把进度写入看板、状态文件或报告;不要只存在上下文里。'
581
+ : '检查状态是否过期,确保下一次循环能恢复而不是重新猜。',
582
+ sources,
583
+ actions: this.stateActions(),
584
+ });
585
+ }
586
+
587
+ private automationActions(): LoopAssetAction[] {
588
+ return [
589
+ action('run-folder-hygiene', '目录整洁巡检', 'loop-session', 'daily-folder-hygiene', {
590
+ sessionName: 'Daily Folder Hygiene',
591
+ prompt:
592
+ '请只读扫描当前项目工作区是否变乱:检查根目录、reports、plans、.omc、.claude、临时输出、陈旧报告、脏 worktree 和未归档产物。不要修改文件,只输出证据、风险和整理建议。',
593
+ }),
594
+ action(
595
+ 'run-memory-conflicts',
596
+ '记忆冲突巡检',
597
+ 'loop-session',
598
+ 'daily-memory-conflict-check',
599
+ {
600
+ sessionName: 'Daily Memory Conflict Check',
601
+ prompt:
602
+ '请只读检查当前项目的 CLAUDE.md、AGENTS.md、.claude/settings、memory 和状态文件是否存在重复、过期或冲突指令。不要写入 memory,只输出冲突证据、建议保留的唯一事实来源和合并计划。',
603
+ }
604
+ ),
605
+ action(
606
+ 'run-workflow-extraction',
607
+ '提取重复 Workflow',
608
+ 'loop-session',
609
+ 'daily-workflow-extraction',
610
+ {
611
+ sessionName: 'Daily Workflow Extraction',
612
+ prompt:
613
+ '请只读查看最近聊天、任务、会话和报告,提取重复出现的工作流程,按价值排序,并给出可沉淀为 skill、workflow、schedule 或 team template 的草案。不要创建文件。',
614
+ }
615
+ ),
616
+ ];
617
+ }
618
+
619
+ private worktreeActions(): LoopAssetAction[] {
620
+ return [
621
+ action('run-worktree-scan', '运行 Worktree Scan', 'loop-session', 'worktree-scan', {
622
+ sessionName: 'Worktree Scan',
623
+ command: '/worktree-scan',
624
+ }),
625
+ ];
626
+ }
627
+
628
+ private skillActions(): LoopAssetAction[] {
629
+ return [
630
+ action('run-skills-scan', '发送 /skills', 'loop-session', 'skills-mcp-scan', {
631
+ sessionName: 'Loop Skills',
632
+ command: '/skills',
633
+ }),
634
+ action('bind-platform', '绑定新渠道', 'open-dialog', 'runtime-config'),
635
+ ];
636
+ }
637
+
638
+ private subagentActions(): LoopAssetAction[] {
639
+ return [
640
+ action('add-member', '自然语言添加验证角色', 'loop-session', 'verifier-gap', {
641
+ sessionName: 'Loop Verifier Setup',
642
+ prompt:
643
+ '请为这个团队添加一个独立 verifier/reviewer 角色,负责验证实现者的产出,不能由实现者自审。请给出成员名、职责和启动方式,并在需要时创建或更新团队成员。',
644
+ }),
645
+ ];
646
+ }
647
+
648
+ private stateActions(): LoopAssetAction[] {
649
+ return [
650
+ action('open-board', '查看任务看板', 'navigate', 'tasks'),
651
+ action('run-state-scan', '运行 State Scan', 'loop-session', 'state-scan', {
652
+ sessionName: 'State Scan',
653
+ command: '/state-scan',
654
+ }),
655
+ ];
656
+ }
657
+ }