@yancyyu/openhermit 1.6.41 → 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-Br0X83Jf.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
  4. package/dist-renderer/assets/{TeamGraphOverlay-DHMTbZPZ.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
  5. package/dist-renderer/assets/{_basePickBy-DzIiX7yH.js → _basePickBy-ZOyLWjMK.js} +1 -1
  6. package/dist-renderer/assets/{_baseUniq-6hZuzTLU.js → _baseUniq-DBb726rt.js} +1 -1
  7. package/dist-renderer/assets/{arc-CXgO6fx_.js → arc-CdiTaR_R.js} +1 -1
  8. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DKWgtDHr.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
  9. package/dist-renderer/assets/{blockDiagram-VD42YOAC-DOMUcC40.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
  10. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-B_k2L7qX.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
  11. package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
  12. package/dist-renderer/assets/{chunk-4BX2VUAB-BeD_ccFy.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
  13. package/dist-renderer/assets/{chunk-55IACEB6-ClZfkA5w.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
  14. package/dist-renderer/assets/{chunk-B4BG7PRW-5XluxXsn.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
  15. package/dist-renderer/assets/{chunk-DI55MBZ5-BzIjjNVm.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
  16. package/dist-renderer/assets/{chunk-FMBD7UC4-HgH3MK_H.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QN33PNHL-WeC5T3Ba.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QZHKN3VN-Cu1ApHfW.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
  19. package/dist-renderer/assets/{chunk-TZMSLE5B-BOhlynJM.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-DGZSihDQ.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
  24. package/dist-renderer/assets/{dagre-6UL2VRFP-CnxwCbku.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
  25. package/dist-renderer/assets/{diagram-PSM6KHXK-DsIhoxdI.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
  26. package/dist-renderer/assets/{diagram-QEK2KX5R-Cmh9KUF5.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
  27. package/dist-renderer/assets/{diagram-S2PKOQOG-CKxV456A.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
  28. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-EnvYjOjc.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
  29. package/dist-renderer/assets/{flowDiagram-NV44I4VS-BmNeWY_A.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
  30. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-D30fyK-u.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
  31. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-CrUNiYg1.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
  32. package/dist-renderer/assets/{graph-CY1gTfTb.js → graph-CDP_R8ct.js} +1 -1
  33. package/dist-renderer/assets/{index-CaEbzwAU.js → index-BSZdT-g-.js} +1 -1
  34. package/dist-renderer/assets/{index-D5K-SjBG.js → index-BhWvMqsz.js} +1 -1
  35. package/dist-renderer/assets/{index-9_hO4N1e.js → index-C2_AupSj.js} +1 -1
  36. package/dist-renderer/assets/{index-59r209c1.js → index-C5ujiwAR.js} +580 -588
  37. package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
  38. package/dist-renderer/assets/{index-DMR9B1UP.js → index-CVNjLwkq.js} +1 -1
  39. package/dist-renderer/assets/{index-BC2hXmg_.js → index-CwG3se0q.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-By_XUlcD.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BM1LJE9m.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-DHIW3aTA.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
  43. package/dist-renderer/assets/{layout-DAKiL_Mo.js → layout-5nA5wUxO.js} +1 -1
  44. package/dist-renderer/assets/{linear-DwOaRYea.js → linear-BtF1i2qN.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-b7bJ2cha.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-DxyL9Zr2.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CR33pHlF.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BAiSRSlh.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-C8JmDjoa.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-c1d0Wi1m.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-nT8BiH2O.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-DpoRepUA.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
  55. package/dist-renderer/assets/{treemap-GDKQZRPO-C41UJeIH.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
  56. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-KMjGARKN.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 +1731 -539
  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 +744 -0
  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 +132 -52
  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 +144 -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 +189 -57
  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 +43 -3
  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-D0XS_akr.js +0 -1
  274. package/dist-renderer/assets/classDiagram-2ON5EDUG-D13Ffs0U.js +0 -1
  275. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-D13Ffs0U.js +0 -1
  276. package/dist-renderer/assets/clone-B1ZrxI1D.js +0 -1
  277. package/dist-renderer/assets/index-iyjkpSus.css +0 -32
  278. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-Dmibmlso.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
@@ -25,6 +25,7 @@ import { useCreateTeamDraft } from '@renderer/hooks/useCreateTeamDraft';
25
25
  import { useTheme } from '@renderer/hooks/useTheme';
26
26
  import { cn } from '@renderer/lib/utils';
27
27
  import { normalizePath } from '@renderer/utils/pathNormalize';
28
+ import { generateBindProject, isValidBindProject } from '@renderer/utils/bindProjectSlug';
28
29
  import { isEphemeralProjectPath } from '@shared/utils/ephemeralProjectPath';
29
30
  import { AlertTriangle, CheckCircle2, X } from 'lucide-react';
30
31
 
@@ -62,19 +63,7 @@ export interface TeamCopyData {
62
63
  templateDirectoryId?: string;
63
64
  }
64
65
 
65
- /**
66
- * Sanitize team name: keep Unicode letters and digits (Chinese, Latin, etc.),
67
- * replace other sequences with `-`, then lowercase Latin chars.
68
- */
69
- function sanitizeTeamName(name: string): string {
70
- const trimmed = name.trim();
71
- if (!trimmed) return '';
72
- let result = trimmed
73
- .replace(/[^\p{L}\p{N}]+/gu, '-')
74
- .replace(/^-+|-+$/g, '')
75
- .toLowerCase();
76
- return result;
77
- }
66
+ // bindProject slug rules live in @renderer/utils/bindProjectSlug (unit-tested).
78
67
 
79
68
  // ---------------------------------------------------------------------------
80
69
  // Wizard step types
@@ -92,6 +81,8 @@ interface CreateTeamDialogProps {
92
81
  provisioningErrorsByTeam: Record<string, string | null>;
93
82
  clearProvisioningError?: (teamName?: string) => void;
94
83
  existingTeamNames: string[];
84
+ existingBindProjects?: string[];
85
+ existingDisplayNames?: string[];
95
86
  provisioningTeamNames?: string[];
96
87
  activeTeams?: ActiveTeamRef[];
97
88
  initialData?: unknown;
@@ -107,6 +98,8 @@ export const CreateTeamDialog = ({
107
98
  provisioningErrorsByTeam,
108
99
  clearProvisioningError,
109
100
  existingTeamNames,
101
+ existingBindProjects = [],
102
+ existingDisplayNames = [],
110
103
  provisioningTeamNames = [],
111
104
  activeTeams,
112
105
  defaultProjectPath,
@@ -137,6 +130,14 @@ export const CreateTeamDialog = ({
137
130
  const [selectedHarness, setSelectedHarness] = useState<CcAgentType>('claudecode');
138
131
  const [description, setDescription] = useState('');
139
132
 
133
+ // ── bindProject (ASCII unique identifier) ────────────────────────────
134
+ // Only the *manual* override is state. The auto value is DERIVED (below) so
135
+ // it is collision-free in the SAME render as `existingBindProjectSet`. A
136
+ // state + useEffect pair lagged one render behind the set and flickered a
137
+ // false "该项目标识已存在" red box whenever the teams list refreshed.
138
+ const [manualBindProject, setManualBindProject] = useState('');
139
+ const [bindProjectManuallyEdited, setBindProjectManuallyEdited] = useState(false);
140
+
140
141
  // ── Projects (for path selector) ─────────────────────────────────────
141
142
  const [projects, setProjects] = useState<Project[]>([]);
142
143
  const [projectsLoading, setProjectsLoading] = useState(false);
@@ -150,21 +151,63 @@ export const CreateTeamDialog = ({
150
151
  const [localError, setLocalError] = useState<string | null>(null);
151
152
  const [isSubmitting, setIsSubmitting] = useState(false);
152
153
  const [fieldErrors, setFieldErrors] = useState<{ teamName?: string; cwd?: string }>({});
154
+ // The slug ACTUALLY used at creation. The live `bindProject` re-derives once
155
+ // the parent's fetchTeams() refreshes existingBindProjects (the just-created
156
+ // slug is now taken) and its numeric-counter fallback can land on an
157
+ // UNRELATED existing team's slug — so the done step's "open" button must use
158
+ // this captured id, not the re-derived one. See the "opens the JUST-CREATED
159
+ // team" regression test.
160
+ const [createdTeamName, setCreatedTeamName] = useState<string | null>(null);
153
161
 
154
162
  // ── Name conflict detection ──────────────────────────────────────────
155
- const allTakenTeamNames = useMemo(
156
- () => [...new Set([...existingTeamNames, ...provisioningTeamNames])],
157
- [existingTeamNames, provisioningTeamNames]
163
+ const existingBindProjectSet = useMemo(
164
+ () => new Set(existingBindProjects.map((value) => value.trim().toLowerCase()).filter(Boolean)),
165
+ [existingBindProjects]
166
+ );
167
+ const provisioningTeamNameSet = useMemo(
168
+ () => new Set(provisioningTeamNames.map((value) => value.trim().toLowerCase()).filter(Boolean)),
169
+ [provisioningTeamNames]
170
+ );
171
+ // displayName (the human-readable name) must be unique too. A duplicate name
172
+ // silently produced a ghost team (the 222-2 incident: draft-restored name +
173
+ // auto-collision-free bindProject + a second create click), so block it up front.
174
+ const existingDisplayNameSet = useMemo(
175
+ () => new Set(existingDisplayNames.map((value) => value.trim().toLowerCase()).filter(Boolean)),
176
+ [existingDisplayNames]
158
177
  );
159
- const sanitizedTeamName = sanitizeTeamName(teamName);
160
- const trimmedInputName = teamName.trim().toLowerCase();
161
- // Check both slug (for ASCII names) and display name (for Chinese/Unicode names)
162
- // This prevents creating "产品经理团队" multiple times with different slugs (team-3, team-4...)
163
- const isNameTaken =
164
- existingTeamNames.includes(sanitizedTeamName) ||
165
- activeTeams?.some((t) => t.displayName.toLowerCase() === trimmedInputName) === true;
178
+ const isDisplayNameTaken =
179
+ Boolean(teamName.trim()) && existingDisplayNameSet.has(teamName.trim().toLowerCase());
180
+ // The collision check is reactive to the live `teams` list. The instant a
181
+ // create succeeds, the parent store adds the new team and `isDisplayNameTaken`
182
+ // trips on the just-created name for the one frame before the dialog moves to
183
+ // the success step — a false "该名称已存在" red-box flicker. Validation
184
+ // (validateCreateFields) runs pre-submit and still uses the raw check, but the
185
+ // *visual* red box / error text / disabled state is suppressed while a create
186
+ // is in flight, since by then the name has already been accepted.
187
+ const showDisplayNameTaken = isDisplayNameTaken && !isSubmitting;
188
+
189
+ // bindProject is DERIVED, not state. The auto value is generated in the same
190
+ // render as `existingBindProjectSet`, so it is collision-free BY CONSTRUCTION
191
+ // and `isBindProjectTaken` can never flicker true between a set change and an
192
+ // effect flush. (The previous state + useEffect implementation lagged one
193
+ // render and produced a transient false "该项目标识已存在" red box.)
194
+ const autoBindProject = useMemo(
195
+ () => generateBindProject(teamName, existingBindProjectSet),
196
+ [teamName, existingBindProjectSet]
197
+ );
198
+ const bindProject = bindProjectManuallyEdited ? manualBindProject : autoBindProject;
199
+ const normalizedBindProject = bindProject.trim().toLowerCase();
200
+
201
+ const isBindProjectTaken = existingBindProjectSet.has(normalizedBindProject);
202
+ // Slug the done-step "open" + provisioning-error lookup target: the one
203
+ // actually used at creation (captured), falling back to the live form value
204
+ // before creation. Never the re-derived `bindProject` once the parent list
205
+ // refreshes — that drifts to a different/colliding id (createdTeamName note).
206
+ const openTeamSlug = createdTeamName ?? bindProject;
166
207
  const isNameProvisioning =
167
- (provisioningTeamNames.includes(sanitizedTeamName) && !isNameTaken);
208
+ provisioningTeamNameSet.has(normalizedBindProject) && !isBindProjectTaken;
209
+ const isBindProjectFormatInvalid =
210
+ Boolean(bindProject) && !isValidBindProject(normalizedBindProject);
168
211
 
169
212
  const effectiveCwd =
170
213
  cwdMode === 'project'
@@ -267,8 +310,8 @@ export const CreateTeamDialog = ({
267
310
 
268
311
  // ── Clear provisioning error on open ─────────────────────────────────
269
312
  useEffect(() => {
270
- if (open && sanitizedTeamName) clearProvisioningError?.(sanitizedTeamName);
271
- }, [open, clearProvisioningError, sanitizedTeamName]);
313
+ if (open && bindProject) clearProvisioningError?.(bindProject);
314
+ }, [open, clearProvisioningError, bindProject]);
272
315
 
273
316
  // ── Reset state on close ─────────────────────────────────────────────
274
317
  const resetState = () => {
@@ -277,12 +320,24 @@ export const CreateTeamDialog = ({
277
320
  setIsSubmitting(false);
278
321
  setConflictDismissed(false);
279
322
  setSelectedProviderRef(null);
323
+ setManualBindProject('');
324
+ setBindProjectManuallyEdited(false);
325
+ setCreatedTeamName(null);
280
326
  setStep('name');
281
327
  };
282
328
 
329
+ // Every close path (overlay click, ✕, 取消) clears the persisted draft so a
330
+ // stale restored name can never seed a duplicate create on reopen.
331
+ const handleClose = () => {
332
+ clearDraft();
333
+ resetState();
334
+ onClose();
335
+ };
336
+
283
337
  const buildCreateRequest = (): TeamCreateRequest => ({
284
- teamName: sanitizedTeamName,
285
- displayName: teamName.trim() || undefined,
338
+ teamName: normalizedBindProject,
339
+ bindProject: normalizedBindProject,
340
+ displayName: teamName.trim(),
286
341
  description: description.trim() || undefined,
287
342
  color: teamColor || undefined,
288
343
  members: [],
@@ -295,12 +350,30 @@ export const CreateTeamDialog = ({
295
350
  });
296
351
 
297
352
  const validateCreateFields = (): boolean => {
298
- if (allTakenTeamNames.includes(sanitizedTeamName)) {
299
- setLocalError(isNameProvisioning ? '数字员工正在启动中' : '数字员工名称已存在');
353
+ if (!teamName.trim()) {
354
+ setLocalError('请输入数字员工名称');
300
355
  return false;
301
356
  }
302
- if (!sanitizedTeamName) {
303
- setLocalError('请输入数字员工名称');
357
+ if (isDisplayNameTaken) {
358
+ setLocalError('该名称已存在,请换一个');
359
+ return false;
360
+ }
361
+ if (!normalizedBindProject) {
362
+ setLocalError('请输入项目标识');
363
+ return false;
364
+ }
365
+ if (!isValidBindProject(normalizedBindProject)) {
366
+ setLocalError(
367
+ '项目标识为必填,只能包含小写英文字母、数字、连字符和下划线,且必须以字母或数字开头'
368
+ );
369
+ return false;
370
+ }
371
+ if (isNameProvisioning) {
372
+ setLocalError('数字员工正在启动中');
373
+ return false;
374
+ }
375
+ if (isBindProjectTaken) {
376
+ setLocalError(`项目标识"${normalizedBindProject}"已存在,请换一个`);
304
377
  return false;
305
378
  }
306
379
  if (!effectiveCwd) {
@@ -310,8 +383,8 @@ export const CreateTeamDialog = ({
310
383
  return true;
311
384
  };
312
385
 
313
- const createLocalTeam = async (): Promise<TeamCreateRequest | null> => {
314
- if (!validateCreateFields()) return null;
386
+ const createLocalTeam = async (): Promise<boolean> => {
387
+ if (!validateCreateFields()) return false;
315
388
 
316
389
  setFieldErrors({});
317
390
  setLocalError(null);
@@ -320,19 +393,31 @@ export const CreateTeamDialog = ({
320
393
  try {
321
394
  const request = buildCreateRequest();
322
395
  await onCreate(request);
323
- return request;
396
+ // Capture the slug that was actually persisted. The done step opens /
397
+ // surfaces errors for THIS team; the live `bindProject` would drift to a
398
+ // different id once the parent list refreshes (see createdTeamName note).
399
+ setCreatedTeamName(request.teamName);
400
+ // Advance to the success step in the SAME synchronous block as the
401
+ // `finally` that releases isSubmitting. The create just added this name
402
+ // to the parent's existingDisplayNames; if the name step re-rendered
403
+ // with isSubmitting already false, `showDisplayNameTaken` would trip on
404
+ // the just-created name for one frame — the false "该名称已存在"
405
+ // red-box flicker right before the success screen. Setting 'done' here
406
+ // (no await between it and the finally) batches with
407
+ // setIsSubmitting(false), so the name step is unmounted atomically and
408
+ // that transition window never opens.
409
+ setStep('done');
410
+ return true;
324
411
  } catch {
325
412
  // error shown via provisioningErrorsByTeam
326
- return null;
413
+ return false;
327
414
  } finally {
328
415
  setIsSubmitting(false);
329
416
  }
330
417
  };
331
418
 
332
419
  const handleCreate = async () => {
333
- const request = await createLocalTeam();
334
- if (!request) return;
335
- setStep('done');
420
+ await createLocalTeam();
336
421
  };
337
422
 
338
423
  // ── Render ───────────────────────────────────────────────────────────
@@ -340,10 +425,7 @@ export const CreateTeamDialog = ({
340
425
  <Dialog
341
426
  open={open}
342
427
  onOpenChange={(next: boolean) => {
343
- if (!next) {
344
- resetState();
345
- onClose();
346
- }
428
+ if (!next) handleClose();
347
429
  }}
348
430
  >
349
431
  <DialogContent className="w-[calc(100vw-2rem)] max-w-2xl sm:w-[40rem]">
@@ -368,7 +450,7 @@ export const CreateTeamDialog = ({
368
450
  <AlertTriangle className="mt-0.5 size-4 shrink-0" />
369
451
  <div className="min-w-0 flex-1 space-y-1">
370
452
  <p className="font-medium">
371
- 该工作目录下已有数字员工"{conflictingTeam.displayName}"正在运行
453
+ 该工作目录下已有数字员工&quot;{conflictingTeam.displayName}&quot;正在运行
372
454
  </p>
373
455
  <p className="opacity-80">在同一目录同时运行两个数字员工存在风险。</p>
374
456
  </div>
@@ -387,28 +469,65 @@ export const CreateTeamDialog = ({
387
469
  {step === 'name' && (
388
470
  <div className="space-y-4 py-2">
389
471
  <div className="space-y-1.5">
390
- <Label htmlFor="team-name">数字员工名称</Label>
472
+ <Label htmlFor="team-name">数字员工名称 *</Label>
391
473
  <Input
392
474
  id="team-name"
475
+ required
393
476
  className={cn(
394
477
  'h-8 text-xs',
395
- fieldErrors.teamName && 'border-[var(--field-error-border)]'
478
+ (fieldErrors.teamName || showDisplayNameTaken) &&
479
+ 'border-[var(--field-error-border)]'
396
480
  )}
397
481
  value={teamName}
398
482
  onChange={(e) => setTeamName(e.target.value)}
399
483
  placeholder="例如:产品助手 / 前端工程师"
400
484
  autoFocus
401
485
  />
402
- {isNameTaken && (
486
+ {isNameProvisioning && (
487
+ <p className="text-[11px]" style={{ color: 'var(--warning-text)' }}>
488
+ 同名数字员工正在启动中
489
+ </p>
490
+ )}
491
+ {showDisplayNameTaken && (
492
+ <p className="text-[11px] text-red-400">该名称已存在,请换一个</p>
493
+ )}
494
+ </div>
495
+
496
+ <div className="space-y-1.5">
497
+ <Label htmlFor="team-bind-project">项目标识 *</Label>
498
+ <Input
499
+ id="team-bind-project"
500
+ required
501
+ className={cn(
502
+ 'h-8 font-mono text-xs',
503
+ (isBindProjectTaken || isBindProjectFormatInvalid) &&
504
+ 'border-[var(--field-error-border)]'
505
+ )}
506
+ value={bindProject}
507
+ onChange={(e) => {
508
+ setManualBindProject(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, ''));
509
+ setBindProjectManuallyEdited(true);
510
+ }}
511
+ placeholder="auto-generated-id"
512
+ />
513
+ {isBindProjectFormatInvalid && (
403
514
  <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
404
- 数字员工名称已存在
515
+ 项目标识只能包含小写英文、数字、连字符和下划线,且必须以字母或数字开头
405
516
  </p>
406
517
  )}
407
518
  {isNameProvisioning && (
408
519
  <p className="text-[11px]" style={{ color: 'var(--warning-text)' }}>
409
- 同名数字员工正在启动中
520
+ 该项目标识正在创建中
410
521
  </p>
411
522
  )}
523
+ {isBindProjectTaken && (
524
+ <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
525
+ 该项目标识已存在
526
+ </p>
527
+ )}
528
+ <p className="text-[11px] text-[var(--color-text-muted)]">
529
+ 用于 URL 路由和 cc-connect 项目绑定,仅限小写英文/数字/连字符
530
+ </p>
412
531
  </div>
413
532
 
414
533
  <div className="space-y-1.5">
@@ -474,8 +593,8 @@ export const CreateTeamDialog = ({
474
593
  onClick={() => selectProviderRef(provider.name)}
475
594
  className={`w-full rounded-lg border px-3 py-2 text-left transition-colors ${
476
595
  checked
477
- ? 'border-indigo-400/60 bg-indigo-500/10'
478
- : 'border-[var(--color-border-subtle)] bg-black/10 hover:border-[var(--color-border)] hover:bg-white/[0.04]'
596
+ ? 'shadow-[var(--color-accent-glow)]/20 border-[var(--color-accent-border)] bg-[var(--color-accent-muted)] shadow-sm'
597
+ : 'border-[var(--color-border-subtle)] bg-black/10 hover:border-[var(--color-border)] hover:bg-[var(--color-accent-soft)]'
479
598
  }`}
480
599
  >
481
600
  <div className="flex items-center justify-between gap-3">
@@ -490,7 +609,7 @@ export const CreateTeamDialog = ({
490
609
  <span
491
610
  className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] ${
492
611
  checked
493
- ? 'bg-indigo-400/20 text-indigo-200'
612
+ ? 'bg-[var(--color-accent-soft)] text-[var(--color-accent)]'
494
613
  : 'bg-white/5 text-[var(--color-text-muted)]'
495
614
  }`}
496
615
  >
@@ -541,7 +660,7 @@ export const CreateTeamDialog = ({
541
660
  {localError}
542
661
  </p>
543
662
  )}
544
- {provisioningErrorsByTeam[sanitizedTeamName] && (
663
+ {provisioningErrorsByTeam[openTeamSlug] && (
545
664
  <p
546
665
  className="mt-1 rounded border p-2 text-xs"
547
666
  style={{
@@ -550,7 +669,7 @@ export const CreateTeamDialog = ({
550
669
  backgroundColor: 'var(--field-error-bg)',
551
670
  }}
552
671
  >
553
- {provisioningErrorsByTeam[sanitizedTeamName]}
672
+ {provisioningErrorsByTeam[openTeamSlug]}
554
673
  </p>
555
674
  )}
556
675
  </div>
@@ -572,7 +691,7 @@ export const CreateTeamDialog = ({
572
691
  <Button
573
692
  size="sm"
574
693
  onClick={() => {
575
- onOpenTeam(sanitizedTeamName, effectiveCwd || undefined, {
694
+ onOpenTeam(openTeamSlug, effectiveCwd || undefined, {
576
695
  displayName: teamName.trim() || undefined,
577
696
  });
578
697
  clearDraft();
@@ -585,10 +704,23 @@ export const CreateTeamDialog = ({
585
704
  </>
586
705
  ) : (
587
706
  <>
588
- <Button variant="outline" size="sm" onClick={onClose}>
707
+ <Button variant="outline" size="sm" onClick={handleClose}>
589
708
  取消
590
709
  </Button>
591
- <Button size="sm" disabled={!sanitizedTeamName || !effectiveCwd || isSubmitting} onClick={handleCreate}>
710
+ <Button
711
+ size="sm"
712
+ disabled={
713
+ !teamName.trim() ||
714
+ !normalizedBindProject ||
715
+ !effectiveCwd ||
716
+ isBindProjectFormatInvalid ||
717
+ isBindProjectTaken ||
718
+ showDisplayNameTaken ||
719
+ isNameProvisioning ||
720
+ isSubmitting
721
+ }
722
+ onClick={handleCreate}
723
+ >
592
724
  {isSubmitting ? '创建中...' : '创建数字员工'}
593
725
  </Button>
594
726
  </>
@@ -1,7 +1,6 @@
1
1
  import { useEffect, useMemo, useRef, useState } from 'react';
2
2
 
3
3
  import { Button } from '@renderer/components/ui/button';
4
- import { Checkbox } from '@renderer/components/ui/checkbox';
5
4
  import {
6
5
  Dialog,
7
6
  DialogContent,
@@ -42,60 +41,20 @@ export const EditTeamDialog = ({
42
41
  }));
43
42
 
44
43
  // ── Derived defaults ─────────────────────────────────────────
45
- const rawSettings = useMemo(
46
- () => (data?.settings ?? {}) as Record<string, unknown>,
47
- [data?.settings]
48
- );
49
-
44
+ // Loop 动态设置(语言/管理来源/飞书权限/消息格式)已统一迁入 RuntimeConfigDialog,
45
+ // 这里只保留团队基础信息:名称、描述、颜色 (#21)
50
46
  const defaults = useMemo(() => {
51
47
  const cfg = data?.config;
52
48
  return {
53
49
  name: cfg?.name ?? '',
54
50
  description: cfg?.description ?? '',
55
51
  color: cfg?.color ?? '',
56
- language:
57
- cfg?.language ?? (typeof rawSettings.language === 'string' ? rawSettings.language : 'zh'),
58
- managedSources:
59
- cfg?.managedSources ??
60
- (typeof rawSettings.admin_from === 'string' ? rawSettings.admin_from : '*'),
61
- platformAllowFrom:
62
- cfg?.platformAllowFrom ??
63
- (typeof rawSettings.platform_allow_from === 'object' &&
64
- rawSettings.platform_allow_from !== null &&
65
- !Array.isArray(rawSettings.platform_allow_from)
66
- ? (rawSettings.platform_allow_from as Record<string, string>)
67
- : {}),
68
- platformAllowChat:
69
- cfg?.platformAllowChat ??
70
- (typeof (rawSettings as Record<string, unknown>).platform_allow_chat === 'object' &&
71
- (rawSettings as Record<string, unknown>).platform_allow_chat !== null &&
72
- !Array.isArray((rawSettings as Record<string, unknown>).platform_allow_chat)
73
- ? ((rawSettings as Record<string, unknown>).platform_allow_chat as Record<string, string>)
74
- : {}),
75
- showContextIndicator:
76
- cfg?.showContextIndicator ??
77
- (typeof rawSettings.show_context_indicator === 'boolean'
78
- ? rawSettings.show_context_indicator
79
- : true),
80
- replyFooter:
81
- cfg?.replyFooter ??
82
- (typeof rawSettings.reply_footer === 'boolean' ? rawSettings.reply_footer : true),
83
- injectSender:
84
- cfg?.injectSender ??
85
- (typeof rawSettings.inject_sender === 'boolean' ? rawSettings.inject_sender : false),
86
52
  };
87
- }, [data, rawSettings]);
53
+ }, [data]);
88
54
 
89
55
  // ── Local form state ─────────────────────────────────────────
90
56
  const [name, setName] = useState(defaults.name);
91
57
  const [description, setDescription] = useState(defaults.description);
92
- const [language, setLanguage] = useState(defaults.language);
93
- const [managedSources, setManagedSources] = useState(defaults.managedSources);
94
- const [feishuAllowFrom, setFeishuAllowFrom] = useState(defaults.platformAllowFrom.feishu ?? '*');
95
- const [feishuAllowChat, setFeishuAllowChat] = useState(defaults.platformAllowChat.feishu ?? '*');
96
- const [showContextIndicator, setShowContextIndicator] = useState(defaults.showContextIndicator);
97
- const [replyFooter, setReplyFooter] = useState(defaults.replyFooter);
98
- const [injectSender, setInjectSender] = useState(defaults.injectSender);
99
58
  const [savePhase, setSavePhase] = useState<'idle' | 'saving' | 'done'>('idle');
100
59
  const [error, setError] = useState<string | null>(null);
101
60
  const saving = savePhase === 'saving';
@@ -115,13 +74,6 @@ export const EditTeamDialog = ({
115
74
  setError(null);
116
75
  setName(d.name);
117
76
  setDescription(d.description);
118
- setLanguage(d.language);
119
- setManagedSources(d.managedSources);
120
- setFeishuAllowFrom(d.platformAllowFrom.feishu ?? '*');
121
- setFeishuAllowChat(d.platformAllowChat.feishu ?? '*');
122
- setShowContextIndicator(d.showContextIndicator);
123
- setReplyFooter(d.replyFooter);
124
- setInjectSender(d.injectSender);
125
77
  }, [open]);
126
78
 
127
79
  const handleSave = (): void => {
@@ -133,22 +85,12 @@ export const EditTeamDialog = ({
133
85
  setSavePhase('saving');
134
86
  setError(null);
135
87
 
136
- const feishu = feishuAllowFrom.trim();
137
- const feishuChat = feishuAllowChat.trim();
138
-
139
88
  void (async () => {
140
89
  try {
141
90
  await api.teams.updateConfig(teamName, {
142
91
  name: name.trim(),
143
92
  description: description.trim(),
144
93
  color: defaultsRef.current.color,
145
- language: language.trim() || undefined,
146
- managedSources: managedSources.trim() || undefined,
147
- platformAllowFrom: feishu ? { feishu } : {},
148
- platformAllowChat: feishuChat ? { feishu: feishuChat } : {},
149
- showContextIndicator,
150
- replyFooter,
151
- injectSender,
152
94
  });
153
95
  await Promise.all([fetchTeams(), selectTeam(teamName)]);
154
96
  setSavePhase('done');
@@ -173,7 +115,7 @@ export const EditTeamDialog = ({
173
115
  <DialogContent className="max-w-lg">
174
116
  <DialogHeader>
175
117
  <DialogTitle>编辑团队</DialogTitle>
176
- <DialogDescription>修改团队信息和消息设置(无需重启)</DialogDescription>
118
+ <DialogDescription>修改团队名称和描述</DialogDescription>
177
119
  </DialogHeader>
178
120
 
179
121
  <div className="space-y-4">
@@ -214,105 +156,15 @@ export const EditTeamDialog = ({
214
156
  />
215
157
  </div>
216
158
 
217
- {/* Messaging settings */}
218
- <div className="rounded-md border border-[var(--color-border)] p-3">
219
- <h3 className="text-xs font-medium text-[var(--color-text)]">消息设置</h3>
220
- <div className="mt-3 space-y-3">
221
- <div className="grid gap-3 md:grid-cols-2">
222
- <div>
223
- <label className={labelCls}>语言</label>
224
- <input
225
- type="text"
226
- value={language}
227
- onChange={(e) => {
228
- setError(null);
229
- setLanguage(e.target.value);
230
- }}
231
- className={inputCls}
232
- placeholder="zh"
233
- />
234
- </div>
235
- <div>
236
- <label className={labelCls}>管理来源</label>
237
- <input
238
- type="text"
239
- value={managedSources}
240
- onChange={(e) => {
241
- setError(null);
242
- setManagedSources(e.target.value);
243
- }}
244
- className={inputCls}
245
- placeholder="user1,user2 或 *"
246
- />
247
- </div>
248
- </div>
249
- <div className="grid gap-3 md:grid-cols-2">
250
- <div>
251
- <label className={labelCls}>飞书私聊权限</label>
252
- <input
253
- type="text"
254
- value={feishuAllowFrom}
255
- onChange={(e) => {
256
- setError(null);
257
- setFeishuAllowFrom(e.target.value);
258
- }}
259
- className={inputCls}
260
- placeholder="ou_xxx 或 *"
261
- />
262
- </div>
263
- <div>
264
- <label className={labelCls}>飞书群聊权限</label>
265
- <input
266
- type="text"
267
- value={feishuAllowChat}
268
- onChange={(e) => {
269
- setError(null);
270
- setFeishuAllowChat(e.target.value);
271
- }}
272
- className={inputCls}
273
- placeholder="oc_xxx 或 *"
274
- />
275
- </div>
276
- </div>
277
- <div className="grid gap-2 md:grid-cols-3">
278
- <label className="flex cursor-pointer items-center gap-2 rounded-md border border-[var(--color-border)] px-2 py-1.5 text-xs text-[var(--color-text-secondary)]">
279
- <Checkbox
280
- checked={showContextIndicator}
281
- onCheckedChange={(c) => {
282
- setError(null);
283
- setShowContextIndicator(c === true);
284
- }}
285
- />
286
- 上下文指示
287
- </label>
288
- <label className="flex cursor-pointer items-center gap-2 rounded-md border border-[var(--color-border)] px-2 py-1.5 text-xs text-[var(--color-text-secondary)]">
289
- <Checkbox
290
- checked={replyFooter}
291
- onCheckedChange={(c) => {
292
- setError(null);
293
- setReplyFooter(c === true);
294
- }}
295
- />
296
- 回复尾部信息
297
- </label>
298
- <label className="flex cursor-pointer items-center gap-2 rounded-md border border-[var(--color-border)] px-2 py-1.5 text-xs text-[var(--color-text-secondary)]">
299
- <Checkbox
300
- checked={injectSender}
301
- onCheckedChange={(c) => {
302
- setError(null);
303
- setInjectSender(c === true);
304
- }}
305
- />
306
- 注入发送者
307
- </label>
308
- </div>
309
- </div>
310
- </div>
311
-
312
159
  {error && <p className="text-xs text-red-400">{error}</p>}
313
160
  </div>
314
161
 
315
162
  <DialogFooter>
163
+ {onDeleteTeam && teamName !== 'default' ? (
164
+ <Button variant="ghost" size="sm" onClick={onDeleteTeam} disabled={saving}>
165
+ 删除项目
166
+ </Button>
167
+ ) : null}
316
168
  <Button variant="outline" size="sm" onClick={onClose} disabled={saving}>
317
169
  {savePhase === 'done' ? '关闭' : '取消'}
318
170
  </Button>