@yancyyu/openhermit 1.6.38 → 1.6.40

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 (243) hide show
  1. package/dist-renderer/assets/ProjectEditorOverlay-CemDOX-3.js +58 -0
  2. package/dist-renderer/assets/{TeamGraphOverlay-ZEDfZyHb.js → TeamGraphOverlay-hPY770Db.js} +1 -1
  3. package/dist-renderer/assets/{_basePickBy-CIhniz70.js → _basePickBy-BHHrJT1i.js} +1 -1
  4. package/dist-renderer/assets/{_baseUniq-cKAW4Q8I.js → _baseUniq-CWErBtke.js} +1 -1
  5. package/dist-renderer/assets/{arc-YmNsoDXW.js → arc-C_o2_Uv8.js} +1 -1
  6. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DHEls2sX.js → architectureDiagram-VXUJARFQ-DUW0LI3t.js} +1 -1
  7. package/dist-renderer/assets/{blockDiagram-VD42YOAC-Bpwf1Sbg.js → blockDiagram-VD42YOAC-CWbCE9hQ.js} +1 -1
  8. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-B0IaQ4w5.js → c4Diagram-YG6GDRKO-BjLadrfV.js} +1 -1
  9. package/dist-renderer/assets/channel-DyP9YlCF.js +1 -0
  10. package/dist-renderer/assets/{chunk-4BX2VUAB-DLk-hcFc.js → chunk-4BX2VUAB-CPnvjZl9.js} +1 -1
  11. package/dist-renderer/assets/{chunk-55IACEB6-1XRmX_Zm.js → chunk-55IACEB6-OlL47yXQ.js} +1 -1
  12. package/dist-renderer/assets/{chunk-B4BG7PRW-1waH1DAD.js → chunk-B4BG7PRW-DTasjbm8.js} +1 -1
  13. package/dist-renderer/assets/{chunk-DI55MBZ5-BqpZBtrN.js → chunk-DI55MBZ5-C5_Xaqkk.js} +1 -1
  14. package/dist-renderer/assets/{chunk-FMBD7UC4-Bly7vVym.js → chunk-FMBD7UC4-NdoM4DMR.js} +1 -1
  15. package/dist-renderer/assets/{chunk-QN33PNHL-Ci2QWBAs.js → chunk-QN33PNHL-C8Fybejy.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QZHKN3VN-YCqFW7d-.js → chunk-QZHKN3VN-E98TYFXJ.js} +1 -1
  17. package/dist-renderer/assets/{chunk-TZMSLE5B-B0xGXInl.js → chunk-TZMSLE5B-h4lFgkIq.js} +1 -1
  18. package/dist-renderer/assets/classDiagram-2ON5EDUG-BqffFTae.js +1 -0
  19. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-BqffFTae.js +1 -0
  20. package/dist-renderer/assets/clone-MPcKWs2O.js +1 -0
  21. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DxcFNQKT.js → cose-bilkent-S5V4N54A-DtQ7fkrs.js} +1 -1
  22. package/dist-renderer/assets/{dagre-6UL2VRFP-DPo_RfZY.js → dagre-6UL2VRFP-CN-nL_z4.js} +1 -1
  23. package/dist-renderer/assets/{diagram-PSM6KHXK-U3hQsFe4.js → diagram-PSM6KHXK-DVJtqmm-.js} +1 -1
  24. package/dist-renderer/assets/{diagram-QEK2KX5R-OrwrAy0V.js → diagram-QEK2KX5R-DlxHxyXh.js} +1 -1
  25. package/dist-renderer/assets/{diagram-S2PKOQOG-CXATPWVw.js → diagram-S2PKOQOG-7dpzO6x6.js} +1 -1
  26. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-B0e8AfMF.js → erDiagram-Q2GNP2WA-GP1TqsHi.js} +1 -1
  27. package/dist-renderer/assets/{flowDiagram-NV44I4VS-CXfzA4jJ.js → flowDiagram-NV44I4VS-C7ZLETuH.js} +1 -1
  28. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-CMr08qVl.js → ganttDiagram-JELNMOA3-CvPB68dH.js} +1 -1
  29. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-vYFHpPmy.js → gitGraphDiagram-V2S2FVAM-B5yOm3w7.js} +1 -1
  30. package/dist-renderer/assets/{graph-DOe5j8dH.js → graph-smeyY1YZ.js} +1 -1
  31. package/dist-renderer/assets/{index-BySQS7AB.js → index-BJx8XvG1.js} +1 -1
  32. package/dist-renderer/assets/{index-C_okzZXP.js → index-CQaXUAua.js} +1 -1
  33. package/dist-renderer/assets/{index-VJ-MM9xa.js → index-CajRpxO2.js} +1 -1
  34. package/dist-renderer/assets/{index-V7dAKPqd.js → index-ChG4rE-E.js} +587 -705
  35. package/dist-renderer/assets/index-DUd0uw9C.css +32 -0
  36. package/dist-renderer/assets/{index-CzWxVCRL.js → index-IhmXZWqf.js} +1 -1
  37. package/dist-renderer/assets/{index-B2Dy7M2G.js → index-x_JkoDRH.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D_WubR0B.js → infoDiagram-HS3SLOUP-D-hWRQGY.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-w9ca-1TI.js → journeyDiagram-XKPGCS4Q-Bb6W8rUG.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-Jg9p6_pN.js → kanban-definition-3W4ZIXB7-CnHdUX0q.js} +1 -1
  41. package/dist-renderer/assets/{layout-B-z3y17c.js → layout-pqss_zkI.js} +1 -1
  42. package/dist-renderer/assets/{linear-D-RTX5UW.js → linear-B1mFITNh.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-CDQmHOYP.js → mindmap-definition-VGOIOE7T-DTD9q7-D.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-D_odsQL7.js → pieDiagram-ADFJNKIX-Df3mhrn7.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-BRsmYWSA.js → quadrantDiagram-AYHSOK5B-B1FZ09vH.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-ChNE_BOV.js → requirementDiagram-UZGBJVZJ-aEO78thZ.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-C8FtpwKc.js → sankeyDiagram-TZEHDZUN-6Ui--jp-.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-DmLCzNcc.js → sequenceDiagram-WL72ISMW-DF4Q1cAM.js} +1 -1
  49. package/dist-renderer/assets/splashScene-D0YB9uxm.js +17 -0
  50. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-WJBm4bhu.js → stateDiagram-FKZM4ZOC-BqA2BI8C.js} +1 -1
  51. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-Cs2ZtUD2.js +1 -0
  52. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BXs_hOJs.js → timeline-definition-IT6M3QCI-DoOkw_A8.js} +1 -1
  53. package/dist-renderer/assets/{treemap-GDKQZRPO-o04MA0G9.js → treemap-GDKQZRPO-DUe26QdD.js} +1 -1
  54. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-Czj69XRd.js → xychartDiagram-PRI3JC2R-BKCnj5Xn.js} +1 -1
  55. package/dist-renderer/index.html +20 -53
  56. package/package.json +25 -18
  57. package/src/main/ipc/extensions.ts +2 -1
  58. package/src/main/server.ts +873 -221
  59. package/src/main/services/extensions/ExtensionFacadeService.ts +2 -5
  60. package/src/main/services/extensions/catalog/PluginCatalogService.ts +4 -2
  61. package/src/main/services/session-intelligence/ConversationTelemetryService.ts +1101 -0
  62. package/src/main/services/session-intelligence/LocalSessionScanner.ts +512 -0
  63. package/src/main/services/session-intelligence/SessionUsageParser.ts +4 -4
  64. package/src/main/services/system-manager/SystemManagerConfigService.ts +122 -0
  65. package/src/main/services/system-manager/SystemManagerPtyService.ts +233 -0
  66. package/src/main/services/system-manager/WorkflowPromptService.ts +75 -0
  67. package/src/main/services/teams-mvp/TaskDispatchService.ts +5 -6
  68. package/src/main/services/teams-mvp/TeamProvisioningService.ts +39 -2
  69. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +22 -4
  70. package/src/main/utils/teamProjectResolution.ts +15 -0
  71. package/src/renderer/App.tsx +8 -4
  72. package/src/renderer/api/httpClient.ts +68 -18
  73. package/src/renderer/api/providers.ts +23 -2
  74. package/src/renderer/assets/participant-avatars/01.svg +3 -0
  75. package/src/renderer/assets/participant-avatars/02.svg +3 -0
  76. package/src/renderer/assets/participant-avatars/03.svg +3 -0
  77. package/src/renderer/assets/participant-avatars/04.svg +3 -0
  78. package/src/renderer/assets/participant-avatars/05.svg +3 -0
  79. package/src/renderer/assets/participant-avatars/06.svg +3 -0
  80. package/src/renderer/assets/participant-avatars/07.svg +3 -0
  81. package/src/renderer/assets/participant-avatars/08.svg +3 -0
  82. package/src/renderer/assets/participant-avatars/09.svg +3 -0
  83. package/src/renderer/assets/participant-avatars/10.svg +3 -0
  84. package/src/renderer/assets/participant-avatars/11.svg +3 -0
  85. package/src/renderer/assets/participant-avatars/12.svg +3 -0
  86. package/src/renderer/assets/participant-avatars/13.svg +3 -0
  87. package/src/renderer/components/chat/ChatHistoryItem.tsx +1 -1
  88. package/src/renderer/components/chat/items/SubagentItem.tsx +2 -2
  89. package/src/renderer/components/chat/viewers/MermaidDiagram.tsx +2 -2
  90. package/src/renderer/components/common/ErrorBoundary.tsx +1 -1
  91. package/src/renderer/components/common/TerminalPane.tsx +213 -0
  92. package/src/renderer/components/dashboard/CliStatusBanner.tsx +7 -7
  93. package/src/renderer/components/dashboard/DashboardView.tsx +9 -36
  94. package/src/renderer/components/extensions/ExtensionStoreView.tsx +7 -126
  95. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
  96. package/src/renderer/components/extensions/common/ExtensionToast.tsx +3 -3
  97. package/src/renderer/components/extensions/common/SourceBadge.tsx +1 -1
  98. package/src/renderer/components/extensions/mcp/McpLibraryEnableDialog.tsx +305 -0
  99. package/src/renderer/components/extensions/mcp/McpLibraryEntryDialog.tsx +418 -0
  100. package/src/renderer/components/extensions/mcp/McpLibraryPanel.tsx +404 -0
  101. package/src/renderer/components/extensions/plugins/CategoryChips.tsx +1 -1
  102. package/src/renderer/components/extensions/plugins/PluginCard.tsx +6 -6
  103. package/src/renderer/components/extensions/plugins/PluginDetailDialog.tsx +2 -2
  104. package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +34 -21
  105. package/src/renderer/components/extensions/skills/SkillEditorDialog.tsx +1 -1
  106. package/src/renderer/components/extensions/skills/SkillsLibraryPanel.tsx +335 -0
  107. package/src/renderer/components/layout/PaneContent.tsx +8 -1
  108. package/src/renderer/components/layout/PaneResizeHandle.tsx +2 -2
  109. package/src/renderer/components/layout/Sidebar.tsx +13 -56
  110. package/src/renderer/components/layout/SortableTab.tsx +22 -33
  111. package/src/renderer/components/layout/TabBar.tsx +1 -1
  112. package/src/renderer/components/layout/TabContextMenu.tsx +1 -1
  113. package/src/renderer/components/report/sections/CostSection.tsx +2 -2
  114. package/src/renderer/components/report/sections/InsightsSection.tsx +1 -1
  115. package/src/renderer/components/runtime/ProviderRuntimeBackendSelector.tsx +2 -2
  116. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +768 -157
  117. package/src/renderer/components/schedules/SchedulesView.tsx +51 -462
  118. package/src/renderer/components/schedules/calendar/CalendarDayView.tsx +173 -0
  119. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +113 -0
  120. package/src/renderer/components/schedules/calendar/CalendarHeader.tsx +148 -0
  121. package/src/renderer/components/schedules/calendar/CalendarMonthView.tsx +142 -0
  122. package/src/renderer/components/schedules/calendar/CalendarWeekView.tsx +219 -0
  123. package/src/renderer/components/schedules/calendar/ScheduleCalendarBoard.tsx +41 -0
  124. package/src/renderer/components/schedules/calendar/TeamGanttView.tsx +405 -0
  125. package/src/renderer/components/schedules/calendar/computeOccurrences.ts +234 -0
  126. package/src/renderer/components/schedules/calendar/index.ts +2 -0
  127. package/src/renderer/components/schedules/calendar/types.ts +44 -0
  128. package/src/renderer/components/search/CommandPalette.tsx +4 -4
  129. package/src/renderer/components/settings/SettingsTabs.tsx +50 -55
  130. package/src/renderer/components/settings/SettingsView.tsx +30 -35
  131. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +5 -1
  132. package/src/renderer/components/settings/components/SettingsSelect.tsx +5 -3
  133. package/src/renderer/components/settings/components/SettingsToggle.tsx +2 -2
  134. package/src/renderer/components/settings/sections/AdvancedSection.tsx +11 -42
  135. package/src/renderer/components/settings/sections/CliStatusSection.tsx +72 -113
  136. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  137. package/src/renderer/components/settings/sections/GeneralSection.tsx +11 -3
  138. package/src/renderer/components/settings/sections/HarnessSection.tsx +18 -14
  139. package/src/renderer/components/settings/sections/PlatformsSection.tsx +3 -3
  140. package/src/renderer/components/settings/sections/TaskBusSection.tsx +33 -40
  141. package/src/renderer/components/settings/sections/index.ts +0 -1
  142. package/src/renderer/components/sidebar/SessionFiltersPopover.tsx +1 -1
  143. package/src/renderer/components/sidebar/SessionItem.tsx +3 -3
  144. package/src/renderer/components/sidebar/SidebarSessions.tsx +184 -6
  145. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +4 -4
  146. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +40 -5
  147. package/src/renderer/components/splash/splashScene.ts +121 -929
  148. package/src/renderer/components/system-manager/FolderBrowser.tsx +163 -0
  149. package/src/renderer/components/system-manager/SystemManagerView.tsx +351 -0
  150. package/src/renderer/components/tasks/TasksView.tsx +112 -134
  151. package/src/renderer/components/team/CcSessionsSection.tsx +431 -89
  152. package/src/renderer/components/team/ClaudeLogsFilterPopover.tsx +1 -1
  153. package/src/renderer/components/team/ClaudeLogsPanel.tsx +1 -1
  154. package/src/renderer/components/team/CollapsibleTeamSection.tsx +17 -32
  155. package/src/renderer/components/team/ProcessesSection.tsx +2 -2
  156. package/src/renderer/components/team/TaskTooltip.tsx +2 -2
  157. package/src/renderer/components/team/TeamDetailView.tsx +319 -123
  158. package/src/renderer/components/team/TeamListFilterPopover.tsx +1 -1
  159. package/src/renderer/components/team/TeamListView.tsx +109 -124
  160. package/src/renderer/components/team/TeamSessionsSection.tsx +6 -6
  161. package/src/renderer/components/team/UnreadCommentsBadge.tsx +1 -1
  162. package/src/renderer/components/team/activity/ActivityItem.tsx +9 -9
  163. package/src/renderer/components/team/activity/ActivityTimeline.tsx +5 -5
  164. package/src/renderer/components/team/activity/LeadThoughtsGroup.tsx +3 -3
  165. package/src/renderer/components/team/activity/ReplyQuoteBlock.tsx +4 -4
  166. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +4 -4
  167. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +84 -306
  168. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +259 -342
  169. package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +1 -1
  170. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +18 -16
  171. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +221 -0
  172. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +8 -1
  173. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +5 -5
  174. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +361 -0
  175. package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +6 -6
  176. package/src/renderer/components/team/dialogs/SkipPermissionsCheckbox.tsx +6 -6
  177. package/src/renderer/components/team/dialogs/StatusHistoryTimeline.tsx +1 -1
  178. package/src/renderer/components/team/dialogs/TaskAttachments.tsx +1 -1
  179. package/src/renderer/components/team/dialogs/TaskCommentInput.tsx +6 -6
  180. package/src/renderer/components/team/dialogs/TaskCommentsSection.tsx +4 -4
  181. package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +3 -3
  182. package/src/renderer/components/team/dialogs/platformMeta.ts +122 -11
  183. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +17 -5
  184. package/src/renderer/components/team/editor/EditorFileTree.tsx +4 -4
  185. package/src/renderer/components/team/editor/EditorSearchPanel.tsx +1 -1
  186. package/src/renderer/components/team/editor/MarkdownSplitView.tsx +1 -1
  187. package/src/renderer/components/team/editor/NewFileDialog.tsx +1 -1
  188. package/src/renderer/components/team/editor/ProjectEditorOverlay.tsx +1 -1
  189. package/src/renderer/components/team/editor/SearchInFilesPanel.tsx +1 -1
  190. package/src/renderer/components/team/kanban/KanbanBoard.tsx +9 -9
  191. package/src/renderer/components/team/kanban/KanbanFilterPopover.tsx +4 -4
  192. package/src/renderer/components/team/kanban/KanbanSearchInput.tsx +1 -1
  193. package/src/renderer/components/team/kanban/KanbanSortPopover.tsx +5 -5
  194. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +4 -4
  195. package/src/renderer/components/team/members/MemberCard.tsx +14 -47
  196. package/src/renderer/components/team/members/MemberDetailDialog.tsx +3 -95
  197. package/src/renderer/components/team/members/MemberDetailStats.tsx +50 -65
  198. package/src/renderer/components/team/members/MemberDraftRow.tsx +1 -1
  199. package/src/renderer/components/team/members/MemberStatsTab.tsx +2 -2
  200. package/src/renderer/components/team/members/MemberWorkspaceTab.tsx +1 -1
  201. package/src/renderer/components/team/messages/MessageComposer.tsx +10 -112
  202. package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +1 -1
  203. package/src/renderer/components/team/messages/MessagesPanel.tsx +136 -119
  204. package/src/renderer/components/team/review/ChangeReviewDialog.tsx +1 -1
  205. package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +3 -3
  206. package/src/renderer/components/team/sidebar/TeamSidebarRail.tsx +4 -4
  207. package/src/renderer/components/team/tasks/TaskRow.tsx +1 -1
  208. package/src/renderer/components/team/tools/AddMcpInline.tsx +27 -17
  209. package/src/renderer/components/team/tools/McpChip.tsx +6 -3
  210. package/src/renderer/components/team/tools/SkillChip.tsx +3 -3
  211. package/src/renderer/components/team/tools/ToolsSection.tsx +418 -70
  212. package/src/renderer/components/ui/MemberSelect.tsx +2 -2
  213. package/src/renderer/components/ui/MentionSuggestionList.tsx +2 -2
  214. package/src/renderer/components/ui/MentionableTextarea.tsx +3 -3
  215. package/src/renderer/hooks/useExtensionsTabState.ts +3 -114
  216. package/src/renderer/index.css +56 -39
  217. package/src/renderer/index.html +17 -50
  218. package/src/renderer/store/index.ts +2 -1
  219. package/src/renderer/store/slices/scheduleSlice.ts +1 -1
  220. package/src/renderer/store/slices/teamSlice.ts +45 -168
  221. package/src/renderer/utils/claudeCodeOnlyProviders.ts +3 -10
  222. package/src/renderer/utils/memberHelpers.ts +5 -17
  223. package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +4 -2
  224. package/src/renderer/utils/providerSlashCommands.ts +0 -5
  225. package/src/renderer/utils/scheduleFormatters.ts +3 -1
  226. package/src/renderer/utils/teamMessageFiltering.ts +14 -1
  227. package/src/renderer/utils/teamModelAvailability.ts +18 -2
  228. package/src/shared/types/api.ts +121 -2
  229. package/src/shared/types/ccConnect.ts +2 -0
  230. package/src/shared/types/index.ts +3 -0
  231. package/src/shared/types/systemManager.ts +49 -0
  232. package/src/shared/types/team.ts +29 -0
  233. package/src/shared/types/terminal.ts +4 -2
  234. package/src/shared/utils/extensionNormalizers.ts +15 -8
  235. package/src/shared/utils/providerExtensionCapabilities.ts +2 -2
  236. package/dist-renderer/assets/ProjectEditorOverlay-lJZi-9Hp.js +0 -52
  237. package/dist-renderer/assets/channel-yIlSKy0e.js +0 -1
  238. package/dist-renderer/assets/classDiagram-2ON5EDUG-24fHez0s.js +0 -1
  239. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-24fHez0s.js +0 -1
  240. package/dist-renderer/assets/clone-BTNuUva-.js +0 -1
  241. package/dist-renderer/assets/index-Bi6nrZ4z.css +0 -1
  242. package/dist-renderer/assets/splashScene-C8lWNnm4.js +0 -1
  243. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-_m6iPPUR.js +0 -1
@@ -1,25 +1,38 @@
1
- /**
2
- * ToolsSection — per-worker MCP and Skills management.
3
- * Chip/tag UI: compact chips for installed tools, inline add forms.
1
+ /*
2
+ * ToolsSection — per-worker capabilities management.
3
+ * MCP uses a cc-switch style model: global templates create project instances.
4
4
  */
5
5
 
6
6
  import { useCallback, useEffect, useMemo, useState } from 'react';
7
7
 
8
+ import { api } from '@renderer/api';
8
9
  import { confirm } from '@renderer/components/common/ConfirmDialog';
10
+ import { Button } from '@renderer/components/ui/button';
11
+ import { Input } from '@renderer/components/ui/input';
12
+ import { McpLibraryEnableDialog } from '@renderer/components/extensions/mcp/McpLibraryEnableDialog';
9
13
  import { useStore } from '@renderer/store';
10
- import { Plus, Wrench } from 'lucide-react';
14
+ import { Plus, RefreshCw, Wrench } from 'lucide-react';
11
15
 
12
16
  import { AddMcpInline } from './AddMcpInline';
13
17
  import { AddSkillInline } from './AddSkillInline';
14
18
  import { McpChip } from './McpChip';
15
19
  import { SkillChip } from './SkillChip';
16
20
 
21
+ import type { McpLibraryEntry, SkillCatalogItem } from '@shared/types/extensions';
22
+
17
23
  interface ToolsSectionProps {
18
24
  teamName: string;
19
25
  projectPath: string | null;
20
26
  harnessType?: string;
21
27
  }
22
28
 
29
+ function summarizeMcp(entry: McpLibraryEntry): string {
30
+ if (entry.installSpec.type === 'stdio') {
31
+ return `stdio · ${entry.installSpec.npmPackage}${entry.installSpec.npmVersion ? `@${entry.installSpec.npmVersion}` : ''}`;
32
+ }
33
+ return `${entry.installSpec.transportType} · ${entry.installSpec.url}`;
34
+ }
35
+
23
36
  export const ToolsSection = ({
24
37
  teamName,
25
38
  projectPath,
@@ -32,30 +45,46 @@ export const ToolsSection = ({
32
45
  const mcpFetchInstalled = useStore((s) => s.mcpFetchInstalled);
33
46
  const runMcpDiagnostics = useStore((s) => s.runMcpDiagnostics);
34
47
  const fetchSkillsCatalog = useStore((s) => s.fetchSkillsCatalog);
48
+ const fetchSkillDetail = useStore((s) => s.fetchSkillDetail);
49
+ const applySkillImport = useStore((s) => s.applySkillImport);
50
+ const previewSkillImport = useStore((s) => s.previewSkillImport);
35
51
  const uninstallMcpServer = useStore((s) => s.uninstallMcpServer);
36
52
  const deleteSkill = useStore((s) => s.deleteSkill);
53
+ const skillDetailsById = useStore((s) => s.skillsDetailsById);
37
54
 
38
55
  // ── Local state ──
39
56
  const [addingMcp, setAddingMcp] = useState(false);
40
57
  const [addingSkill, setAddingSkill] = useState(false);
58
+ const [mcpLibrary, setMcpLibrary] = useState<McpLibraryEntry[]>([]);
59
+ const [userSkills, setUserSkills] = useState<SkillCatalogItem[]>([]);
60
+ const [libraryLoading, setLibraryLoading] = useState(false);
61
+ const [libraryError, setLibraryError] = useState<string | null>(null);
62
+ const [selectedMcpTemplate, setSelectedMcpTemplate] = useState<McpLibraryEntry | null>(null);
63
+ const [importingMcpTemplates, setImportingMcpTemplates] = useState(false);
64
+ const [enablingSkillId, setEnablingSkillId] = useState<string | null>(null);
65
+ const [mcpSearch, setMcpSearch] = useState('');
66
+ const [skillSearch, setSkillSearch] = useState('');
67
+ const [showAllMcp, setShowAllMcp] = useState(false);
68
+ const [showAllSkills, setShowAllSkills] = useState(false);
69
+ const [applyNotice, setApplyNotice] = useState<string | null>(null);
41
70
 
42
71
  // ── Derived data ──
43
72
  const mcpServers = useMemo(
44
- () => (projectPath ? mcpByPath[projectPath] ?? [] : []),
45
- [mcpByPath, projectPath],
73
+ () => (projectPath ? (mcpByPath[projectPath] ?? []) : []),
74
+ [mcpByPath, projectPath]
46
75
  );
47
76
  // Diagnostics are stored keyed by `getMcpDiagnosticKey(name, scope)`, but the
48
77
  // scope is not always present (e.g. the text-mode CLI parser omits it), so the
49
78
  // scoped key can't be reconstructed reliably from an installed entry. Index by
50
79
  // server name instead — chip rows already assume names are unique per project.
51
80
  const diagnosticByName = useMemo(() => {
52
- const record = projectPath ? diagnosticsByPath[projectPath] ?? {} : {};
81
+ const record = projectPath ? (diagnosticsByPath[projectPath] ?? {}) : {};
53
82
  return Object.fromEntries(Object.values(record).map((d) => [d.name, d] as const));
54
83
  }, [diagnosticsByPath, projectPath]);
55
84
 
56
85
  // Deduplicate skills by name (same skill may appear from multiple roots)
57
86
  const skills = useMemo(() => {
58
- const raw = projectPath ? skillsByPath[projectPath] ?? [] : [];
87
+ const raw = projectPath ? (skillsByPath[projectPath] ?? []) : [];
59
88
  const seen = new Set<string>();
60
89
  return raw.filter((skill) => {
61
90
  const key = skill.name.toLowerCase();
@@ -65,6 +94,54 @@ export const ToolsSection = ({
65
94
  });
66
95
  }, [skillsByPath, projectPath]);
67
96
 
97
+ const installedMcpNames = useMemo(
98
+ () => new Set(mcpServers.map((entry) => entry.name.toLowerCase())),
99
+ [mcpServers]
100
+ );
101
+ const installedSkillNames = useMemo(
102
+ () => new Set(skills.map((skill) => skill.name.toLowerCase())),
103
+ [skills]
104
+ );
105
+ const availableMcpLibrary = useMemo(() => {
106
+ const query = mcpSearch.trim().toLowerCase();
107
+ return mcpLibrary.filter((entry) => {
108
+ if (!query) return true;
109
+ return [entry.name, entry.description ?? '', summarizeMcp(entry)]
110
+ .join(' ')
111
+ .toLowerCase()
112
+ .includes(query);
113
+ });
114
+ }, [mcpLibrary, mcpSearch]);
115
+ const availableUserSkills = useMemo(() => {
116
+ const query = skillSearch.trim().toLowerCase();
117
+ return userSkills.filter((skill) => {
118
+ if (installedSkillNames.has(skill.name.toLowerCase())) return false;
119
+ if (!query) return true;
120
+ return [skill.name, skill.description ?? '', skill.folderName]
121
+ .join(' ')
122
+ .toLowerCase()
123
+ .includes(query);
124
+ });
125
+ }, [installedSkillNames, skillSearch, userSkills]);
126
+ const visibleMcpLibrary = showAllMcp ? availableMcpLibrary : availableMcpLibrary.slice(0, 6);
127
+ const visibleUserSkills = showAllSkills ? availableUserSkills : availableUserSkills.slice(0, 6);
128
+ const refreshLibraries = useCallback(async (): Promise<void> => {
129
+ setLibraryLoading(true);
130
+ setLibraryError(null);
131
+ try {
132
+ const [libraryEntries, globalSkills] = await Promise.all([
133
+ api.mcpRegistry?.libraryList?.() ?? Promise.resolve([]),
134
+ api.skills?.list?.() ?? Promise.resolve([]),
135
+ ]);
136
+ setMcpLibrary(libraryEntries);
137
+ setUserSkills(globalSkills);
138
+ } catch (err) {
139
+ setLibraryError(err instanceof Error ? err.message : '加载全局能力库失败');
140
+ } finally {
141
+ setLibraryLoading(false);
142
+ }
143
+ }, []);
144
+
68
145
  // ── Fetch data on mount ──
69
146
  useEffect(() => {
70
147
  if (projectPath) {
@@ -72,75 +149,215 @@ export const ToolsSection = ({
72
149
  runMcpDiagnostics(projectPath).catch(() => {});
73
150
  fetchSkillsCatalog(projectPath).catch(() => {});
74
151
  }
75
- }, [projectPath, mcpFetchInstalled, runMcpDiagnostics, fetchSkillsCatalog]);
152
+ void refreshLibraries();
153
+ }, [projectPath, mcpFetchInstalled, runMcpDiagnostics, fetchSkillsCatalog, refreshLibraries]);
76
154
 
77
155
  // ── Handlers ──
78
156
  const handleRemoveMcp = useCallback(
79
157
  (entry: { name: string; scope: string }) => {
80
158
  void (async () => {
81
159
  const confirmed = await confirm({
82
- title: '删除 MCP 服务器',
83
- message: `确认删除 MCP 服务器「${entry.name}」?删除后该工具将不再可用。`,
84
- confirmLabel: '删除',
160
+ title: '移除 MCP 项目实例',
161
+ message: `确认从当前项目移除 MCP 实例「${entry.name}」?全局模板不会被删除。`,
162
+ confirmLabel: '移除实例',
85
163
  cancelLabel: '取消',
86
164
  variant: 'danger',
87
165
  });
88
166
  if (!confirmed) return;
89
- uninstallMcpServer('', entry.name, entry.scope, projectPath ?? undefined).catch(() => {});
167
+ uninstallMcpServer('', entry.name, entry.scope, projectPath ?? undefined)
168
+ .then(() => {
169
+ setApplyNotice('MCP 实例已移除;正在运行的数字员工需要重启后才会卸载该能力。');
170
+ })
171
+ .catch(() => {});
90
172
  })();
91
173
  },
92
- [uninstallMcpServer, projectPath],
174
+ [uninstallMcpServer, projectPath]
93
175
  );
94
176
 
95
177
  const handleRemoveSkill = useCallback(
96
178
  (skill: { id: string; name: string }) => {
97
179
  void (async () => {
98
180
  const confirmed = await confirm({
99
- title: '删除 Skill',
100
- message: `确认删除 Skill「${skill.name}」?删除后该技能将不再可用。`,
101
- confirmLabel: '删除',
181
+ title: '禁用 Skill',
182
+ message: `确认从当前团队禁用 Skill「${skill.name}」?全局 Skill 仍会保留。`,
183
+ confirmLabel: '禁用',
102
184
  cancelLabel: '取消',
103
185
  variant: 'danger',
104
186
  });
105
187
  if (!confirmed) return;
106
- deleteSkill({ skillId: skill.id, projectPath: projectPath ?? undefined }).catch(() => {});
188
+ deleteSkill({ skillId: skill.id, projectPath: projectPath ?? undefined })
189
+ .then(() => {
190
+ setApplyNotice('Skill 已禁用;正在运行的数字员工需要重启后才会卸载该能力。');
191
+ })
192
+ .catch(() => {});
107
193
  })();
108
194
  },
109
- [deleteSkill, projectPath],
195
+ [deleteSkill, projectPath]
110
196
  );
111
197
 
112
- const handleMcpAdded = useCallback(() => {
113
- setAddingMcp(false);
198
+ const handleMcpTemplateAdded = useCallback(
199
+ (entry: McpLibraryEntry) => {
200
+ setAddingMcp(false);
201
+ setMcpLibrary((prev) => {
202
+ const next = prev.filter((item) => item.id !== entry.id);
203
+ return [entry, ...next];
204
+ });
205
+ setSelectedMcpTemplate(entry);
206
+ void refreshLibraries();
207
+ },
208
+ [refreshLibraries]
209
+ );
210
+
211
+ const handleMcpInstanceAdded = useCallback(() => {
212
+ setSelectedMcpTemplate(null);
114
213
  if (projectPath) {
115
214
  mcpFetchInstalled(projectPath).catch(() => {});
116
215
  runMcpDiagnostics(projectPath).catch(() => {});
117
216
  }
118
- }, [projectPath, mcpFetchInstalled, runMcpDiagnostics]);
217
+ void refreshLibraries();
218
+ }, [projectPath, mcpFetchInstalled, runMcpDiagnostics, refreshLibraries]);
219
+
220
+ const handleImportMcpTemplates = useCallback(() => {
221
+ void (async () => {
222
+ if (!api.mcpRegistry?.libraryImport) {
223
+ setLibraryError('MCP 模板导入 API 不可用');
224
+ return;
225
+ }
226
+ setImportingMcpTemplates(true);
227
+ setLibraryError(null);
228
+ try {
229
+ const result = await api.mcpRegistry.libraryImport({
230
+ projectPath: projectPath ?? undefined,
231
+ });
232
+ await refreshLibraries();
233
+ setApplyNotice(
234
+ `已从现有 MCP 配置导入模板:新增 ${result.imported.length} 个,跳过 ${result.skipped.length} 个。`
235
+ );
236
+ } catch (err) {
237
+ setLibraryError(err instanceof Error ? err.message : '导入现有 MCP 配置失败');
238
+ } finally {
239
+ setImportingMcpTemplates(false);
240
+ }
241
+ })();
242
+ }, [projectPath, refreshLibraries]);
119
243
 
120
244
  const handleSkillAdded = useCallback(() => {
121
245
  setAddingSkill(false);
122
246
  if (projectPath) {
123
247
  fetchSkillsCatalog(projectPath).catch(() => {});
124
248
  }
125
- }, [projectPath, fetchSkillsCatalog]);
249
+ void refreshLibraries();
250
+ }, [projectPath, fetchSkillsCatalog, refreshLibraries]);
251
+
252
+ const enableSkillFromLibrary = useCallback(
253
+ async (skill: SkillCatalogItem): Promise<void> => {
254
+ if (!projectPath) return;
255
+ setEnablingSkillId(skill.id);
256
+ try {
257
+ await fetchSkillDetail(skill.id);
258
+ const detail =
259
+ useStore.getState().skillsDetailsById[skill.id] ?? skillDetailsById[skill.id];
260
+ const sourceDir = detail?.item.skillDir ?? skill.skillDir;
261
+ const preview = await previewSkillImport({
262
+ sourceDir,
263
+ scope: 'project',
264
+ rootKind: skill.rootKind,
265
+ projectPath,
266
+ folderName: skill.folderName,
267
+ });
268
+ await applySkillImport({
269
+ sourceDir,
270
+ scope: 'project',
271
+ rootKind: skill.rootKind,
272
+ projectPath,
273
+ folderName: skill.folderName,
274
+ reviewPlanId: preview.planId,
275
+ });
276
+ await fetchSkillsCatalog(projectPath);
277
+ setApplyNotice('Skill 已启用;正在运行的数字员工需要重启后才会加载新能力。');
278
+ } finally {
279
+ setEnablingSkillId(null);
280
+ }
281
+ },
282
+ [
283
+ applySkillImport,
284
+ fetchSkillDetail,
285
+ fetchSkillsCatalog,
286
+ previewSkillImport,
287
+ projectPath,
288
+ skillDetailsById,
289
+ ]
290
+ );
126
291
 
127
292
  if (!projectPath) {
128
293
  return (
129
294
  <div className="flex items-center gap-2 px-1 py-2 text-xs text-[var(--color-text-muted)]">
130
295
  <Wrench size={12} />
131
- <span>需要关联项目目录才能管理工具</span>
296
+ <span>需要关联项目目录才能管理能力</span>
132
297
  </div>
133
298
  );
134
299
  }
135
300
 
136
301
  return (
137
- <div className="flex flex-col gap-3 px-1 py-2">
138
- {/* MCP 工具 */}
139
- <div className="flex flex-col gap-1.5">
140
- <div className="flex items-center gap-1.5 text-[11px] font-medium text-[var(--color-text-muted)]">
141
- <span>MCP 工具</span>
142
- <span className="text-[10px]">({mcpServers.length})</span>
302
+ <div className="flex flex-col gap-4 px-1 py-2">
303
+ {libraryError ? (
304
+ <div className="rounded-md border border-amber-500/30 bg-amber-500/10 px-2 py-1.5 text-xs text-amber-300">
305
+ {libraryError}
143
306
  </div>
307
+ ) : null}
308
+
309
+ {applyNotice ? (
310
+ <div className="rounded-md border border-indigo-500/30 bg-indigo-500/10 px-2 py-1.5 text-xs text-indigo-300">
311
+ {applyNotice}
312
+ </div>
313
+ ) : null}
314
+
315
+ <div className="flex items-center justify-between gap-2">
316
+ <div className="text-[11px] text-[var(--color-text-muted)]">
317
+ 当前项目管理 MCP 实例;全局库只提供可复用模板。先导入/新建模板,再添加为项目实例。
318
+ </div>
319
+ <div className="flex items-center gap-1">
320
+ <Button
321
+ variant="ghost"
322
+ size="sm"
323
+ className="h-6 px-2 text-[11px]"
324
+ disabled={importingMcpTemplates}
325
+ onClick={handleImportMcpTemplates}
326
+ >
327
+ {importingMcpTemplates ? '导入中...' : '导入现有 MCP'}
328
+ </Button>
329
+ <Button
330
+ variant="ghost"
331
+ size="sm"
332
+ className="h-6 px-2 text-[11px]"
333
+ onClick={() => void refreshLibraries()}
334
+ >
335
+ <RefreshCw className={libraryLoading ? 'mr-1 size-3 animate-spin' : 'mr-1 size-3'} />
336
+ 刷新
337
+ </Button>
338
+ </div>
339
+ </div>
340
+
341
+ {/* MCP capabilities */}
342
+ <div className="flex flex-col gap-2 rounded-lg border border-[var(--color-border-subtle)] bg-white/[0.015] p-2">
343
+ <div className="flex items-center justify-between gap-2">
344
+ <div className="flex items-center gap-1.5 text-[11px] font-medium text-[var(--color-text-muted)]">
345
+ <span>MCP 实例</span>
346
+ <span className="text-[10px]">
347
+ 已配置实例 {mcpServers.length} · 模板 {mcpLibrary.length}
348
+ </span>
349
+ </div>
350
+ <Button
351
+ variant="ghost"
352
+ size="sm"
353
+ className="h-6 px-2 text-[11px]"
354
+ onClick={() => setAddingMcp(true)}
355
+ >
356
+ <Plus size={10} className="mr-1" />
357
+ 新建模板
358
+ </Button>
359
+ </div>
360
+
144
361
  <div className="flex flex-wrap items-center gap-1.5">
145
362
  {mcpServers.map((entry) => (
146
363
  <McpChip
@@ -150,56 +367,187 @@ export const ToolsSection = ({
150
367
  onRemove={handleRemoveMcp}
151
368
  />
152
369
  ))}
153
- {addingMcp ? (
154
- <AddMcpInline
155
- projectPath={projectPath}
156
- harnessType={harnessType ?? 'claudecode'}
157
- onAdded={handleMcpAdded}
158
- onCancel={() => setAddingMcp(false)}
159
- />
370
+ {mcpServers.length === 0 ? (
371
+ <span className="text-xs text-[var(--color-text-muted)]">
372
+ 当前项目还没有配置 MCP 实例。
373
+ </span>
374
+ ) : null}
375
+ </div>
376
+
377
+ {addingMcp ? (
378
+ <AddMcpInline onAdded={handleMcpTemplateAdded} onCancel={() => setAddingMcp(false)} />
379
+ ) : null}
380
+
381
+ <div className="space-y-1.5">
382
+ <div className="text-[10px] uppercase tracking-wide text-[var(--color-text-muted)]">
383
+ 从模板添加
384
+ </div>
385
+ <Input
386
+ value={mcpSearch}
387
+ onChange={(event) => setMcpSearch(event.target.value)}
388
+ placeholder="搜索 MCP 模板..."
389
+ className="h-7 text-xs"
390
+ />
391
+ {availableMcpLibrary.length > 0 ? (
392
+ <div className="flex flex-col gap-1.5">
393
+ {visibleMcpLibrary.map((entry) => (
394
+ <div
395
+ key={entry.id}
396
+ className="flex items-center justify-between gap-2 rounded-md border border-[var(--color-border-subtle)] px-2 py-1.5"
397
+ >
398
+ <div className="min-w-0">
399
+ <div className="truncate text-xs text-[var(--color-text)]">{entry.name}</div>
400
+ <div className="truncate text-[10px] text-[var(--color-text-muted)]">
401
+ {summarizeMcp(entry)}
402
+ </div>
403
+ </div>
404
+ <Button
405
+ variant="outline"
406
+ size="sm"
407
+ className="h-6 px-2 text-[11px]"
408
+ onClick={() => setSelectedMcpTemplate(entry)}
409
+ >
410
+ 从模板添加
411
+ </Button>
412
+ </div>
413
+ ))}
414
+ {availableMcpLibrary.length > 6 ? (
415
+ <Button
416
+ variant="ghost"
417
+ size="sm"
418
+ className="h-6 justify-start px-2 text-[11px]"
419
+ onClick={() => setShowAllMcp((value) => !value)}
420
+ >
421
+ {showAllMcp ? '收起' : `显示全部 ${availableMcpLibrary.length} 个模板`}
422
+ </Button>
423
+ ) : null}
424
+ </div>
160
425
  ) : (
161
- <button
162
- type="button"
163
- onClick={() => setAddingMcp(true)}
164
- className="inline-flex items-center gap-1 rounded-full border border-dashed border-[var(--color-border)] px-2 py-1 text-xs text-[var(--color-text-muted)] transition-colors hover:border-[var(--color-text-muted)] hover:text-[var(--color-text)]"
165
- >
166
- <Plus size={10} />
167
- 添加
168
- </button>
426
+ <div className="flex flex-col gap-2 rounded-md border border-dashed border-[var(--color-border)] px-2 py-2 text-xs text-[var(--color-text-muted)]">
427
+ <span>全局 MCP 模板库暂无可添加项。可以从现有 MCP 配置导入,或新建模板。</span>
428
+ <div className="flex flex-wrap gap-2">
429
+ <Button
430
+ variant="outline"
431
+ size="sm"
432
+ className="h-6 px-2 text-[11px]"
433
+ disabled={importingMcpTemplates}
434
+ onClick={handleImportMcpTemplates}
435
+ >
436
+ {importingMcpTemplates ? '导入中...' : '导入现有 MCP'}
437
+ </Button>
438
+ <Button
439
+ variant="ghost"
440
+ size="sm"
441
+ className="h-6 px-2 text-[11px]"
442
+ onClick={() => setAddingMcp(true)}
443
+ >
444
+ 新建模板
445
+ </Button>
446
+ </div>
447
+ </div>
169
448
  )}
170
449
  </div>
171
450
  </div>
172
451
 
173
- {/* Skills */}
174
- <div className="flex flex-col gap-1.5">
175
- <div className="flex items-center gap-1.5 text-[11px] font-medium text-[var(--color-text-muted)]">
176
- <span>Skills</span>
177
- <span className="text-[10px]">({skills.length})</span>
452
+ <McpLibraryEnableDialog
453
+ open={Boolean(selectedMcpTemplate)}
454
+ entry={selectedMcpTemplate}
455
+ projectPath={projectPath}
456
+ installedServers={mcpServers}
457
+ harnessType={harnessType}
458
+ onClose={() => setSelectedMcpTemplate(null)}
459
+ onEnabled={handleMcpInstanceAdded}
460
+ />
461
+
462
+ {/* Skill capabilities */}
463
+ <div className="flex flex-col gap-2 rounded-lg border border-[var(--color-border-subtle)] bg-white/[0.015] p-2">
464
+ <div className="flex items-center justify-between gap-2">
465
+ <div className="flex items-center gap-1.5 text-[11px] font-medium text-[var(--color-text-muted)]">
466
+ <span>Skill 能力</span>
467
+ <span className="text-[10px]">
468
+ 已启用 {skills.length} · 全局 {userSkills.length}
469
+ </span>
470
+ </div>
471
+ <Button
472
+ variant="ghost"
473
+ size="sm"
474
+ className="h-6 px-2 text-[11px]"
475
+ onClick={() => setAddingSkill(true)}
476
+ >
477
+ <Plus size={10} className="mr-1" />
478
+ 新建 Skill
479
+ </Button>
178
480
  </div>
481
+
179
482
  <div className="flex flex-wrap items-center gap-1.5">
180
483
  {skills.map((skill) => (
181
- <SkillChip
182
- key={skill.id}
183
- skill={skill}
184
- onRemove={handleRemoveSkill}
185
- />
484
+ <SkillChip key={skill.id} skill={skill} onRemove={handleRemoveSkill} />
186
485
  ))}
187
- {addingSkill ? (
188
- <AddSkillInline
189
- projectPath={projectPath}
190
- projectLabel={teamName}
191
- onAdded={handleSkillAdded}
192
- onCancel={() => setAddingSkill(false)}
193
- />
486
+ {skills.length === 0 ? (
487
+ <span className="text-xs text-[var(--color-text-muted)]">
488
+ 当前团队还没有启用 Skill。
489
+ </span>
490
+ ) : null}
491
+ </div>
492
+
493
+ {addingSkill ? (
494
+ <AddSkillInline
495
+ projectPath={projectPath}
496
+ projectLabel={teamName}
497
+ onAdded={handleSkillAdded}
498
+ onCancel={() => setAddingSkill(false)}
499
+ />
500
+ ) : null}
501
+
502
+ <div className="space-y-1.5">
503
+ <div className="text-[10px] uppercase tracking-wide text-[var(--color-text-muted)]">
504
+ 从全局 Skill 启用
505
+ </div>
506
+ <Input
507
+ value={skillSearch}
508
+ onChange={(event) => setSkillSearch(event.target.value)}
509
+ placeholder="搜索 Skill..."
510
+ className="h-7 text-xs"
511
+ />
512
+ {availableUserSkills.length > 0 ? (
513
+ <div className="flex flex-col gap-1.5">
514
+ {visibleUserSkills.map((skill) => (
515
+ <div
516
+ key={skill.id}
517
+ className="flex items-center justify-between gap-2 rounded-md border border-[var(--color-border-subtle)] px-2 py-1.5"
518
+ >
519
+ <div className="min-w-0">
520
+ <div className="truncate text-xs text-[var(--color-text)]">{skill.name}</div>
521
+ <div className="truncate text-[10px] text-[var(--color-text-muted)]">
522
+ {skill.description || skill.folderName}
523
+ </div>
524
+ </div>
525
+ <Button
526
+ variant="outline"
527
+ size="sm"
528
+ className="h-6 px-2 text-[11px]"
529
+ disabled={enablingSkillId === skill.id}
530
+ onClick={() => void enableSkillFromLibrary(skill)}
531
+ >
532
+ {enablingSkillId === skill.id ? '启用中...' : '启用'}
533
+ </Button>
534
+ </div>
535
+ ))}
536
+ {availableUserSkills.length > 6 ? (
537
+ <Button
538
+ variant="ghost"
539
+ size="sm"
540
+ className="h-6 justify-start px-2 text-[11px]"
541
+ onClick={() => setShowAllSkills((value) => !value)}
542
+ >
543
+ {showAllSkills ? '收起' : `显示全部 ${availableUserSkills.length} 个 Skill`}
544
+ </Button>
545
+ ) : null}
546
+ </div>
194
547
  ) : (
195
- <button
196
- type="button"
197
- onClick={() => setAddingSkill(true)}
198
- className="inline-flex items-center gap-1 rounded-full border border-dashed border-[var(--color-border)] px-2 py-1 text-xs text-[var(--color-text-muted)] transition-colors hover:border-[var(--color-text-muted)] hover:text-[var(--color-text)]"
199
- >
200
- <Plus size={10} />
201
- 添加
202
- </button>
548
+ <div className="rounded-md border border-dashed border-[var(--color-border)] px-2 py-2 text-xs text-[var(--color-text-muted)]">
549
+ 全局 Skill 暂无可启用项。可以先创建用户级 Skill,再在团队中启用。
550
+ </div>
203
551
  )}
204
552
  </div>
205
553
  </div>
@@ -150,7 +150,7 @@ export const MemberSelect = ({
150
150
  >
151
151
  <span className="text-[var(--color-text-muted)]">未分配</span>
152
152
  {value === null ? (
153
- <Check size={12} className="ml-auto shrink-0 text-blue-400" />
153
+ <Check size={12} className="ml-auto shrink-0 text-indigo-400" />
154
154
  ) : null}
155
155
  </CommandPrimitive.Item>
156
156
  ) : null}
@@ -196,7 +196,7 @@ export const MemberSelect = ({
196
196
  </span>
197
197
  ) : null}
198
198
  {isSelected ? (
199
- <Check size={12} className="ml-auto shrink-0 text-blue-400" />
199
+ <Check size={12} className="ml-auto shrink-0 text-indigo-400" />
200
200
  ) : null}
201
201
  </CommandPrimitive.Item>
202
202
  );
@@ -165,7 +165,7 @@ export const MentionSuggestionList = ({
165
165
  ) : isFile ? (
166
166
  <FileIcon fileName={s.name} className="size-3.5" />
167
167
  ) : isTask ? (
168
- <Hash size={13} className="shrink-0 text-blue-500 dark:text-blue-400" />
168
+ <Hash size={13} className="shrink-0 text-indigo-500 dark:text-indigo-400" />
169
169
  ) : isCommand ? (
170
170
  <Command size={13} className="shrink-0 text-amber-500 dark:text-amber-400" />
171
171
  ) : isSkill ? (
@@ -190,7 +190,7 @@ export const MentionSuggestionList = ({
190
190
  className={isFileOrFolder ? 'truncate' : 'font-medium'}
191
191
  style={
192
192
  isTask
193
- ? { color: 'var(--color-link, #60a5fa)' }
193
+ ? { color: 'var(--color-link, #818cf8)' }
194
194
  : isCommand
195
195
  ? { color: 'rgb(245 158 11)' }
196
196
  : isSkill
@@ -309,8 +309,8 @@ function parseSegments(
309
309
  }
310
310
 
311
311
  // Default fallback color for mentions without a team color
312
- const DEFAULT_MENTION_BG = 'rgba(59, 130, 246, 0.15)';
313
- const DEFAULT_MENTION_TEXT = '#60a5fa';
312
+ const DEFAULT_MENTION_BG = 'rgba(99, 102, 241, 0.15)';
313
+ const DEFAULT_MENTION_TEXT = '#818cf8';
314
314
  const URL_BADGE_BG = 'var(--url-badge-bg)';
315
315
  const URL_BADGE_BORDER = 'var(--url-badge-border)';
316
316
  const URL_BADGE_TEXT = 'var(--url-badge-text)';
@@ -1235,7 +1235,7 @@ export const MentionableTextarea = React.forwardRef<HTMLTextAreaElement, Mention
1235
1235
  style={
1236
1236
  seg.encoded
1237
1237
  ? {
1238
- backgroundColor: 'rgba(59, 130, 246, 0.15)',
1238
+ backgroundColor: 'rgba(99, 102, 241, 0.15)',
1239
1239
  color: PROSE_LINK,
1240
1240
  // Only vertical padding (doesn't affect inline text flow).
1241
1241
  // No horizontal padding/margin/box-shadow spread to avoid