@yancyyu/openhermit 1.6.42 → 1.6.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/README.md +98 -89
  2. package/bin/hermit.mjs +96 -0
  3. package/dist-renderer/assets/{ProjectEditorOverlay-DlFQ6mai.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
  4. package/dist-renderer/assets/{TeamGraphOverlay-D2TPMPGR.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
  5. package/dist-renderer/assets/{_basePickBy-Cmd0RHLQ.js → _basePickBy-ZOyLWjMK.js} +1 -1
  6. package/dist-renderer/assets/{_baseUniq-BI_iy8ea.js → _baseUniq-DBb726rt.js} +1 -1
  7. package/dist-renderer/assets/{arc-NzW2mjTP.js → arc-CdiTaR_R.js} +1 -1
  8. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Bzq85AYv.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
  9. package/dist-renderer/assets/{blockDiagram-VD42YOAC-D1PvYS-b.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
  10. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-D49RKzPC.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
  11. package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
  12. package/dist-renderer/assets/{chunk-4BX2VUAB-fmI_MQmQ.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
  13. package/dist-renderer/assets/{chunk-55IACEB6-Xsv9RCXZ.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
  14. package/dist-renderer/assets/{chunk-B4BG7PRW-BE1KO8Um.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
  15. package/dist-renderer/assets/{chunk-DI55MBZ5-tqJ7Mv7f.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
  16. package/dist-renderer/assets/{chunk-FMBD7UC4-DMD45MVJ.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QN33PNHL-DOhGrz-q.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QZHKN3VN-D8yDgJdD.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
  19. package/dist-renderer/assets/{chunk-TZMSLE5B-BcsEDu7A.js → chunk-TZMSLE5B-BQEil57G.js} +1 -1
  20. package/dist-renderer/assets/classDiagram-2ON5EDUG-lpzulY5X.js +1 -0
  21. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-lpzulY5X.js +1 -0
  22. package/dist-renderer/assets/clone-CriGymY9.js +1 -0
  23. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DlSqGHMX.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
  24. package/dist-renderer/assets/{dagre-6UL2VRFP-BTT9tSAx.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
  25. package/dist-renderer/assets/{diagram-PSM6KHXK-Du-U-mK2.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
  26. package/dist-renderer/assets/{diagram-QEK2KX5R-jFdHeKas.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
  27. package/dist-renderer/assets/{diagram-S2PKOQOG-DKLNK2bu.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
  28. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-CZxHgIIo.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
  29. package/dist-renderer/assets/{flowDiagram-NV44I4VS-v4XStCD0.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
  30. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DJjD_BEL.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
  31. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BNy-jr03.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
  32. package/dist-renderer/assets/{graph-DDTrn6je.js → graph-CDP_R8ct.js} +1 -1
  33. package/dist-renderer/assets/{index-BBp78BAu.js → index-BSZdT-g-.js} +1 -1
  34. package/dist-renderer/assets/{index-eotrJaYy.js → index-BhWvMqsz.js} +1 -1
  35. package/dist-renderer/assets/{index-D8_B-cfs.js → index-C2_AupSj.js} +1 -1
  36. package/dist-renderer/assets/{index-BQrwHZ-k.js → index-C5ujiwAR.js} +580 -588
  37. package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
  38. package/dist-renderer/assets/{index-CRKQSG9S.js → index-CVNjLwkq.js} +1 -1
  39. package/dist-renderer/assets/{index-DR6Wz52b.js → index-CwG3se0q.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DqnOsuza.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DTobaO1d.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-HbwVOvWc.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
  43. package/dist-renderer/assets/{layout--VYmTcw2.js → layout-5nA5wUxO.js} +1 -1
  44. package/dist-renderer/assets/{linear-BsJh89Mr.js → linear-BtF1i2qN.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-BZqUZePd.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-B1q_nH6P.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-UD8QhSEu.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BA_i7Nw8.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-CMTnX-2d.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-BQXDB615.js → sequenceDiagram-WL72ISMW-CJg-WYyY.js} +1 -1
  51. package/dist-renderer/assets/{splashScene-D0YB9uxm.js → splashScene-94xWCzLA.js} +1 -1
  52. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BAsPXy6X.js → stateDiagram-FKZM4ZOC-DWHOoFdv.js} +1 -1
  53. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-CGYZOoMb.js +1 -0
  54. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BdasmVkC.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
  55. package/dist-renderer/assets/{treemap-GDKQZRPO-BkKQqIui.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
  56. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-EAlPHOdx.js → xychartDiagram-PRI3JC2R-CCOcGbrD.js} +1 -1
  57. package/dist-renderer/chat-community-qr.jpg +0 -0
  58. package/dist-renderer/fonts/Agave-Bold.ttf +0 -0
  59. package/dist-renderer/fonts/Agave-Regular.ttf +0 -0
  60. package/dist-renderer/icon.png +0 -0
  61. package/dist-renderer/icon.rar +0 -0
  62. package/dist-renderer/index.html +3 -3
  63. package/package.json +21 -26
  64. package/src/features/worker-society/core/application/WorkerSocietyService.test.ts +802 -0
  65. package/src/features/worker-society/core/application/WorkerSocietyService.ts +428 -0
  66. package/src/features/worker-society/core/application/fakes.ts +101 -0
  67. package/src/features/worker-society/core/application/ports.ts +70 -0
  68. package/src/features/worker-society/core/domain/models/society.ts +141 -0
  69. package/src/features/worker-society/core/domain/policies/societyPolicies.test.ts +739 -0
  70. package/src/features/worker-society/core/domain/policies/societyPolicies.ts +496 -0
  71. package/src/features/worker-society/main/adapters/input/societyMcp.test.ts +317 -0
  72. package/src/features/worker-society/main/adapters/input/societyMcp.ts +257 -0
  73. package/src/features/worker-society/main/adapters/input/societyRoutes.test.ts +695 -0
  74. package/src/features/worker-society/main/adapters/input/societyRoutes.ts +194 -0
  75. package/src/features/worker-society/main/composition/societyComposition.test.ts +74 -0
  76. package/src/features/worker-society/main/composition/societyComposition.ts +70 -0
  77. package/src/features/worker-society/main/composition/workerSocietyPlugin.test.ts +69 -0
  78. package/src/features/worker-society/main/composition/workerSocietyPlugin.ts +67 -0
  79. package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.test.ts +132 -0
  80. package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.ts +84 -0
  81. package/src/features/worker-society/main/infrastructure/fsStores.test.ts +216 -0
  82. package/src/features/worker-society/main/infrastructure/fsStores.ts +113 -0
  83. package/src/features/worker-society/main/infrastructure/mergingProfileStore.test.ts +195 -0
  84. package/src/features/worker-society/main/infrastructure/mergingProfileStore.ts +96 -0
  85. package/src/features/worker-society/renderer/SocietyGraph.tsx +166 -0
  86. package/src/features/worker-society/renderer/SocietyNodeLabels.tsx +139 -0
  87. package/src/features/worker-society/renderer/SocietyNodeOverlay.tsx +339 -0
  88. package/src/features/worker-society/renderer/SocietyView.tsx +437 -0
  89. package/src/features/worker-society/renderer/index.ts +11 -0
  90. package/src/features/worker-society/renderer/societyApi.test.ts +259 -0
  91. package/src/features/worker-society/renderer/societyApi.ts +144 -0
  92. package/src/features/worker-society/renderer/societyGraphAdapter.test.ts +321 -0
  93. package/src/features/worker-society/renderer/societyGraphAdapter.ts +240 -0
  94. package/src/features/worker-society/renderer/societyOverlayActions.test.ts +57 -0
  95. package/src/features/worker-society/renderer/societyOverlayActions.ts +49 -0
  96. package/src/features/worker-society/renderer/societyStore.test.ts +218 -0
  97. package/src/features/worker-society/renderer/societyStore.ts +146 -0
  98. package/src/features/worker-society/renderer/societyViewUtils.test.ts +81 -0
  99. package/src/features/worker-society/renderer/societyViewUtils.ts +68 -0
  100. package/src/main/ipc/extensions.ts +27 -0
  101. package/src/main/server.ts +1709 -534
  102. package/src/main/services/ccConnect/CcConnectBridge.ts +26 -11
  103. package/src/main/services/ccConnect/CcConnectClient.ts +9 -2
  104. package/src/main/services/ccConnect/workDirReconcile.test.ts +57 -0
  105. package/src/main/services/ccConnect/workDirReconcile.ts +36 -0
  106. package/src/main/services/direct-cli/DirectCliSessionManager.test.ts +397 -0
  107. package/src/main/services/direct-cli/DirectCliSessionManager.ts +508 -0
  108. package/src/main/services/direct-cli/DirectCliSessionStore.test.ts +79 -0
  109. package/src/main/services/direct-cli/DirectCliSessionStore.ts +97 -0
  110. package/src/main/services/direct-cli/__tests__/directCliMessageId.test.ts +40 -0
  111. package/src/main/services/direct-cli/directCliMessageId.ts +21 -0
  112. package/src/main/services/direct-cli/index.ts +17 -0
  113. package/src/main/services/extensions/capability-packs/CapabilityPackLoaderService.ts +637 -0
  114. package/src/main/services/extensions/catalog/PluginCatalogService.ts +2 -2
  115. package/src/main/services/loop-assets/LoopAssetsScannerService.ts +657 -0
  116. package/src/main/services/runtime/providerAwareCliEnv.ts +33 -5
  117. package/src/main/services/session-intelligence/LocalSessionScanner.ts +156 -71
  118. package/src/main/services/session-intelligence/SessionUsageParser.ts +103 -8
  119. package/src/main/services/session-intelligence/UsageTelemetryService.ts +11 -0
  120. package/src/main/services/session-intelligence/__tests__/teamSessionListMapper.test.ts +104 -0
  121. package/src/main/services/session-intelligence/teamSessionListMapper.ts +78 -0
  122. package/src/main/services/system-manager/AdminLoopInitializer.ts +95 -0
  123. package/src/main/services/system-manager/BuiltinWorkflowSeeder.ts +679 -74
  124. package/src/main/services/system-manager/SystemManagerConfigService.ts +19 -1
  125. package/src/main/services/system-manager/WorkflowPromptService.ts +58 -5
  126. package/src/main/services/system-manager/__tests__/AdminLoopInitializer.test.ts +129 -0
  127. package/src/main/services/system-manager/__tests__/SystemManagerConfigService.test.ts +60 -0
  128. package/src/main/services/teams-mvp/CollaborationBoardService.ts +2 -0
  129. package/src/main/services/teams-mvp/OpsRunbookContext.ts +60 -0
  130. package/src/main/services/teams-mvp/TaskDispatchService.test.ts +305 -0
  131. package/src/main/services/teams-mvp/TaskDispatchService.ts +250 -131
  132. package/src/main/services/teams-mvp/TeamProvisioningService.ts +12 -2
  133. package/src/main/services/teams-mvp/TeamWorkspaceService.test.ts +207 -0
  134. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +104 -51
  135. package/src/main/services/teams-mvp/index.ts +6 -0
  136. package/src/main/utils/externalPlatformSessionRouting.ts +92 -0
  137. package/src/main/utils/toolApprovalRules.ts +151 -0
  138. package/src/renderer/App.tsx +24 -89
  139. package/src/renderer/api/httpClient.ts +115 -37
  140. package/src/renderer/api/providers.ts +5 -16
  141. package/src/renderer/components/chat/CommunityChatView.tsx +81 -0
  142. package/src/renderer/components/dashboard/DashboardView.tsx +130 -84
  143. package/src/renderer/components/extensions/ExtensionStoreView.tsx +39 -5
  144. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +2 -1
  145. package/src/renderer/components/extensions/capability-packs/CapabilityPacksPanel.tsx +170 -0
  146. package/src/renderer/components/layout/PaneContent.tsx +10 -2
  147. package/src/renderer/components/layout/SortableTab.tsx +4 -0
  148. package/src/renderer/components/layout/TabBarActions.tsx +13 -16
  149. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +4 -135
  150. package/src/renderer/components/schedules/SchedulesView.tsx +22 -14
  151. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +7 -6
  152. package/src/renderer/components/settings/SettingsTabs.tsx +24 -21
  153. package/src/renderer/components/settings/SettingsView.tsx +22 -13
  154. package/src/renderer/components/settings/components/SettingRow.tsx +13 -5
  155. package/src/renderer/components/settings/components/SettingsSectionCard.tsx +53 -0
  156. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +10 -6
  157. package/src/renderer/components/settings/components/SettingsSelect.tsx +12 -9
  158. package/src/renderer/components/settings/components/SettingsToggle.tsx +6 -5
  159. package/src/renderer/components/settings/components/index.ts +1 -0
  160. package/src/renderer/components/settings/sections/AdvancedSection.tsx +78 -59
  161. package/src/renderer/components/settings/sections/CliStatusSection.tsx +32 -44
  162. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  163. package/src/renderer/components/settings/sections/GeneralSection.tsx +216 -186
  164. package/src/renderer/components/settings/sections/PlatformsSection.tsx +25 -17
  165. package/src/renderer/components/settings/sections/TaskBusSection.tsx +63 -22
  166. package/src/renderer/components/sidebar/SidebarSessions.tsx +120 -80
  167. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +1 -1
  168. package/src/renderer/components/splash/splashScene.ts +6 -2
  169. package/src/renderer/components/system-manager/SystemManagerView.tsx +169 -255
  170. package/src/renderer/components/tasks/TasksView.tsx +63 -37
  171. package/src/renderer/components/team/CcSessionsSection.tsx +124 -89
  172. package/src/renderer/components/team/HarnessBrandLogos.tsx +318 -0
  173. package/src/renderer/components/team/HarnessSelect.tsx +25 -26
  174. package/src/renderer/components/team/TeamDetailView.tsx +137 -153
  175. package/src/renderer/components/team/TeamEmptyState.tsx +9 -37
  176. package/src/renderer/components/team/TeamListView.tsx +143 -30
  177. package/src/renderer/components/team/__tests__/CcSessionsSection.hasLocalFile.test.tsx +128 -0
  178. package/src/renderer/components/team/activity/ActivityItem.tsx +21 -9
  179. package/src/renderer/components/team/activity/ActivityTimeline.tsx +2 -2
  180. package/src/renderer/components/team/dialogs/AdvancedCliSection.tsx +1 -1
  181. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +13 -10
  182. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +156 -83
  183. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +9 -157
  184. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +19 -15
  185. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +48 -10
  186. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +11 -12
  187. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +39 -37
  188. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +434 -64
  189. package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +12 -10
  190. package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +2 -2
  191. package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.bindProject.test.tsx +399 -0
  192. package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.chineseRepro.test.tsx +253 -0
  193. package/src/renderer/components/team/dialogs/platformAllowUtils.ts +91 -0
  194. package/src/renderer/components/team/dialogs/teammateRuntimeCompatibility.tsx +1 -1
  195. package/src/renderer/components/team/kanban/KanbanTaskCard.test.tsx +41 -0
  196. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +41 -86
  197. package/src/renderer/components/team/loop-console/LoopCommandComposer.tsx +310 -0
  198. package/src/renderer/components/team/loop-console/LoopConsolePanel.tsx +372 -0
  199. package/src/renderer/components/team/loop-console/loopSendIntent.test.ts +85 -0
  200. package/src/renderer/components/team/loop-console/loopSendIntent.ts +221 -0
  201. package/src/renderer/components/team/loop-console/useLeadSessionToolActivity.ts +74 -0
  202. package/src/renderer/components/team/loop-console/useLoopCommandSuggestions.ts +165 -0
  203. package/src/renderer/components/team/loop-console/useLoopConsoleController.ts +266 -0
  204. package/src/renderer/components/team/members/LeadModelRow.test.tsx +1 -1
  205. package/src/renderer/components/team/members/LeadModelRow.tsx +5 -3
  206. package/src/renderer/components/team/members/MemberDetailDialog.tsx +11 -0
  207. package/src/renderer/components/team/members/MemberDetailStats.tsx +13 -3
  208. package/src/renderer/components/team/members/MemberDraftRow.test.tsx +1 -1
  209. package/src/renderer/components/team/members/MemberDraftRow.tsx +1 -1
  210. package/src/renderer/components/team/members/MemberMessagesTab.tsx +2 -2
  211. package/src/renderer/components/team/members/MemberStatsTab.tsx +1 -1
  212. package/src/renderer/components/team/messages/MessageComposer.tsx +150 -44
  213. package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +2 -2
  214. package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -28
  215. package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +6 -6
  216. package/src/renderer/components/team/taskLogs/ExactTaskLogCard.tsx +2 -2
  217. package/src/renderer/components/team/taskLogs/TaskLogStreamSection.tsx +1 -1
  218. package/src/renderer/components/terminal/TerminalPanel.tsx +2 -3
  219. package/src/renderer/components/ui/MentionableTextarea.tsx +5 -1
  220. package/src/renderer/constants/teamColors.ts +5 -5
  221. package/src/renderer/hooks/useExtensionsTabState.ts +1 -1
  222. package/src/renderer/hooks/useMentionDetection.ts +5 -1
  223. package/src/renderer/hooks/useProjectWorkflowCommands.ts +57 -0
  224. package/src/renderer/hooks/useTeamSuggestions.ts +2 -0
  225. package/src/renderer/index.css +19 -2
  226. package/src/renderer/main.tsx +7 -1
  227. package/src/renderer/store/index.ts +18 -1
  228. package/src/renderer/store/slices/extensionsSlice.ts +83 -0
  229. package/src/renderer/store/slices/tabSlice.ts +61 -0
  230. package/src/renderer/store/slices/teamSlice.ts +138 -9
  231. package/src/renderer/types/mention.ts +8 -0
  232. package/src/renderer/types/tabs.ts +3 -1
  233. package/src/renderer/utils/__tests__/bindProjectSlug.test.ts +69 -0
  234. package/src/renderer/utils/__tests__/groupTransformer.test.ts +148 -0
  235. package/src/renderer/utils/__tests__/initialRoute.test.ts +101 -0
  236. package/src/renderer/utils/__tests__/leadToolActivity.test.ts +124 -0
  237. package/src/renderer/utils/__tests__/mergeTeamMessages.test.ts +81 -0
  238. package/src/renderer/utils/__tests__/teamMessageFiltering.test.ts +213 -0
  239. package/src/renderer/utils/__tests__/teamMessageKey.test.ts +75 -0
  240. package/src/renderer/utils/__tests__/workflowCommandExecution.test.ts +173 -0
  241. package/src/renderer/utils/__tests__/workflowCommandSuggestions.test.ts +59 -0
  242. package/src/renderer/utils/bindProjectSlug.ts +57 -0
  243. package/src/renderer/utils/capabilityCommandExecution.ts +113 -0
  244. package/src/renderer/utils/initialRoute.ts +89 -0
  245. package/src/renderer/utils/leadToolActivity.ts +117 -0
  246. package/src/renderer/utils/loopShortcutSuggestions.ts +106 -0
  247. package/src/renderer/utils/mentionSuggestions.ts +1 -1
  248. package/src/renderer/utils/slashCommandRegistry.ts +231 -0
  249. package/src/renderer/utils/teamMentionDirective.ts +31 -0
  250. package/src/renderer/utils/workflowCommandExecution.ts +96 -0
  251. package/src/renderer/utils/workflowCommandSuggestions.ts +49 -0
  252. package/src/shared/types/api.ts +79 -4
  253. package/src/shared/types/ccConnect.ts +1 -0
  254. package/src/shared/types/extensions/api.ts +19 -0
  255. package/src/shared/types/extensions/capabilityPack.ts +118 -0
  256. package/src/shared/types/extensions/index.ts +29 -1
  257. package/src/shared/types/index.ts +6 -0
  258. package/src/shared/types/loopAssets.ts +54 -0
  259. package/src/shared/types/providers.ts +0 -16
  260. package/src/shared/types/systemManager.ts +26 -1
  261. package/src/shared/types/team.ts +41 -5
  262. package/src/shared/types/terminal.ts +2 -36
  263. package/src/shared/types/worker.test.ts +28 -0
  264. package/src/shared/types/worker.ts +3 -0
  265. package/src/shared/utils/__tests__/effortLevels.test.ts +88 -0
  266. package/src/shared/utils/__tests__/providerBackend.test.ts +88 -0
  267. package/src/shared/utils/__tests__/providerLaunchArgs.test.ts +220 -0
  268. package/src/shared/utils/claudeStreamJson.test.ts +187 -0
  269. package/src/shared/utils/claudeStreamJson.ts +153 -0
  270. package/src/shared/utils/providerLaunchArgs.ts +217 -0
  271. package/src/shared/utils/slashCommands.ts +10 -0
  272. package/src/types/node-pty.d.ts +8 -0
  273. package/dist-renderer/assets/channel-Ch7JrfUu.js +0 -1
  274. package/dist-renderer/assets/classDiagram-2ON5EDUG-z9I4AnFy.js +0 -1
  275. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-z9I4AnFy.js +0 -1
  276. package/dist-renderer/assets/clone-Dfi1Jx6l.js +0 -1
  277. package/dist-renderer/assets/index-iyjkpSus.css +0 -32
  278. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DTUIBfce.js +0 -1
  279. package/src/main/services/system-manager/SystemManagerPtyService.ts +0 -233
  280. package/src/renderer/components/common/TerminalPane.tsx +0 -213
  281. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +0 -292
@@ -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,45 +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
- }
78
-
79
- /**
80
- * Generate a unique ASCII project identifier from a display name.
81
- * For Chinese names: produces "team-xxxx" (4-char random suffix).
82
- * For ASCII names: produces a slugified version.
83
- */
84
- function generateBindProject(displayName: string): string {
85
- const trimmed = displayName.trim();
86
- if (!trimmed) return '';
87
- // Try to extract ASCII parts from the name
88
- const asciiParts = trimmed
89
- .toLowerCase()
90
- .normalize('NFKD')
91
- .replace(/[̀-ͯ]/g, '')
92
- .replace(/[^a-z0-9]+/g, '-')
93
- .replace(/-+/g, '-')
94
- .replace(/^-|-$/g, '');
95
- const base = asciiParts || 'team';
96
- const suffix = Math.random().toString(36).slice(2, 6);
97
- return `${base}-${suffix}`;
98
- }
99
-
100
- /** Validate bindProject: ASCII lowercase alphanumeric, hyphens, underscores. */
101
- function isValidBindProject(value: string): boolean {
102
- return /^[a-z0-9][a-z0-9_-]{1,}$/.test(value);
103
- }
66
+ // bindProject slug rules live in @renderer/utils/bindProjectSlug (unit-tested).
104
67
 
105
68
  // ---------------------------------------------------------------------------
106
69
  // Wizard step types
@@ -119,6 +82,7 @@ interface CreateTeamDialogProps {
119
82
  clearProvisioningError?: (teamName?: string) => void;
120
83
  existingTeamNames: string[];
121
84
  existingBindProjects?: string[];
85
+ existingDisplayNames?: string[];
122
86
  provisioningTeamNames?: string[];
123
87
  activeTeams?: ActiveTeamRef[];
124
88
  initialData?: unknown;
@@ -135,6 +99,7 @@ export const CreateTeamDialog = ({
135
99
  clearProvisioningError,
136
100
  existingTeamNames,
137
101
  existingBindProjects = [],
102
+ existingDisplayNames = [],
138
103
  provisioningTeamNames = [],
139
104
  activeTeams,
140
105
  defaultProjectPath,
@@ -166,16 +131,13 @@ export const CreateTeamDialog = ({
166
131
  const [description, setDescription] = useState('');
167
132
 
168
133
  // ── bindProject (ASCII unique identifier) ────────────────────────────
169
- const [bindProject, setBindProject] = useState('');
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('');
170
139
  const [bindProjectManuallyEdited, setBindProjectManuallyEdited] = useState(false);
171
140
 
172
- // Auto-generate bindProject from displayName when not manually edited
173
- useEffect(() => {
174
- if (bindProjectManuallyEdited) return;
175
- const auto = generateBindProject(teamName);
176
- setBindProject(auto);
177
- }, [teamName, bindProjectManuallyEdited]);
178
-
179
141
  // ── Projects (for path selector) ─────────────────────────────────────
180
142
  const [projects, setProjects] = useState<Project[]>([]);
181
143
  const [projectsLoading, setProjectsLoading] = useState(false);
@@ -189,10 +151,63 @@ export const CreateTeamDialog = ({
189
151
  const [localError, setLocalError] = useState<string | null>(null);
190
152
  const [isSubmitting, setIsSubmitting] = useState(false);
191
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);
192
161
 
193
162
  // ── Name conflict detection ──────────────────────────────────────────
194
- const isBindProjectTaken = existingBindProjects.includes(bindProject);
195
- const isNameProvisioning = provisioningTeamNames.includes(bindProject) && !isBindProjectTaken;
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]
177
+ );
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;
207
+ const isNameProvisioning =
208
+ provisioningTeamNameSet.has(normalizedBindProject) && !isBindProjectTaken;
209
+ const isBindProjectFormatInvalid =
210
+ Boolean(bindProject) && !isValidBindProject(normalizedBindProject);
196
211
 
197
212
  const effectiveCwd =
198
213
  cwdMode === 'project'
@@ -305,15 +320,24 @@ export const CreateTeamDialog = ({
305
320
  setIsSubmitting(false);
306
321
  setConflictDismissed(false);
307
322
  setSelectedProviderRef(null);
308
- setBindProject('');
323
+ setManualBindProject('');
309
324
  setBindProjectManuallyEdited(false);
325
+ setCreatedTeamName(null);
310
326
  setStep('name');
311
327
  };
312
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
+
313
337
  const buildCreateRequest = (): TeamCreateRequest => ({
314
- teamName: bindProject,
315
- bindProject,
316
- displayName: teamName.trim() || undefined,
338
+ teamName: normalizedBindProject,
339
+ bindProject: normalizedBindProject,
340
+ displayName: teamName.trim(),
317
341
  description: description.trim() || undefined,
318
342
  color: teamColor || undefined,
319
343
  members: [],
@@ -330,16 +354,26 @@ export const CreateTeamDialog = ({
330
354
  setLocalError('请输入数字员工名称');
331
355
  return false;
332
356
  }
333
- if (!bindProject) {
357
+ if (isDisplayNameTaken) {
358
+ setLocalError('该名称已存在,请换一个');
359
+ return false;
360
+ }
361
+ if (!normalizedBindProject) {
334
362
  setLocalError('请输入项目标识');
335
363
  return false;
336
364
  }
337
- if (!isValidBindProject(bindProject)) {
338
- setLocalError('项目标识只能包含小写英文字母、数字、连字符和下划线(至少2个字符,以字母或数字开头)');
365
+ if (!isValidBindProject(normalizedBindProject)) {
366
+ setLocalError(
367
+ '项目标识为必填,只能包含小写英文字母、数字、连字符和下划线,且必须以字母或数字开头'
368
+ );
369
+ return false;
370
+ }
371
+ if (isNameProvisioning) {
372
+ setLocalError('数字员工正在启动中');
339
373
  return false;
340
374
  }
341
375
  if (isBindProjectTaken) {
342
- setLocalError(isNameProvisioning ? '数字员工正在启动中' : `项目标识"${bindProject}"已存在,请换一个`);
376
+ setLocalError(`项目标识"${normalizedBindProject}"已存在,请换一个`);
343
377
  return false;
344
378
  }
345
379
  if (!effectiveCwd) {
@@ -349,8 +383,8 @@ export const CreateTeamDialog = ({
349
383
  return true;
350
384
  };
351
385
 
352
- const createLocalTeam = async (): Promise<TeamCreateRequest | null> => {
353
- if (!validateCreateFields()) return null;
386
+ const createLocalTeam = async (): Promise<boolean> => {
387
+ if (!validateCreateFields()) return false;
354
388
 
355
389
  setFieldErrors({});
356
390
  setLocalError(null);
@@ -359,19 +393,31 @@ export const CreateTeamDialog = ({
359
393
  try {
360
394
  const request = buildCreateRequest();
361
395
  await onCreate(request);
362
- 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;
363
411
  } catch {
364
412
  // error shown via provisioningErrorsByTeam
365
- return null;
413
+ return false;
366
414
  } finally {
367
415
  setIsSubmitting(false);
368
416
  }
369
417
  };
370
418
 
371
419
  const handleCreate = async () => {
372
- const request = await createLocalTeam();
373
- if (!request) return;
374
- setStep('done');
420
+ await createLocalTeam();
375
421
  };
376
422
 
377
423
  // ── Render ───────────────────────────────────────────────────────────
@@ -379,10 +425,7 @@ export const CreateTeamDialog = ({
379
425
  <Dialog
380
426
  open={open}
381
427
  onOpenChange={(next: boolean) => {
382
- if (!next) {
383
- resetState();
384
- onClose();
385
- }
428
+ if (!next) handleClose();
386
429
  }}
387
430
  >
388
431
  <DialogContent className="w-[calc(100vw-2rem)] max-w-2xl sm:w-[40rem]">
@@ -407,7 +450,7 @@ export const CreateTeamDialog = ({
407
450
  <AlertTriangle className="mt-0.5 size-4 shrink-0" />
408
451
  <div className="min-w-0 flex-1 space-y-1">
409
452
  <p className="font-medium">
410
- 该工作目录下已有数字员工"{conflictingTeam.displayName}"正在运行
453
+ 该工作目录下已有数字员工&quot;{conflictingTeam.displayName}&quot;正在运行
411
454
  </p>
412
455
  <p className="opacity-80">在同一目录同时运行两个数字员工存在风险。</p>
413
456
  </div>
@@ -426,12 +469,14 @@ export const CreateTeamDialog = ({
426
469
  {step === 'name' && (
427
470
  <div className="space-y-4 py-2">
428
471
  <div className="space-y-1.5">
429
- <Label htmlFor="team-name">数字员工名称</Label>
472
+ <Label htmlFor="team-name">数字员工名称 *</Label>
430
473
  <Input
431
474
  id="team-name"
475
+ required
432
476
  className={cn(
433
477
  'h-8 text-xs',
434
- fieldErrors.teamName && 'border-[var(--field-error-border)]'
478
+ (fieldErrors.teamName || showDisplayNameTaken) &&
479
+ 'border-[var(--field-error-border)]'
435
480
  )}
436
481
  value={teamName}
437
482
  onChange={(e) => setTeamName(e.target.value)}
@@ -443,23 +488,38 @@ export const CreateTeamDialog = ({
443
488
  同名数字员工正在启动中
444
489
  </p>
445
490
  )}
491
+ {showDisplayNameTaken && (
492
+ <p className="text-[11px] text-red-400">该名称已存在,请换一个</p>
493
+ )}
446
494
  </div>
447
495
 
448
496
  <div className="space-y-1.5">
449
- <Label htmlFor="team-bind-project">项目标识</Label>
497
+ <Label htmlFor="team-bind-project">项目标识 *</Label>
450
498
  <Input
451
499
  id="team-bind-project"
500
+ required
452
501
  className={cn(
453
- 'h-8 text-xs font-mono',
454
- isBindProjectTaken && 'border-[var(--field-error-border)]'
502
+ 'h-8 font-mono text-xs',
503
+ (isBindProjectTaken || isBindProjectFormatInvalid) &&
504
+ 'border-[var(--field-error-border)]'
455
505
  )}
456
506
  value={bindProject}
457
507
  onChange={(e) => {
458
- setBindProject(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, ''));
508
+ setManualBindProject(e.target.value.toLowerCase().replace(/[^a-z0-9_-]/g, ''));
459
509
  setBindProjectManuallyEdited(true);
460
510
  }}
461
511
  placeholder="auto-generated-id"
462
512
  />
513
+ {isBindProjectFormatInvalid && (
514
+ <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
515
+ 项目标识只能包含小写英文、数字、连字符和下划线,且必须以字母或数字开头
516
+ </p>
517
+ )}
518
+ {isNameProvisioning && (
519
+ <p className="text-[11px]" style={{ color: 'var(--warning-text)' }}>
520
+ 该项目标识正在创建中
521
+ </p>
522
+ )}
463
523
  {isBindProjectTaken && (
464
524
  <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
465
525
  该项目标识已存在
@@ -533,8 +593,8 @@ export const CreateTeamDialog = ({
533
593
  onClick={() => selectProviderRef(provider.name)}
534
594
  className={`w-full rounded-lg border px-3 py-2 text-left transition-colors ${
535
595
  checked
536
- ? 'border-indigo-400/60 bg-indigo-500/10'
537
- : '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)]'
538
598
  }`}
539
599
  >
540
600
  <div className="flex items-center justify-between gap-3">
@@ -549,7 +609,7 @@ export const CreateTeamDialog = ({
549
609
  <span
550
610
  className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] ${
551
611
  checked
552
- ? 'bg-indigo-400/20 text-indigo-200'
612
+ ? 'bg-[var(--color-accent-soft)] text-[var(--color-accent)]'
553
613
  : 'bg-white/5 text-[var(--color-text-muted)]'
554
614
  }`}
555
615
  >
@@ -600,7 +660,7 @@ export const CreateTeamDialog = ({
600
660
  {localError}
601
661
  </p>
602
662
  )}
603
- {provisioningErrorsByTeam[bindProject] && (
663
+ {provisioningErrorsByTeam[openTeamSlug] && (
604
664
  <p
605
665
  className="mt-1 rounded border p-2 text-xs"
606
666
  style={{
@@ -609,7 +669,7 @@ export const CreateTeamDialog = ({
609
669
  backgroundColor: 'var(--field-error-bg)',
610
670
  }}
611
671
  >
612
- {provisioningErrorsByTeam[bindProject]}
672
+ {provisioningErrorsByTeam[openTeamSlug]}
613
673
  </p>
614
674
  )}
615
675
  </div>
@@ -631,7 +691,7 @@ export const CreateTeamDialog = ({
631
691
  <Button
632
692
  size="sm"
633
693
  onClick={() => {
634
- onOpenTeam(bindProject, effectiveCwd || undefined, {
694
+ onOpenTeam(openTeamSlug, effectiveCwd || undefined, {
635
695
  displayName: teamName.trim() || undefined,
636
696
  });
637
697
  clearDraft();
@@ -644,10 +704,23 @@ export const CreateTeamDialog = ({
644
704
  </>
645
705
  ) : (
646
706
  <>
647
- <Button variant="outline" size="sm" onClick={onClose}>
707
+ <Button variant="outline" size="sm" onClick={handleClose}>
648
708
  取消
649
709
  </Button>
650
- <Button size="sm" disabled={!teamName.trim() || !bindProject || !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
+ >
651
724
  {isSubmitting ? '创建中...' : '创建数字员工'}
652
725
  </Button>
653
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>