@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
@@ -6,10 +6,9 @@
6
6
 
7
7
  import { useMemo, useState } from 'react';
8
8
 
9
- import { api } from '@renderer/api';
10
9
  import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
11
10
  import { useStore } from '@renderer/store';
12
- import { ListTodo, PanelRight, Puzzle, Users } from 'lucide-react';
11
+ import { ListTodo, MessageCircle, PanelRight, Puzzle, Users } from 'lucide-react';
13
12
  import { useShallow } from 'zustand/react/shallow';
14
13
 
15
14
  import { MoreMenu } from './MoreMenu';
@@ -17,6 +16,7 @@ import { MoreMenu } from './MoreMenu';
17
16
  export const TabBarActions = (): React.JSX.Element => {
18
17
  const {
19
18
  unreadCount,
19
+ openChatTab,
20
20
  openExtensionsTab,
21
21
  openTasksTab,
22
22
  openTeamsTab,
@@ -28,6 +28,7 @@ export const TabBarActions = (): React.JSX.Element => {
28
28
  } = useStore(
29
29
  useShallow((s) => ({
30
30
  unreadCount: s.unreadCount,
31
+ openChatTab: s.openChatTab,
31
32
  openExtensionsTab: s.openExtensionsTab,
32
33
  openTasksTab: s.openTasksTab,
33
34
  openTeamsTab: s.openTeamsTab,
@@ -43,7 +44,7 @@ export const TabBarActions = (): React.JSX.Element => {
43
44
  const [teamsHover, setTeamsHover] = useState(false);
44
45
  const [extensionsHover, setExtensionsHover] = useState(false);
45
46
  const [tasksHover, setTasksHover] = useState(false);
46
- const [githubHover, setGithubHover] = useState(false);
47
+ const [chatHover, setChatHover] = useState(false);
47
48
  const [expandHover, setExpandHover] = useState(false);
48
49
 
49
50
  // Derive active tab and session detail for MoreMenu
@@ -118,28 +119,24 @@ export const TabBarActions = (): React.JSX.Element => {
118
119
  <TooltipContent side="bottom">任务</TooltipContent>
119
120
  </Tooltip>
120
121
 
121
- {/* GitHub link */}
122
+ {/* Feishu group QR */}
122
123
  <Tooltip>
123
124
  <TooltipTrigger asChild>
124
125
  <button
125
- onClick={async () => {
126
- await api.openExternal('https://github.com/yancyuu/Hermit');
127
- }}
128
- onMouseEnter={() => setGithubHover(true)}
129
- onMouseLeave={() => setGithubHover(false)}
126
+ onClick={openChatTab}
127
+ onMouseEnter={() => setChatHover(true)}
128
+ onMouseLeave={() => setChatHover(false)}
130
129
  className="rounded-md p-2 transition-colors"
131
130
  style={{
132
- color: githubHover ? 'var(--color-text)' : 'var(--color-text-muted)',
133
- backgroundColor: githubHover ? 'var(--color-surface-raised)' : 'transparent',
131
+ color: chatHover ? 'var(--color-text)' : 'var(--color-text-muted)',
132
+ backgroundColor: chatHover ? 'var(--color-surface-raised)' : 'transparent',
134
133
  }}
135
- aria-label="GitHub"
134
+ aria-label="加入飞书群"
136
135
  >
137
- <svg className="size-4" viewBox="0 0 24 24" fill="currentColor">
138
- <path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0 0 24 12c0-6.63-5.37-12-12-12Z" />
139
- </svg>
136
+ <MessageCircle className="size-4" />
140
137
  </button>
141
138
  </TooltipTrigger>
142
- <TooltipContent side="bottom">GitHub</TooltipContent>
139
+ <TooltipContent side="bottom">加入飞书群</TooltipContent>
143
140
  </Tooltip>
144
141
 
145
142
  {/* More menu (Notifications, Settings, Search, Export, Analyze) */}
@@ -16,12 +16,11 @@ import {
16
16
  import { Input } from '@renderer/components/ui/input';
17
17
  import { Tabs, TabsContent, TabsList, TabsTrigger } from '@renderer/components/ui/tabs';
18
18
  import { emitOpenHermitEvent, OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
19
- import { CheckCircle2, Download, Loader2, Pencil, Plus, RefreshCw, Trash2 } from 'lucide-react';
19
+ import { Loader2, Pencil, Plus, RefreshCw, Trash2 } from 'lucide-react';
20
20
 
21
21
  import type { CliProviderId, CliProviderStatus } from '@shared/types';
22
22
  import type {
23
23
  AgentType,
24
- CCSwitchProvider,
25
24
  GlobalProvider,
26
25
  ProviderModelEntry,
27
26
  ProviderPreset,
@@ -214,23 +213,6 @@ function formFromPreset(preset: ProviderPreset, fallbackAgentType: AgentType): P
214
213
  };
215
214
  }
216
215
 
217
- function formFromCCSwitch(
218
- provider: CCSwitchProvider,
219
- fallbackAgentType: AgentType
220
- ): ProviderFormState {
221
- const agentType = normalizeAgentType(provider.app_type) ?? fallbackAgentType;
222
- return {
223
- ...emptyForm(agentType),
224
- name: provider.name,
225
- apiKey: provider.api_key ?? '',
226
- baseUrl: provider.base_url ?? '',
227
- model: provider.model ?? '',
228
- agentTypes: [agentType],
229
- agentModels: provider.model ? { [agentType]: provider.model } : {},
230
- endpoints: provider.base_url ? { [agentType]: provider.base_url } : {},
231
- };
232
- }
233
-
234
216
  function formToProvider(form: ProviderFormState, originalName?: string): GlobalProvider {
235
217
  const agentTypes = form.agentTypes.length > 0 ? form.agentTypes : undefined;
236
218
  const endpoints = Object.fromEntries(
@@ -271,11 +253,8 @@ export const ProviderRuntimeSettingsDialog = ({
271
253
  const harnessLabel = CLI_PROVIDER_LABELS[initialProviderId] ?? initialProviderId;
272
254
  const [providers, setProviders] = useState<GlobalProvider[]>([]);
273
255
  const [presets, setPresets] = useState<ProviderPreset[]>([]);
274
- const [ccSwitchProviders, setCcSwitchProviders] = useState<CCSwitchProvider[]>([]);
275
- const [ccSwitchAvailable, setCcSwitchAvailable] = useState<boolean | null>(null);
276
256
  const [loading, setLoading] = useState(false);
277
257
  const [presetsLoading, setPresetsLoading] = useState(false);
278
- const [ccSwitchLoading, setCcSwitchLoading] = useState(false);
279
258
  const [saving, setSaving] = useState(false);
280
259
  const [error, setError] = useState<string | null>(null);
281
260
  const [formError, setFormError] = useState<string | null>(null);
@@ -313,20 +292,6 @@ export const ProviderRuntimeSettingsDialog = ({
313
292
  }
314
293
  }, []);
315
294
 
316
- const refreshCCSwitch = useCallback(async (): Promise<void> => {
317
- setCcSwitchLoading(true);
318
- try {
319
- const result = await providersApi.listCCSwitch();
320
- setCcSwitchProviders(result.providers ?? []);
321
- setCcSwitchAvailable(result.available);
322
- } catch {
323
- setCcSwitchProviders([]);
324
- setCcSwitchAvailable(false);
325
- } finally {
326
- setCcSwitchLoading(false);
327
- }
328
- }, []);
329
-
330
295
  useEffect(() => {
331
296
  if (!open) return;
332
297
  setForm(emptyForm(agentType));
@@ -334,8 +299,7 @@ export const ProviderRuntimeSettingsDialog = ({
334
299
  setFormError(null);
335
300
  void refreshProviders();
336
301
  void refreshPresets();
337
- void refreshCCSwitch();
338
- }, [agentType, open, refreshCCSwitch, refreshPresets, refreshProviders]);
302
+ }, [agentType, open, refreshPresets, refreshProviders]);
339
303
 
340
304
  const updateForm = (patch: Partial<ProviderFormState>): void => {
341
305
  setForm((prev) => ({ ...prev, ...patch }));
@@ -410,19 +374,6 @@ export const ProviderRuntimeSettingsDialog = ({
410
374
  }
411
375
  };
412
376
 
413
- const handleImportCCSwitch = async (providerName: string): Promise<void> => {
414
- setSaving(true);
415
- try {
416
- await providersApi.importCCSwitch([providerName]);
417
- await refreshProviders();
418
- emitOpenHermitEvent(OPEN_HERMIT_EVENTS.providersChanged);
419
- } catch (err) {
420
- setError(err instanceof Error ? err.message : '导入 cc-switch Provider 失败');
421
- } finally {
422
- setSaving(false);
423
- }
424
- };
425
-
426
377
  return (
427
378
  <Dialog open={open} onOpenChange={onOpenChange}>
428
379
  <DialogContent className="flex max-h-[88vh] w-[min(96vw,1120px)] max-w-[min(96vw,1120px)] flex-col overflow-hidden">
@@ -439,7 +390,6 @@ export const ProviderRuntimeSettingsDialog = ({
439
390
  <TabsList className="mb-3">
440
391
  <TabsTrigger value="providers">Provider 库</TabsTrigger>
441
392
  <TabsTrigger value="presets">预设</TabsTrigger>
442
- <TabsTrigger value="cc-switch">cc-switch</TabsTrigger>
443
393
  </TabsList>
444
394
 
445
395
  <TabsContent value="providers" className="mt-0 space-y-3">
@@ -479,7 +429,7 @@ export const ProviderRuntimeSettingsDialog = ({
479
429
  </div>
480
430
  ) : providers.length === 0 ? (
481
431
  <div className="rounded-xl border border-dashed border-[var(--color-border)] p-6 text-center text-sm text-[var(--color-text-muted)]">
482
- 还没有全局 Provider。可以从右侧新建,或从预设/cc-switch 导入。
432
+ 还没有全局 Provider。可以从右侧新建,或从预设导入。
483
433
  </div>
484
434
  ) : (
485
435
  <div className="space-y-2">
@@ -565,7 +515,7 @@ export const ProviderRuntimeSettingsDialog = ({
565
515
  <div>
566
516
  <div className="text-sm font-medium text-[var(--color-text)]">从预设开始</div>
567
517
  <div className="text-xs text-[var(--color-text-muted)]">
568
- 参考 cc-switch 的交互:先选网关预设,再补 Key、模型和适用 Harness。
518
+ 先选网关预设,再补 Key、模型和适用 Harness。
569
519
  </div>
570
520
  </div>
571
521
  <Button
@@ -625,87 +575,6 @@ export const ProviderRuntimeSettingsDialog = ({
625
575
  ))}
626
576
  </div>
627
577
  </TabsContent>
628
-
629
- <TabsContent value="cc-switch" className="mt-0 space-y-3">
630
- <div className="flex items-center justify-between gap-3">
631
- <div>
632
- <div className="text-sm font-medium text-[var(--color-text)]">
633
- 从 cc-switch 导入
634
- </div>
635
- <div className="text-xs text-[var(--color-text-muted)]">
636
- 可导入已有 cc-switch Provider,再在右侧按 Hermit 字段调整。
637
- </div>
638
- </div>
639
- <Button
640
- size="sm"
641
- variant="outline"
642
- disabled={ccSwitchLoading}
643
- onClick={() => void refreshCCSwitch()}
644
- >
645
- <RefreshCw
646
- className={ccSwitchLoading ? 'mr-1 size-3.5 animate-spin' : 'mr-1 size-3.5'}
647
- />
648
- 刷新
649
- </Button>
650
- </div>
651
- {ccSwitchAvailable === false ? (
652
- <div className="rounded-md border border-amber-500/30 bg-amber-500/10 px-3 py-2 text-xs text-amber-300">
653
- 没有检测到可导入的 Provider,或服务未返回导入数据。
654
- </div>
655
- ) : null}
656
- <div className="space-y-2">
657
- {ccSwitchProviders.map((provider) => (
658
- <div
659
- key={`${provider.app_type}:${provider.name}`}
660
- className="rounded-xl border border-[var(--color-border-subtle)] bg-white/[0.025] px-3 py-3"
661
- >
662
- <div className="flex flex-wrap items-start justify-between gap-2">
663
- <div className="min-w-0">
664
- <div className="flex items-center gap-2 text-sm font-medium text-[var(--color-text)]">
665
- {provider.is_current ? (
666
- <CheckCircle2 className="size-3.5 text-emerald-400" />
667
- ) : null}
668
- {provider.name}
669
- </div>
670
- <div className="mt-1 text-[11px] text-[var(--color-text-muted)]">
671
- {provider.app_type} · {provider.base_url || '默认端点'} ·{' '}
672
- {provider.model || '未指定模型'}
673
- </div>
674
- </div>
675
- <div className="flex items-center gap-1">
676
- <Button
677
- size="sm"
678
- variant="ghost"
679
- className="h-7 px-2 text-xs"
680
- onClick={() => {
681
- setEditingName(null);
682
- setForm(formFromCCSwitch(provider, agentType));
683
- setFormError(null);
684
- }}
685
- >
686
- 填入表单
687
- </Button>
688
- <Button
689
- size="sm"
690
- variant="outline"
691
- className="h-7 px-2 text-xs"
692
- disabled={saving}
693
- onClick={() => void handleImportCCSwitch(provider.name)}
694
- >
695
- <Download className="mr-1 size-3" />
696
- 直接导入
697
- </Button>
698
- </div>
699
- </div>
700
- </div>
701
- ))}
702
- {ccSwitchProviders.length === 0 && !ccSwitchLoading ? (
703
- <div className="rounded-xl border border-dashed border-[var(--color-border)] p-5 text-center text-xs text-[var(--color-text-muted)]">
704
- 暂无 cc-switch Provider 可导入。
705
- </div>
706
- ) : null}
707
- </div>
708
- </TabsContent>
709
578
  </Tabs>
710
579
  </div>
711
580
 
@@ -14,13 +14,7 @@ import { CcCronScheduleDialog } from '../team/schedule/CcCronScheduleDialog';
14
14
  import type { Schedule } from '@shared/types';
15
15
 
16
16
  export const SchedulesView = (): React.JSX.Element => {
17
- const {
18
- schedules,
19
- schedulesLoading,
20
- fetchSchedules,
21
- openTeamTab,
22
- teamByName,
23
- } = useStore(
17
+ const { schedules, schedulesLoading, fetchSchedules, openTeamTab, teamByName } = useStore(
24
18
  useShallow((s) => ({
25
19
  schedules: s.schedules,
26
20
  schedulesLoading: s.schedulesLoading,
@@ -93,14 +87,20 @@ export const SchedulesView = (): React.JSX.Element => {
93
87
  return (
94
88
  <div className="flex h-full flex-col bg-[var(--color-surface)]">
95
89
  {/* Minimal header */}
96
- <div className="flex shrink-0 items-center justify-between px-4 pt-4 pb-2">
90
+ <div className="flex shrink-0 items-center justify-between px-4 pb-2 pt-4">
97
91
  <div className="flex items-center gap-2">
98
- <h1 className="flex items-center gap-2 text-xs font-medium uppercase tracking-wider" style={{ color: 'var(--color-text-muted)' }}>
92
+ <h1
93
+ className="flex items-center gap-2 text-xs font-medium uppercase tracking-wider"
94
+ style={{ color: 'var(--color-text-muted)' }}
95
+ >
99
96
  <span className="text-cyan-400/40">#</span>
100
97
  定时任务
101
98
  </h1>
102
99
  {schedules.length > 0 && (
103
- <span className="rounded-full px-2 py-0.5 text-[10px]" style={{ color: 'var(--color-text-muted)', background: 'rgba(148,163,184,0.06)' }}>
100
+ <span
101
+ className="rounded-full px-2 py-0.5 text-[10px]"
102
+ style={{ color: 'var(--color-text-muted)', background: 'rgba(148,163,184,0.06)' }}
103
+ >
104
104
  {schedules.filter((s) => s.status === 'active').length} 运行中
105
105
  </span>
106
106
  )}
@@ -112,18 +112,26 @@ export const SchedulesView = (): React.JSX.Element => {
112
112
  </div>
113
113
 
114
114
  {/* Content — fills remaining space */}
115
- <div className="flex-1 min-h-0 overflow-auto px-2 pb-4">
115
+ <div className="min-h-0 flex-1 overflow-auto px-2 pb-4">
116
116
  {schedulesLoading && schedules.length === 0 ? (
117
117
  <div className="flex items-center justify-center py-24 text-sm text-[var(--color-text-muted)]">
118
118
  正在加载计划...
119
119
  </div>
120
120
  ) : schedules.length === 0 ? (
121
121
  <div className="flex flex-col items-center justify-center gap-3 rounded-xl border border-dashed border-[var(--color-border)] py-20 text-center">
122
- <Calendar className="size-6" style={{ color: 'var(--color-text-muted)', opacity: 0.4 }} />
122
+ <Calendar
123
+ className="size-6"
124
+ style={{ color: 'var(--color-text-muted)', opacity: 0.4 }}
125
+ />
123
126
  <p className="text-xs" style={{ color: 'var(--color-text-muted)' }}>
124
- 暂无定时任务。在团队中创建计划即可自动运行。
127
+ 暂无定时任务。在 Loop workspace 中创建计划即可自动运行。
125
128
  </p>
126
- <Button size="sm" variant="ghost" className="mt-1 gap-1.5 text-xs" onClick={handleCreate}>
129
+ <Button
130
+ size="sm"
131
+ variant="ghost"
132
+ className="mt-1 gap-1.5 text-xs"
133
+ onClick={handleCreate}
134
+ >
127
135
  <Plus className="size-3.5" />
128
136
  创建计划
129
137
  </Button>
@@ -37,12 +37,15 @@ export const CalendarEventBlock = React.memo(function CalendarEventBlock({
37
37
  type="button"
38
38
  className={cn(
39
39
  'flex w-full items-center gap-1 overflow-hidden rounded px-1 py-[1px] text-left transition-opacity hover:opacity-80',
40
- className,
40
+ className
41
41
  )}
42
42
  style={{ backgroundColor: hexToRgba(occurrence.color, 0.12), ...style }}
43
43
  onClick={onClick}
44
44
  >
45
- <span className="size-1.5 shrink-0 rounded-full" style={{ backgroundColor: occurrence.color }} />
45
+ <span
46
+ className="size-1.5 shrink-0 rounded-full"
47
+ style={{ backgroundColor: occurrence.color }}
48
+ />
46
49
  <span className="truncate text-[10px] leading-tight" style={{ color: occurrence.color }}>
47
50
  {label}
48
51
  </span>
@@ -57,7 +60,7 @@ export const CalendarEventBlock = React.memo(function CalendarEventBlock({
57
60
  className={cn(
58
61
  'group relative flex w-full flex-col overflow-hidden rounded-[3px] px-1.5 py-0.5 text-left transition-opacity hover:opacity-90 focus:outline-none',
59
62
  occurrence.status === 'paused' && 'opacity-50',
60
- className,
63
+ className
61
64
  )}
62
65
  style={{
63
66
  backgroundColor: occurrence.color,
@@ -68,9 +71,7 @@ export const CalendarEventBlock = React.memo(function CalendarEventBlock({
68
71
  onClick={onClick}
69
72
  title={`${label} · ${occurrence.teamDisplayName}\n${timeStr}`}
70
73
  >
71
- <span className="truncate text-[11px] font-medium leading-tight text-white/95">
72
- {label}
73
- </span>
74
+ <span className="truncate text-[11px] font-medium leading-tight text-white/95">{label}</span>
74
75
  {variant === 'day' && (
75
76
  <span className="truncate text-[10px] leading-tight text-white/70">
76
77
  {occurrence.teamDisplayName}
@@ -59,8 +59,14 @@ export const SettingsTabs = ({
59
59
 
60
60
  return (
61
61
  <TooltipProvider>
62
- <div className="flex items-center" style={{ backgroundColor: 'var(--color-surface-raised)' }}>
63
- {visibleTabs.map((tab, index) => {
62
+ <div
63
+ className="inline-flex items-center gap-1 rounded-xl border p-1 shadow-inner shadow-black/10"
64
+ style={{
65
+ backgroundColor: 'var(--color-surface-raised)',
66
+ borderColor: 'var(--color-border-subtle)',
67
+ }}
68
+ >
69
+ {visibleTabs.map((tab) => {
64
70
  const Icon = tab.icon;
65
71
  const isActive = activeSection === tab.id;
66
72
 
@@ -68,33 +74,30 @@ export const SettingsTabs = ({
68
74
  <button
69
75
  key={tab.id}
70
76
  onClick={() => onSectionChange(tab.id)}
71
- className={`flex items-center gap-1.5 px-3 py-2 text-xs transition-colors ${
77
+ className={`group relative flex h-8 w-[112px] items-center justify-center gap-1.5 whitespace-nowrap rounded-lg px-3 text-xs transition-all duration-200 ${
72
78
  isActive
73
- ? 'font-medium'
74
- : 'text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]'
79
+ ? 'shadow-[var(--color-accent-glow)]/20 font-medium text-[var(--color-accent)] shadow-sm'
80
+ : 'text-[var(--color-text-muted)] hover:bg-[var(--color-accent-soft)] hover:text-[var(--color-text-secondary)]'
75
81
  }`}
76
- style={{
77
- borderLeft: index > 0 ? '1px solid var(--color-border-subtle)' : undefined,
78
- color: isActive ? '#818cf8' : undefined,
79
- }}
82
+ style={
83
+ isActive
84
+ ? {
85
+ backgroundColor: 'var(--color-accent-muted)',
86
+ border: '1px solid var(--color-accent-border)',
87
+ }
88
+ : { border: '1px solid transparent' }
89
+ }
80
90
  >
81
- <Icon className={`size-3 ${isActive ? 'opacity-90' : 'opacity-40'}`} />
91
+ <Icon
92
+ className={`size-3 transition-opacity ${isActive ? 'opacity-95' : 'opacity-45 group-hover:opacity-70'}`}
93
+ />
82
94
  {tab.label}
83
95
 
84
96
  <Tooltip>
85
97
  <TooltipTrigger asChild>
86
98
  <span
87
- role="button"
88
- tabIndex={0}
89
- aria-label={`What is ${tab.label}?`}
90
- onClick={(event) => event.stopPropagation()}
91
- onMouseDown={(event) => event.stopPropagation()}
92
- onKeyDown={(event) => {
93
- if (event.key === 'Enter' || event.key === ' ') {
94
- event.stopPropagation();
95
- }
96
- }}
97
- className="ml-0.5 inline-flex items-center justify-center rounded-full text-[var(--color-text-muted)] opacity-0 transition-opacity hover:opacity-100"
99
+ aria-hidden="true"
100
+ className="ml-0.5 inline-flex items-center justify-center rounded-full text-[var(--color-text-muted)] opacity-0 transition-opacity hover:text-[var(--color-accent)] group-hover:opacity-100 group-focus-visible:opacity-100"
98
101
  >
99
102
  <Info className="size-2.5" />
100
103
  </span>
@@ -6,7 +6,7 @@
6
6
  import { useEffect, useState } from 'react';
7
7
 
8
8
  import { useStore } from '@renderer/store';
9
- import { Loader2 } from 'lucide-react';
9
+ import { Loader2, SlidersHorizontal } from 'lucide-react';
10
10
  import { useShallow } from 'zustand/react/shallow';
11
11
 
12
12
  import { useSettingsConfig, useSettingsHandlers } from './hooks';
@@ -100,28 +100,37 @@ export const SettingsView = (): React.JSX.Element | null => {
100
100
 
101
101
  return (
102
102
  <div className="flex-1 overflow-auto" style={{ backgroundColor: 'var(--color-surface)' }}>
103
- {/* Clean container */}
103
+ {/* Control-console settings shell */}
104
104
  <div
105
- className="mx-auto flex min-h-full max-w-3xl flex-col"
105
+ className="mx-auto flex min-h-full max-w-4xl flex-col px-6 py-6"
106
106
  style={{
107
107
  backgroundColor: 'var(--color-surface)',
108
108
  }}
109
109
  >
110
- {/* Tabs area */}
111
110
  <div
112
- className="border-b"
113
- style={{
114
- borderColor: 'var(--color-border-subtle)',
115
- }}
111
+ className="bg-[var(--color-surface-raised)]/60 mb-5 overflow-hidden rounded-2xl border shadow-sm shadow-black/10"
112
+ style={{ borderColor: 'var(--color-border-subtle)' }}
116
113
  >
117
- <SettingsTabs activeSection={activeSection} onSectionChange={setActiveSection} />
118
- {error && (
119
- <div className="px-4 pb-2 text-[10px] text-red-400">{error}</div>
120
- )}
114
+ <div className="pointer-events-none h-px bg-gradient-to-r from-transparent via-[var(--color-accent-border)] to-transparent" />
115
+ <div className="flex flex-col gap-4 px-4 py-4 sm:flex-row sm:items-center sm:justify-between">
116
+ <div className="flex items-start gap-3">
117
+ <div className="shadow-[var(--color-accent-glow)]/20 flex size-9 shrink-0 items-center justify-center rounded-xl border border-[var(--color-accent-border)] bg-[var(--color-accent-soft)] text-[var(--color-accent)] shadow-sm">
118
+ <SlidersHorizontal className="size-4" />
119
+ </div>
120
+ <div>
121
+ <h2 className="text-base font-semibold text-[var(--color-text)]">设置 Helm Loop</h2>
122
+ <p className="mt-1 text-xs leading-relaxed text-[var(--color-text-muted)]">
123
+ 配置 Hermit 运行时、外观、数字员工渠道和本地控制行为。
124
+ </p>
125
+ </div>
126
+ </div>
127
+ <SettingsTabs activeSection={activeSection} onSectionChange={setActiveSection} />
128
+ </div>
129
+ {error && <div className="px-4 pb-3 text-[10px] text-red-400">{error}</div>}
121
130
  </div>
122
131
 
123
132
  {/* Content */}
124
- <div className="flex-1 overflow-y-auto px-6 py-5">
133
+ <div className="flex-1 overflow-y-auto duration-200 animate-in fade-in slide-in-from-bottom-1">
125
134
  {activeSection === 'general' && (
126
135
  <GeneralSection
127
136
  safeConfig={safeConfig}
@@ -18,12 +18,15 @@ export const SettingRow = ({
18
18
  }: SettingRowProps): React.JSX.Element => {
19
19
  return (
20
20
  <div
21
- className="flex items-center justify-between border-b py-3"
21
+ className="group flex items-center justify-between border-b px-3 py-3.5 transition-colors duration-150 last:border-b-0 hover:bg-[var(--color-accent-soft)]"
22
22
  style={{ borderColor: 'var(--color-border-subtle)' }}
23
23
  >
24
- <div className="flex items-start gap-2.5">
24
+ <div className="flex items-start gap-3">
25
25
  {icon ? (
26
- <div className="mt-0.5 shrink-0" style={{ color: 'var(--color-text-muted)' }}>
26
+ <div
27
+ className="mt-0.5 flex size-5 shrink-0 items-center justify-center rounded transition-colors duration-150 group-hover:text-[var(--color-text)]"
28
+ style={{ color: 'var(--color-text-muted)' }}
29
+ >
27
30
  {icon}
28
31
  </div>
29
32
  ) : null}
@@ -32,13 +35,18 @@ export const SettingRow = ({
32
35
  {label}
33
36
  </div>
34
37
  {description && (
35
- <div className="text-xs" style={{ color: 'var(--color-text-muted)' }}>
38
+ <div
39
+ className="mt-0.5 text-xs leading-relaxed"
40
+ style={{ color: 'var(--color-text-muted)' }}
41
+ >
36
42
  {description}
37
43
  </div>
38
44
  )}
39
45
  </div>
40
46
  </div>
41
- <div className="shrink-0">{children}</div>
47
+ <div className="shrink-0 transition-transform duration-100 group-active:scale-[0.97]">
48
+ {children}
49
+ </div>
42
50
  </div>
43
51
  );
44
52
  };
@@ -0,0 +1,53 @@
1
+ /**
2
+ * SettingsSectionCard - Premium settings panel surface.
3
+ * Adds a subtle accent hairline and glow while preserving Hermit's dense control-console feel.
4
+ */
5
+
6
+ interface SettingsSectionCardProps {
7
+ readonly title: string;
8
+ readonly description?: string;
9
+ readonly icon?: React.ReactNode;
10
+ readonly children: React.ReactNode;
11
+ readonly className?: string;
12
+ }
13
+
14
+ export const SettingsSectionCard = ({
15
+ title,
16
+ description,
17
+ icon,
18
+ children,
19
+ className = '',
20
+ }: SettingsSectionCardProps): React.JSX.Element => {
21
+ return (
22
+ <section
23
+ className={`bg-[var(--color-surface-raised)]/55 group relative overflow-hidden rounded-2xl border shadow-sm shadow-black/10 transition-all duration-200 hover:border-[var(--color-border-emphasis)] ${className}`}
24
+ style={{ borderColor: 'var(--color-border-subtle)' }}
25
+ >
26
+ <div className="pointer-events-none absolute inset-x-8 top-0 h-px bg-gradient-to-r from-transparent via-[var(--color-accent-border)] to-transparent opacity-80" />
27
+ <div className="pointer-events-none absolute -right-20 -top-24 size-48 rounded-full bg-[var(--color-accent-soft)] blur-3xl transition-opacity duration-300 group-hover:opacity-80" />
28
+
29
+ <div
30
+ className="relative border-b px-4 py-3"
31
+ style={{ borderColor: 'var(--color-border-subtle)' }}
32
+ >
33
+ <div className="flex items-start gap-3">
34
+ {icon && (
35
+ <div className="shadow-[var(--color-accent-glow)]/20 mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-lg border border-[var(--color-accent-border)] bg-[var(--color-accent-soft)] text-[var(--color-accent)] shadow-sm">
36
+ {icon}
37
+ </div>
38
+ )}
39
+ <div className="min-w-0">
40
+ <h3 className="text-sm font-semibold text-[var(--color-text)]">{title}</h3>
41
+ {description && (
42
+ <p className="mt-0.5 text-xs leading-relaxed text-[var(--color-text-muted)]">
43
+ {description}
44
+ </p>
45
+ )}
46
+ </div>
47
+ </div>
48
+ </div>
49
+
50
+ <div className="relative px-1">{children}</div>
51
+ </section>
52
+ );
53
+ };
@@ -14,15 +14,19 @@ export const SettingsSectionHeader = ({
14
14
  }: SettingsSectionHeaderProps): React.JSX.Element => {
15
15
  return (
16
16
  <h3
17
- className="mb-3 mt-7 flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.12em] first:mt-0"
17
+ className="mb-3 mt-8 flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.12em] first:mt-0"
18
18
  style={{ color: 'var(--color-text-muted)' }}
19
19
  >
20
- {icon}
20
+ {icon && (
21
+ <span
22
+ className="flex size-4 items-center justify-center rounded opacity-70"
23
+ style={{ backgroundColor: 'var(--color-border-subtle)' }}
24
+ >
25
+ {icon}
26
+ </span>
27
+ )}
21
28
  {title}
22
- <div
23
- className="ml-1 h-px flex-1"
24
- style={{ backgroundColor: 'var(--color-border-subtle)' }}
25
- />
29
+ <div className="ml-1 h-px flex-1" style={{ backgroundColor: 'var(--color-border-subtle)' }} />
26
30
  </h3>
27
31
  );
28
32
  };