@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.
- package/README.md +98 -89
- package/bin/hermit.mjs +96 -0
- package/dist-renderer/assets/{ProjectEditorOverlay-DlFQ6mai.js → ProjectEditorOverlay-C98qSs7-.js} +1 -1
- package/dist-renderer/assets/{TeamGraphOverlay-D2TPMPGR.js → TeamGraphOverlay-CsBbZwcL.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-Cmd0RHLQ.js → _basePickBy-ZOyLWjMK.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-BI_iy8ea.js → _baseUniq-DBb726rt.js} +1 -1
- package/dist-renderer/assets/{arc-NzW2mjTP.js → arc-CdiTaR_R.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Bzq85AYv.js → architectureDiagram-VXUJARFQ-Cz3sc5TH.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-D1PvYS-b.js → blockDiagram-VD42YOAC-DE4c-KJ3.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-D49RKzPC.js → c4Diagram-YG6GDRKO-CmTMDTrV.js} +1 -1
- package/dist-renderer/assets/channel-KTpqi9eT.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-fmI_MQmQ.js → chunk-4BX2VUAB-rhHy3tFl.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-Xsv9RCXZ.js → chunk-55IACEB6-fLZBzuo_.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-BE1KO8Um.js → chunk-B4BG7PRW-DOzxQhim.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-tqJ7Mv7f.js → chunk-DI55MBZ5-COQCcXC5.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-DMD45MVJ.js → chunk-FMBD7UC4-IKU9U_Y4.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-DOhGrz-q.js → chunk-QN33PNHL-D6WV154X.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-D8yDgJdD.js → chunk-QZHKN3VN-D90_2DQp.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-BcsEDu7A.js → chunk-TZMSLE5B-BQEil57G.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-lpzulY5X.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-lpzulY5X.js +1 -0
- package/dist-renderer/assets/clone-CriGymY9.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DlSqGHMX.js → cose-bilkent-S5V4N54A-6WiK6U2P.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-BTT9tSAx.js → dagre-6UL2VRFP-DF4MMuTn.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-Du-U-mK2.js → diagram-PSM6KHXK-CcF1eZ7E.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-jFdHeKas.js → diagram-QEK2KX5R-DYlOVPQB.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-DKLNK2bu.js → diagram-S2PKOQOG-BHXWsZOP.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-CZxHgIIo.js → erDiagram-Q2GNP2WA-GjmuBx8d.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-v4XStCD0.js → flowDiagram-NV44I4VS-BuS7YVHk.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DJjD_BEL.js → ganttDiagram-JELNMOA3-3Teu5tAa.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BNy-jr03.js → gitGraphDiagram-V2S2FVAM-BiLdCYu5.js} +1 -1
- package/dist-renderer/assets/{graph-DDTrn6je.js → graph-CDP_R8ct.js} +1 -1
- package/dist-renderer/assets/{index-BBp78BAu.js → index-BSZdT-g-.js} +1 -1
- package/dist-renderer/assets/{index-eotrJaYy.js → index-BhWvMqsz.js} +1 -1
- package/dist-renderer/assets/{index-D8_B-cfs.js → index-C2_AupSj.js} +1 -1
- package/dist-renderer/assets/{index-BQrwHZ-k.js → index-C5ujiwAR.js} +580 -588
- package/dist-renderer/assets/index-CIS2CTK9.css +1 -0
- package/dist-renderer/assets/{index-CRKQSG9S.js → index-CVNjLwkq.js} +1 -1
- package/dist-renderer/assets/{index-DR6Wz52b.js → index-CwG3se0q.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DqnOsuza.js → infoDiagram-HS3SLOUP-DLHUFo72.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DTobaO1d.js → journeyDiagram-XKPGCS4Q-BE07RpJD.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-HbwVOvWc.js → kanban-definition-3W4ZIXB7-DDHZy4NB.js} +1 -1
- package/dist-renderer/assets/{layout--VYmTcw2.js → layout-5nA5wUxO.js} +1 -1
- package/dist-renderer/assets/{linear-BsJh89Mr.js → linear-BtF1i2qN.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-BZqUZePd.js → mindmap-definition-VGOIOE7T-Z1Ui9Sqy.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-B1q_nH6P.js → pieDiagram-ADFJNKIX-LCjxckWv.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-UD8QhSEu.js → quadrantDiagram-AYHSOK5B-BOwKjSco.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-BA_i7Nw8.js → requirementDiagram-UZGBJVZJ-pChP8Znd.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-CMTnX-2d.js → sankeyDiagram-TZEHDZUN-DifZ2qpo.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-BQXDB615.js → sequenceDiagram-WL72ISMW-CJg-WYyY.js} +1 -1
- package/dist-renderer/assets/{splashScene-D0YB9uxm.js → splashScene-94xWCzLA.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BAsPXy6X.js → stateDiagram-FKZM4ZOC-DWHOoFdv.js} +1 -1
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-CGYZOoMb.js +1 -0
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BdasmVkC.js → timeline-definition-IT6M3QCI-CPgokIo8.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-BkKQqIui.js → treemap-GDKQZRPO-DAVqSR9L.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-EAlPHOdx.js → xychartDiagram-PRI3JC2R-CCOcGbrD.js} +1 -1
- package/dist-renderer/chat-community-qr.jpg +0 -0
- package/dist-renderer/fonts/Agave-Bold.ttf +0 -0
- package/dist-renderer/fonts/Agave-Regular.ttf +0 -0
- package/dist-renderer/icon.png +0 -0
- package/dist-renderer/icon.rar +0 -0
- package/dist-renderer/index.html +3 -3
- package/package.json +21 -26
- package/src/features/worker-society/core/application/WorkerSocietyService.test.ts +802 -0
- package/src/features/worker-society/core/application/WorkerSocietyService.ts +428 -0
- package/src/features/worker-society/core/application/fakes.ts +101 -0
- package/src/features/worker-society/core/application/ports.ts +70 -0
- package/src/features/worker-society/core/domain/models/society.ts +141 -0
- package/src/features/worker-society/core/domain/policies/societyPolicies.test.ts +739 -0
- package/src/features/worker-society/core/domain/policies/societyPolicies.ts +496 -0
- package/src/features/worker-society/main/adapters/input/societyMcp.test.ts +317 -0
- package/src/features/worker-society/main/adapters/input/societyMcp.ts +257 -0
- package/src/features/worker-society/main/adapters/input/societyRoutes.test.ts +695 -0
- package/src/features/worker-society/main/adapters/input/societyRoutes.ts +194 -0
- package/src/features/worker-society/main/composition/societyComposition.test.ts +74 -0
- package/src/features/worker-society/main/composition/societyComposition.ts +70 -0
- package/src/features/worker-society/main/composition/workerSocietyPlugin.test.ts +69 -0
- package/src/features/worker-society/main/composition/workerSocietyPlugin.ts +67 -0
- package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.test.ts +132 -0
- package/src/features/worker-society/main/infrastructure/crossTeamMessageGateway.ts +84 -0
- package/src/features/worker-society/main/infrastructure/fsStores.test.ts +216 -0
- package/src/features/worker-society/main/infrastructure/fsStores.ts +113 -0
- package/src/features/worker-society/main/infrastructure/mergingProfileStore.test.ts +195 -0
- package/src/features/worker-society/main/infrastructure/mergingProfileStore.ts +96 -0
- package/src/features/worker-society/renderer/SocietyGraph.tsx +166 -0
- package/src/features/worker-society/renderer/SocietyNodeLabels.tsx +139 -0
- package/src/features/worker-society/renderer/SocietyNodeOverlay.tsx +339 -0
- package/src/features/worker-society/renderer/SocietyView.tsx +437 -0
- package/src/features/worker-society/renderer/index.ts +11 -0
- package/src/features/worker-society/renderer/societyApi.test.ts +259 -0
- package/src/features/worker-society/renderer/societyApi.ts +144 -0
- package/src/features/worker-society/renderer/societyGraphAdapter.test.ts +321 -0
- package/src/features/worker-society/renderer/societyGraphAdapter.ts +240 -0
- package/src/features/worker-society/renderer/societyOverlayActions.test.ts +57 -0
- package/src/features/worker-society/renderer/societyOverlayActions.ts +49 -0
- package/src/features/worker-society/renderer/societyStore.test.ts +218 -0
- package/src/features/worker-society/renderer/societyStore.ts +146 -0
- package/src/features/worker-society/renderer/societyViewUtils.test.ts +81 -0
- package/src/features/worker-society/renderer/societyViewUtils.ts +68 -0
- package/src/main/ipc/extensions.ts +27 -0
- package/src/main/server.ts +1709 -534
- package/src/main/services/ccConnect/CcConnectBridge.ts +26 -11
- package/src/main/services/ccConnect/CcConnectClient.ts +9 -2
- package/src/main/services/ccConnect/workDirReconcile.test.ts +57 -0
- package/src/main/services/ccConnect/workDirReconcile.ts +36 -0
- package/src/main/services/direct-cli/DirectCliSessionManager.test.ts +397 -0
- package/src/main/services/direct-cli/DirectCliSessionManager.ts +508 -0
- package/src/main/services/direct-cli/DirectCliSessionStore.test.ts +79 -0
- package/src/main/services/direct-cli/DirectCliSessionStore.ts +97 -0
- package/src/main/services/direct-cli/__tests__/directCliMessageId.test.ts +40 -0
- package/src/main/services/direct-cli/directCliMessageId.ts +21 -0
- package/src/main/services/direct-cli/index.ts +17 -0
- package/src/main/services/extensions/capability-packs/CapabilityPackLoaderService.ts +637 -0
- package/src/main/services/extensions/catalog/PluginCatalogService.ts +2 -2
- package/src/main/services/loop-assets/LoopAssetsScannerService.ts +657 -0
- package/src/main/services/runtime/providerAwareCliEnv.ts +33 -5
- package/src/main/services/session-intelligence/LocalSessionScanner.ts +156 -71
- package/src/main/services/session-intelligence/SessionUsageParser.ts +103 -8
- package/src/main/services/session-intelligence/UsageTelemetryService.ts +11 -0
- package/src/main/services/session-intelligence/__tests__/teamSessionListMapper.test.ts +104 -0
- package/src/main/services/session-intelligence/teamSessionListMapper.ts +78 -0
- package/src/main/services/system-manager/AdminLoopInitializer.ts +95 -0
- package/src/main/services/system-manager/BuiltinWorkflowSeeder.ts +679 -74
- package/src/main/services/system-manager/SystemManagerConfigService.ts +19 -1
- package/src/main/services/system-manager/WorkflowPromptService.ts +58 -5
- package/src/main/services/system-manager/__tests__/AdminLoopInitializer.test.ts +129 -0
- package/src/main/services/system-manager/__tests__/SystemManagerConfigService.test.ts +60 -0
- package/src/main/services/teams-mvp/CollaborationBoardService.ts +2 -0
- package/src/main/services/teams-mvp/OpsRunbookContext.ts +60 -0
- package/src/main/services/teams-mvp/TaskDispatchService.test.ts +305 -0
- package/src/main/services/teams-mvp/TaskDispatchService.ts +250 -131
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +12 -2
- package/src/main/services/teams-mvp/TeamWorkspaceService.test.ts +207 -0
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +104 -51
- package/src/main/services/teams-mvp/index.ts +6 -0
- package/src/main/utils/externalPlatformSessionRouting.ts +92 -0
- package/src/main/utils/toolApprovalRules.ts +151 -0
- package/src/renderer/App.tsx +24 -89
- package/src/renderer/api/httpClient.ts +115 -37
- package/src/renderer/api/providers.ts +5 -16
- package/src/renderer/components/chat/CommunityChatView.tsx +81 -0
- package/src/renderer/components/dashboard/DashboardView.tsx +130 -84
- package/src/renderer/components/extensions/ExtensionStoreView.tsx +39 -5
- package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +2 -1
- package/src/renderer/components/extensions/capability-packs/CapabilityPacksPanel.tsx +170 -0
- package/src/renderer/components/layout/PaneContent.tsx +10 -2
- package/src/renderer/components/layout/SortableTab.tsx +4 -0
- package/src/renderer/components/layout/TabBarActions.tsx +13 -16
- package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +4 -135
- package/src/renderer/components/schedules/SchedulesView.tsx +22 -14
- package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +7 -6
- package/src/renderer/components/settings/SettingsTabs.tsx +24 -21
- package/src/renderer/components/settings/SettingsView.tsx +22 -13
- package/src/renderer/components/settings/components/SettingRow.tsx +13 -5
- package/src/renderer/components/settings/components/SettingsSectionCard.tsx +53 -0
- package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +10 -6
- package/src/renderer/components/settings/components/SettingsSelect.tsx +12 -9
- package/src/renderer/components/settings/components/SettingsToggle.tsx +6 -5
- package/src/renderer/components/settings/components/index.ts +1 -0
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +78 -59
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +32 -44
- package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
- package/src/renderer/components/settings/sections/GeneralSection.tsx +216 -186
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +25 -17
- package/src/renderer/components/settings/sections/TaskBusSection.tsx +63 -22
- package/src/renderer/components/sidebar/SidebarSessions.tsx +120 -80
- package/src/renderer/components/sidebar/SidebarTaskItem.tsx +1 -1
- package/src/renderer/components/splash/splashScene.ts +6 -2
- package/src/renderer/components/system-manager/SystemManagerView.tsx +169 -255
- package/src/renderer/components/tasks/TasksView.tsx +63 -37
- package/src/renderer/components/team/CcSessionsSection.tsx +124 -89
- package/src/renderer/components/team/HarnessBrandLogos.tsx +318 -0
- package/src/renderer/components/team/HarnessSelect.tsx +25 -26
- package/src/renderer/components/team/TeamDetailView.tsx +137 -153
- package/src/renderer/components/team/TeamEmptyState.tsx +9 -37
- package/src/renderer/components/team/TeamListView.tsx +143 -30
- package/src/renderer/components/team/__tests__/CcSessionsSection.hasLocalFile.test.tsx +128 -0
- package/src/renderer/components/team/activity/ActivityItem.tsx +21 -9
- package/src/renderer/components/team/activity/ActivityTimeline.tsx +2 -2
- package/src/renderer/components/team/dialogs/AdvancedCliSection.tsx +1 -1
- package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +13 -10
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +156 -83
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +9 -157
- package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +19 -15
- package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +48 -10
- package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +11 -12
- package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +39 -37
- package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +434 -64
- package/src/renderer/components/team/dialogs/SendMessageDialog.tsx +12 -10
- package/src/renderer/components/team/dialogs/TaskDetailDialog.tsx +2 -2
- package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.bindProject.test.tsx +399 -0
- package/src/renderer/components/team/dialogs/__tests__/CreateTeamDialog.chineseRepro.test.tsx +253 -0
- package/src/renderer/components/team/dialogs/platformAllowUtils.ts +91 -0
- package/src/renderer/components/team/dialogs/teammateRuntimeCompatibility.tsx +1 -1
- package/src/renderer/components/team/kanban/KanbanTaskCard.test.tsx +41 -0
- package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +41 -86
- package/src/renderer/components/team/loop-console/LoopCommandComposer.tsx +310 -0
- package/src/renderer/components/team/loop-console/LoopConsolePanel.tsx +372 -0
- package/src/renderer/components/team/loop-console/loopSendIntent.test.ts +85 -0
- package/src/renderer/components/team/loop-console/loopSendIntent.ts +221 -0
- package/src/renderer/components/team/loop-console/useLeadSessionToolActivity.ts +74 -0
- package/src/renderer/components/team/loop-console/useLoopCommandSuggestions.ts +165 -0
- package/src/renderer/components/team/loop-console/useLoopConsoleController.ts +266 -0
- package/src/renderer/components/team/members/LeadModelRow.test.tsx +1 -1
- package/src/renderer/components/team/members/LeadModelRow.tsx +5 -3
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +11 -0
- package/src/renderer/components/team/members/MemberDetailStats.tsx +13 -3
- package/src/renderer/components/team/members/MemberDraftRow.test.tsx +1 -1
- package/src/renderer/components/team/members/MemberDraftRow.tsx +1 -1
- package/src/renderer/components/team/members/MemberMessagesTab.tsx +2 -2
- package/src/renderer/components/team/members/MemberStatsTab.tsx +1 -1
- package/src/renderer/components/team/messages/MessageComposer.tsx +150 -44
- package/src/renderer/components/team/messages/MessagesFilterPopover.tsx +2 -2
- package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -28
- package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +6 -6
- package/src/renderer/components/team/taskLogs/ExactTaskLogCard.tsx +2 -2
- package/src/renderer/components/team/taskLogs/TaskLogStreamSection.tsx +1 -1
- package/src/renderer/components/terminal/TerminalPanel.tsx +2 -3
- package/src/renderer/components/ui/MentionableTextarea.tsx +5 -1
- package/src/renderer/constants/teamColors.ts +5 -5
- package/src/renderer/hooks/useExtensionsTabState.ts +1 -1
- package/src/renderer/hooks/useMentionDetection.ts +5 -1
- package/src/renderer/hooks/useProjectWorkflowCommands.ts +57 -0
- package/src/renderer/hooks/useTeamSuggestions.ts +2 -0
- package/src/renderer/index.css +19 -2
- package/src/renderer/main.tsx +7 -1
- package/src/renderer/store/index.ts +18 -1
- package/src/renderer/store/slices/extensionsSlice.ts +83 -0
- package/src/renderer/store/slices/tabSlice.ts +61 -0
- package/src/renderer/store/slices/teamSlice.ts +138 -9
- package/src/renderer/types/mention.ts +8 -0
- package/src/renderer/types/tabs.ts +3 -1
- package/src/renderer/utils/__tests__/bindProjectSlug.test.ts +69 -0
- package/src/renderer/utils/__tests__/groupTransformer.test.ts +148 -0
- package/src/renderer/utils/__tests__/initialRoute.test.ts +101 -0
- package/src/renderer/utils/__tests__/leadToolActivity.test.ts +124 -0
- package/src/renderer/utils/__tests__/mergeTeamMessages.test.ts +81 -0
- package/src/renderer/utils/__tests__/teamMessageFiltering.test.ts +213 -0
- package/src/renderer/utils/__tests__/teamMessageKey.test.ts +75 -0
- package/src/renderer/utils/__tests__/workflowCommandExecution.test.ts +173 -0
- package/src/renderer/utils/__tests__/workflowCommandSuggestions.test.ts +59 -0
- package/src/renderer/utils/bindProjectSlug.ts +57 -0
- package/src/renderer/utils/capabilityCommandExecution.ts +113 -0
- package/src/renderer/utils/initialRoute.ts +89 -0
- package/src/renderer/utils/leadToolActivity.ts +117 -0
- package/src/renderer/utils/loopShortcutSuggestions.ts +106 -0
- package/src/renderer/utils/mentionSuggestions.ts +1 -1
- package/src/renderer/utils/slashCommandRegistry.ts +231 -0
- package/src/renderer/utils/teamMentionDirective.ts +31 -0
- package/src/renderer/utils/workflowCommandExecution.ts +96 -0
- package/src/renderer/utils/workflowCommandSuggestions.ts +49 -0
- package/src/shared/types/api.ts +79 -4
- package/src/shared/types/ccConnect.ts +1 -0
- package/src/shared/types/extensions/api.ts +19 -0
- package/src/shared/types/extensions/capabilityPack.ts +118 -0
- package/src/shared/types/extensions/index.ts +29 -1
- package/src/shared/types/index.ts +6 -0
- package/src/shared/types/loopAssets.ts +54 -0
- package/src/shared/types/providers.ts +0 -16
- package/src/shared/types/systemManager.ts +26 -1
- package/src/shared/types/team.ts +41 -5
- package/src/shared/types/terminal.ts +2 -36
- package/src/shared/types/worker.test.ts +28 -0
- package/src/shared/types/worker.ts +3 -0
- package/src/shared/utils/__tests__/effortLevels.test.ts +88 -0
- package/src/shared/utils/__tests__/providerBackend.test.ts +88 -0
- package/src/shared/utils/__tests__/providerLaunchArgs.test.ts +220 -0
- package/src/shared/utils/claudeStreamJson.test.ts +187 -0
- package/src/shared/utils/claudeStreamJson.ts +153 -0
- package/src/shared/utils/providerLaunchArgs.ts +217 -0
- package/src/shared/utils/slashCommands.ts +10 -0
- package/src/types/node-pty.d.ts +8 -0
- package/dist-renderer/assets/channel-Ch7JrfUu.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-z9I4AnFy.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-z9I4AnFy.js +0 -1
- package/dist-renderer/assets/clone-Dfi1Jx6l.js +0 -1
- package/dist-renderer/assets/index-iyjkpSus.css +0 -32
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DTUIBfce.js +0 -1
- package/src/main/services/system-manager/SystemManagerPtyService.ts +0 -233
- package/src/renderer/components/common/TerminalPane.tsx +0 -213
- 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
|
-
|
|
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
|
|
195
|
-
|
|
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
|
-
|
|
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:
|
|
315
|
-
bindProject,
|
|
316
|
-
displayName: teamName.trim()
|
|
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 (
|
|
357
|
+
if (isDisplayNameTaken) {
|
|
358
|
+
setLocalError('该名称已存在,请换一个');
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
if (!normalizedBindProject) {
|
|
334
362
|
setLocalError('请输入项目标识');
|
|
335
363
|
return false;
|
|
336
364
|
}
|
|
337
|
-
if (!isValidBindProject(
|
|
338
|
-
setLocalError(
|
|
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(
|
|
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<
|
|
353
|
-
if (!validateCreateFields()) return
|
|
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
|
-
|
|
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
|
|
413
|
+
return false;
|
|
366
414
|
} finally {
|
|
367
415
|
setIsSubmitting(false);
|
|
368
416
|
}
|
|
369
417
|
};
|
|
370
418
|
|
|
371
419
|
const handleCreate = async () => {
|
|
372
|
-
|
|
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
|
-
|
|
453
|
+
该工作目录下已有数字员工"{conflictingTeam.displayName}"正在运行
|
|
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"
|
|
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
|
|
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"
|
|
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
|
|
454
|
-
isBindProjectTaken
|
|
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
|
-
|
|
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
|
-
? '
|
|
537
|
-
: 'border-[var(--color-border-subtle)] bg-black/10 hover:border-[var(--color-border)] hover:bg-
|
|
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-
|
|
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[
|
|
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[
|
|
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(
|
|
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={
|
|
707
|
+
<Button variant="outline" size="sm" onClick={handleClose}>
|
|
648
708
|
取消
|
|
649
709
|
</Button>
|
|
650
|
-
<Button
|
|
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
|
-
|
|
46
|
-
|
|
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
|
|
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
|
|
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>
|