@yancyyu/openhermit 1.6.29 → 1.6.31

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 (157) hide show
  1. package/dist-renderer/assets/{ProjectEditorOverlay-CQm6jUR1.js → ProjectEditorOverlay-DkXfi2pg.js} +1 -1
  2. package/dist-renderer/assets/{TeamGraphOverlay-h0WDfifv.js → TeamGraphOverlay-CHNNVraw.js} +1 -1
  3. package/dist-renderer/assets/{_basePickBy-CgG_tjgX.js → _basePickBy-Do-Ff83V.js} +1 -1
  4. package/dist-renderer/assets/{_baseUniq-DwPTU9lP.js → _baseUniq-nDLhSuJI.js} +1 -1
  5. package/dist-renderer/assets/{arc-7nIrGRzY.js → arc-Bp7fA6sx.js} +1 -1
  6. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-BYhA6Ev2.js → architectureDiagram-VXUJARFQ-CPC1HdGy.js} +1 -1
  7. package/dist-renderer/assets/{blockDiagram-VD42YOAC-BVpZUGDg.js → blockDiagram-VD42YOAC-DTVKyNTO.js} +1 -1
  8. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-DsdreMQ9.js → c4Diagram-YG6GDRKO-XVu-AN00.js} +1 -1
  9. package/dist-renderer/assets/channel-CIwbNcUO.js +1 -0
  10. package/dist-renderer/assets/{chunk-4BX2VUAB-CcoAs7Jd.js → chunk-4BX2VUAB-BcWmVyA-.js} +1 -1
  11. package/dist-renderer/assets/{chunk-55IACEB6-CGGAOoXd.js → chunk-55IACEB6-Co4Z2jsE.js} +1 -1
  12. package/dist-renderer/assets/{chunk-B4BG7PRW-FhpTEPvD.js → chunk-B4BG7PRW-C8q9gfDT.js} +1 -1
  13. package/dist-renderer/assets/{chunk-DI55MBZ5-DoYySbm1.js → chunk-DI55MBZ5-qDgb1gxO.js} +1 -1
  14. package/dist-renderer/assets/{chunk-FMBD7UC4-e9l2tGHG.js → chunk-FMBD7UC4-Cm8Gu2gu.js} +1 -1
  15. package/dist-renderer/assets/{chunk-QN33PNHL-DeiXVTCy.js → chunk-QN33PNHL-DYji1BRS.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QZHKN3VN-DC2UJLJM.js → chunk-QZHKN3VN-DWAS568H.js} +1 -1
  17. package/dist-renderer/assets/{chunk-TZMSLE5B-BHFD9eZI.js → chunk-TZMSLE5B-CLFzXLA8.js} +1 -1
  18. package/dist-renderer/assets/classDiagram-2ON5EDUG-04A-pvql.js +1 -0
  19. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-04A-pvql.js +1 -0
  20. package/dist-renderer/assets/clone-DQnvTIEM.js +1 -0
  21. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-BdybQraU.js → cose-bilkent-S5V4N54A-CZdGhX_3.js} +1 -1
  22. package/dist-renderer/assets/{dagre-6UL2VRFP-DdF3pwM3.js → dagre-6UL2VRFP-BVY-G6nO.js} +1 -1
  23. package/dist-renderer/assets/{diagram-PSM6KHXK-B9Ldd3nh.js → diagram-PSM6KHXK-CUACvAwG.js} +1 -1
  24. package/dist-renderer/assets/{diagram-QEK2KX5R-XEqkrbpu.js → diagram-QEK2KX5R-3SfnesSG.js} +1 -1
  25. package/dist-renderer/assets/{diagram-S2PKOQOG-CipwtY59.js → diagram-S2PKOQOG-E3ksXClJ.js} +1 -1
  26. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-BB-2ISGo.js → erDiagram-Q2GNP2WA-aYjGXss7.js} +1 -1
  27. package/dist-renderer/assets/{flowDiagram-NV44I4VS-B8XmJ0u2.js → flowDiagram-NV44I4VS-JMHrrTQs.js} +1 -1
  28. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-D-8XglBb.js → ganttDiagram-JELNMOA3-CVQ-R5rN.js} +1 -1
  29. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DL4ChakD.js → gitGraphDiagram-V2S2FVAM-OLn9jq61.js} +1 -1
  30. package/dist-renderer/assets/{graph-BiFNoBjP.js → graph-BAb2J0l8.js} +1 -1
  31. package/dist-renderer/assets/{index-qNBNjW4K.js → index-BSoCjBWn.js} +1 -1
  32. package/dist-renderer/assets/{index-6m1ZAymG.js → index-BtG3HbqP.js} +1 -1
  33. package/dist-renderer/assets/{index-BowUl0Jb.js → index-CH8e7g1f.js} +583 -573
  34. package/dist-renderer/assets/index-CSt8DTcn.css +1 -0
  35. package/dist-renderer/assets/{index-Dp3kJTEe.js → index-Ca4iNkRA.js} +1 -1
  36. package/dist-renderer/assets/{index-vAykq1H1.js → index-DU9PGgZJ.js} +1 -1
  37. package/dist-renderer/assets/{index-TOpt_T7A.js → index-DtMzIS9o.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DRIBfHDi.js → infoDiagram-HS3SLOUP-CY_ptQNL.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BOMiigU4.js → journeyDiagram-XKPGCS4Q-C2vuHEo_.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-DDxeyjod.js → kanban-definition-3W4ZIXB7-mbdNfu8h.js} +1 -1
  41. package/dist-renderer/assets/{layout-DNANbrI4.js → layout-Do_ArEB1.js} +1 -1
  42. package/dist-renderer/assets/{linear-DxEJi1yT.js → linear-BMlMKyiq.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-nBfGriW8.js → mindmap-definition-VGOIOE7T-Dfntn-o2.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-Din5j6sV.js → pieDiagram-ADFJNKIX-LiWHsGMV.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-DMVK2BEQ.js → quadrantDiagram-AYHSOK5B-D87St8AF.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-6SC94Gg_.js → requirementDiagram-UZGBJVZJ-DAa6lHBx.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-CD2gghhu.js → sankeyDiagram-TZEHDZUN-VOUngars.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-BnhkN7nZ.js → sequenceDiagram-WL72ISMW-BzwzmFr2.js} +1 -1
  49. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-Bn8XdYX-.js → stateDiagram-FKZM4ZOC-BjAQEJ52.js} +1 -1
  50. package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-1b6sI1_g.js → stateDiagram-v2-4FDKWEC3-BDwy4GJm.js} +1 -1
  51. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-CNs3RPoa.js → timeline-definition-IT6M3QCI-Y5XBZt3W.js} +1 -1
  52. package/dist-renderer/assets/treemap-GDKQZRPO-DzkdUEow.js +162 -0
  53. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-B8o5J2f3.js → xychartDiagram-PRI3JC2R-D-zbvJOv.js} +1 -1
  54. package/dist-renderer/index.html +2 -2
  55. package/package.json +4 -1
  56. package/src/main/ipc/extensions.ts +353 -0
  57. package/src/main/server.ts +209 -6
  58. package/src/main/services/extensions/ExtensionFacadeService.ts +135 -0
  59. package/src/main/services/extensions/catalog/GlamaMcpEnrichmentService.ts +190 -0
  60. package/src/main/services/extensions/catalog/McpCatalogAggregator.ts +150 -0
  61. package/src/main/services/extensions/catalog/OfficialMcpRegistryService.ts +381 -0
  62. package/src/main/services/extensions/catalog/PluginCatalogService.ts +392 -0
  63. package/src/main/services/extensions/credentials/CredentialService.ts +343 -0
  64. package/src/main/services/extensions/install/McpInstallService.ts +407 -0
  65. package/src/main/services/extensions/install/PluginInstallService.ts +198 -0
  66. package/src/main/services/extensions/runtime/ClaudeCodeAdapter.ts +199 -0
  67. package/src/main/services/extensions/runtime/CodexAdapter.ts +100 -0
  68. package/src/main/services/extensions/runtime/CursorAdapter.ts +154 -0
  69. package/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts +172 -0
  70. package/src/main/services/extensions/runtime/GeminiAdapter.ts +91 -0
  71. package/src/main/services/extensions/runtime/HarnessInstallAdapter.ts +49 -0
  72. package/src/main/services/extensions/runtime/McpConfigStateReader.ts +209 -0
  73. package/src/main/services/extensions/runtime/OpenCodeAdapter.ts +91 -0
  74. package/src/main/services/extensions/runtime/adapterRegistry.ts +54 -0
  75. package/src/main/services/extensions/runtime/mcpDiagnosticsParser.ts +214 -0
  76. package/src/main/services/extensions/runtime/mcpRuntimeJson.ts +45 -0
  77. package/src/main/services/extensions/skills/SkillImportService.ts +155 -0
  78. package/src/main/services/extensions/skills/SkillMetadataParser.ts +323 -0
  79. package/src/main/services/extensions/skills/SkillPlanService.ts +411 -0
  80. package/src/main/services/extensions/skills/SkillReviewService.ts +73 -0
  81. package/src/main/services/extensions/skills/SkillRootsResolver.ts +49 -0
  82. package/src/main/services/extensions/skills/SkillScaffoldService.ts +89 -0
  83. package/src/main/services/extensions/skills/SkillScanner.ts +117 -0
  84. package/src/main/services/extensions/skills/SkillValidator.ts +69 -0
  85. package/src/main/services/extensions/skills/SkillsCatalogService.ts +92 -0
  86. package/src/main/services/extensions/skills/SkillsMutationService.ts +146 -0
  87. package/src/main/services/extensions/skills/SkillsWatcherService.ts +134 -0
  88. package/src/main/services/extensions/state/McpInstallationStateService.ts +42 -0
  89. package/src/main/services/extensions/state/PluginInstallationStateService.ts +281 -0
  90. package/src/main/services/identity/AgentTeamsIdentityStore.ts +218 -0
  91. package/src/main/services/runtime/providerAwareCliEnv.ts +60 -0
  92. package/src/main/services/team/ClaudeBinaryResolver.ts +469 -0
  93. package/src/main/services/team/ClaudeDoctorProbe.ts +0 -0
  94. package/src/main/services/team/cliFlavor.ts +54 -0
  95. package/src/main/services/teams-mvp/TaskDispatchService.ts +3 -0
  96. package/src/main/utils/atomicWrite.ts +72 -0
  97. package/src/main/utils/childProcess.ts +554 -0
  98. package/src/main/utils/cliEnv.ts +54 -0
  99. package/src/main/utils/cliPathMerge.ts +97 -0
  100. package/src/main/utils/pathDecoder.ts +664 -0
  101. package/src/main/utils/pathValidation.ts +432 -0
  102. package/src/main/utils/shellEnv.ts +331 -0
  103. package/src/renderer/api/httpClient.ts +61 -0
  104. package/src/renderer/components/extensions/ExtensionStoreView.tsx +63 -35
  105. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
  106. package/src/renderer/components/extensions/common/ExtensionToast.tsx +141 -0
  107. package/src/renderer/components/extensions/common/HarnessSelector.tsx +71 -0
  108. package/src/renderer/components/extensions/env/EnvVarPanel.tsx +335 -0
  109. package/src/renderer/components/extensions/env/ProjectEnvPanel.tsx +239 -0
  110. package/src/renderer/components/extensions/mcp/CustomMcpServerDialog.tsx +14 -223
  111. package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +111 -15
  112. package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +51 -1
  113. package/src/renderer/components/extensions/skills/SkillsPanel.tsx +1 -126
  114. package/src/renderer/components/settings/sections/HarnessSection.tsx +2 -6
  115. package/src/renderer/components/settings/sections/TaskBusSection.tsx +17 -7
  116. package/src/renderer/components/sidebar/SidebarSessions.tsx +23 -0
  117. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +1 -7
  118. package/src/renderer/components/team/HarnessSelect.tsx +71 -0
  119. package/src/renderer/components/team/TeamDetailView.tsx +74 -123
  120. package/src/renderer/components/team/TeamListFilterPopover.tsx +0 -16
  121. package/src/renderer/components/team/TeamListView.tsx +7 -32
  122. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +21 -12
  123. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +287 -418
  124. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +283 -0
  125. package/src/renderer/components/team/kanban/KanbanBoard.tsx +26 -64
  126. package/src/renderer/components/team/messages/MessagesPanel.tsx +28 -24
  127. package/src/renderer/components/terminal/TerminalPanel.tsx +156 -0
  128. package/src/renderer/hooks/useExtensionsTabState.ts +2 -2
  129. package/src/renderer/store/slices/extensionsSlice.ts +42 -107
  130. package/src/renderer/store/slices/teamSlice.ts +8 -2
  131. package/src/renderer/utils/multimodelProviderVisibility.ts +17 -0
  132. package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +29 -9
  133. package/src/shared/types/api.ts +29 -0
  134. package/src/shared/types/extensions/index.ts +1 -0
  135. package/src/shared/types/extensions/mcp.ts +2 -0
  136. package/src/shared/types/extensions/plugin.ts +2 -1
  137. package/src/shared/types/extensions/skill.ts +7 -0
  138. package/src/shared/utils/providerExtensionCapabilities.ts +1 -1
  139. package/dist-renderer/assets/channel-C0SqeFU7.js +0 -1
  140. package/dist-renderer/assets/classDiagram-2ON5EDUG-DWew1HpM.js +0 -1
  141. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-DWew1HpM.js +0 -1
  142. package/dist-renderer/assets/clone-Dm-k63Yr.js +0 -1
  143. package/dist-renderer/assets/index-BhellmRb.css +0 -1
  144. package/dist-renderer/assets/treemap-GDKQZRPO-DU_yr827.js +0 -162
  145. package/src/features/recent-projects/main/adapters/input/http/registerRecentProjectsHttp.ts +0 -30
  146. package/src/features/recent-projects/main/adapters/output/presenters/DashboardRecentProjectsPresenter.ts +0 -27
  147. package/src/features/recent-projects/main/adapters/output/sources/ClaudeRecentProjectsSourceAdapter.ts +0 -91
  148. package/src/features/recent-projects/main/adapters/output/sources/CodexRecentProjectsSourceAdapter.ts +0 -326
  149. package/src/features/recent-projects/main/composition/createRecentProjectsFeature.ts +0 -43
  150. package/src/features/recent-projects/main/index.ts +0 -3
  151. package/src/features/recent-projects/main/infrastructure/cache/InMemoryRecentProjectsCache.ts +0 -34
  152. package/src/features/recent-projects/main/infrastructure/codex/CodexAppServerClient.ts +0 -116
  153. package/src/features/recent-projects/main/infrastructure/identity/RecentProjectIdentityResolver.ts +0 -20
  154. package/src/features/recent-projects/main/infrastructure/identity/normalizeIdentityPath.ts +0 -10
  155. package/src/renderer/components/extensions/apikeys/ApiKeyCard.tsx +0 -143
  156. package/src/renderer/components/extensions/apikeys/ApiKeyFormDialog.tsx +0 -282
  157. package/src/renderer/components/extensions/apikeys/ApiKeysPanel.tsx +0 -280
@@ -22,6 +22,7 @@ import {
22
22
  DialogHeader,
23
23
  DialogTitle,
24
24
  } from '@renderer/components/ui/dialog';
25
+ import { Popover, PopoverContent, PopoverTrigger } from '@renderer/components/ui/popover';
25
26
  import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
26
27
  import { getTeamColorSet, getThemedBadge } from '@renderer/constants/teamColors';
27
28
  import { useTabIdOptional } from '@renderer/contexts/useTabUIContext';
@@ -69,6 +70,8 @@ import {
69
70
  Trash2,
70
71
  Loader2,
71
72
  MessageSquare,
73
+ MoreHorizontal,
74
+ Shield,
72
75
  Users,
73
76
  } from 'lucide-react';
74
77
  import { useShallow } from 'zustand/react/shallow';
@@ -96,6 +99,7 @@ const ProjectEditorOverlay = lazy(() =>
96
99
  import { MemberList } from './members/MemberList';
97
100
  import { MessagesPanel } from './messages/MessagesPanel';
98
101
  import { ChangeReviewDialog } from './review/ChangeReviewDialog';
102
+ import { ProjectEnvPanel } from '../extensions/env/ProjectEnvPanel';
99
103
  import {
100
104
  getTeamPendingRepliesState,
101
105
  setTeamPendingRepliesState,
@@ -880,22 +884,8 @@ export const TeamDetailView = ({
880
884
  const [removeMemberConfirm, setRemoveMemberConfirm] = useState<string | null>(null);
881
885
  const [updatingRoleLoading, setUpdatingRoleLoading] = useState(false);
882
886
  const [editDialogOpen, setEditDialogOpen] = useState(false);
883
- const [savedLaunchRequest, setSavedLaunchRequest] = useState<TeamLaunchRequest | null>(null);
884
- useEffect(() => {
885
- if (!editDialogOpen || !teamName) return;
886
- let cancelled = false;
887
- void (async () => {
888
- try {
889
- const saved = await api.teams.getSavedRequest(teamName);
890
- if (!cancelled) setSavedLaunchRequest(saved ?? null);
891
- } catch {
892
- if (!cancelled) setSavedLaunchRequest(null);
893
- }
894
- })();
895
- return () => {
896
- cancelled = true;
897
- };
898
- }, [editDialogOpen, teamName]);
887
+ const [envDialogOpen, setEnvDialogOpen] = useState(false);
888
+ const [headerMenuOpen, setHeaderMenuOpen] = useState(false);
899
889
  const [launchDialogState, setLaunchDialogState] = useState<{
900
890
  open: boolean;
901
891
  mode: TeamLaunchDialogMode;
@@ -1640,11 +1630,7 @@ export const TeamDetailView = ({
1640
1630
 
1641
1631
  const handleRestartTeamFromEdit = useCallback(async (): Promise<void> => {
1642
1632
  await api.ccSettings.restart();
1643
- // Wait for cc-connect to come back, then refresh
1644
- setTimeout(() => {
1645
- void fetchTeams();
1646
- void selectTeam(teamName);
1647
- }, 3000);
1633
+ await Promise.all([fetchTeams(), selectTeam(teamName)]);
1648
1634
  }, [fetchTeams, selectTeam, teamName]);
1649
1635
 
1650
1636
  const handleSaveAndRestartFromEdit = useCallback(
@@ -2086,24 +2072,6 @@ export const TeamDetailView = ({
2086
2072
  const headerColorSet = data.config.color
2087
2073
  ? getTeamColorSet(data.config.color)
2088
2074
  : nameColorSet(data.config.name);
2089
- const rawTeamSettings = (data.settings ?? {}) as Record<string, unknown>;
2090
- const currentManagedSources =
2091
- data.config.managedSources ??
2092
- (typeof rawTeamSettings.admin_from === 'string' ? rawTeamSettings.admin_from : '*');
2093
- const currentDisabledCommands =
2094
- data.config.disabledCommands ??
2095
- (Array.isArray(rawTeamSettings.disabled_commands)
2096
- ? rawTeamSettings.disabled_commands.filter(
2097
- (entry): entry is string => typeof entry === 'string' && entry.trim().length > 0
2098
- )
2099
- : []);
2100
- const currentPlatformAllowFrom =
2101
- data.config.platformAllowFrom ??
2102
- (typeof rawTeamSettings.platform_allow_from === 'object' &&
2103
- rawTeamSettings.platform_allow_from !== null &&
2104
- !Array.isArray(rawTeamSettings.platform_allow_from)
2105
- ? (rawTeamSettings.platform_allow_from as Record<string, string>)
2106
- : {});
2107
2075
 
2108
2076
  return (
2109
2077
  <>
@@ -2155,37 +2123,55 @@ export const TeamDetailView = ({
2155
2123
  </div>
2156
2124
  </div>
2157
2125
  <div className="flex shrink-0 items-center gap-1.5">
2158
- <Tooltip>
2159
- <TooltipTrigger asChild>
2126
+ <Button
2127
+ variant="outline"
2128
+ size="sm"
2129
+ className="h-7 gap-1.5 px-2.5 text-xs text-[var(--color-text-secondary)]"
2130
+ disabled={isTeamProvisioning}
2131
+ onClick={() => setEditDialogOpen(true)}
2132
+ >
2133
+ <Pencil size={12} />
2134
+ 编辑
2135
+ </Button>
2136
+ <Popover open={headerMenuOpen} onOpenChange={setHeaderMenuOpen}>
2137
+ <PopoverTrigger asChild>
2160
2138
  <Button
2161
2139
  variant="ghost"
2162
2140
  size="sm"
2163
- className="h-7 gap-1 px-2 text-xs text-[var(--color-text-muted)] hover:text-[var(--color-text)]"
2164
- disabled={isTeamProvisioning}
2165
- onClick={() => setEditDialogOpen(true)}
2141
+ className="h-7 w-7 px-0 text-[var(--color-text-muted)]"
2166
2142
  >
2167
- <Pencil size={12} />
2143
+ <MoreHorizontal size={14} />
2168
2144
  </Button>
2169
- </TooltipTrigger>
2170
- <TooltipContent side="bottom">
2171
- {isTeamProvisioning ? '团队仍在编排中,暂时无法编辑' : '编辑团队'}
2172
- </TooltipContent>
2173
- </Tooltip>
2174
- {teamName !== 'default' && teamName !== 'my-project' && (
2175
- <Tooltip>
2176
- <TooltipTrigger asChild>
2177
- <Button
2178
- variant="ghost"
2179
- size="sm"
2180
- className="h-7 gap-1 px-2 text-xs text-red-400 hover:bg-red-500/10 hover:text-red-300"
2181
- onClick={handleDeleteTeam}
2145
+ </PopoverTrigger>
2146
+ <PopoverContent align="end" className="w-44 p-1">
2147
+ {data.config.projectPath && (
2148
+ <button
2149
+ type="button"
2150
+ className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-xs text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-raised)] hover:text-[var(--color-text)]"
2151
+ onClick={() => {
2152
+ setHeaderMenuOpen(false);
2153
+ setEnvDialogOpen(true);
2154
+ }}
2182
2155
  >
2183
- <Trash2 size={12} />
2184
- </Button>
2185
- </TooltipTrigger>
2186
- <TooltipContent side="bottom">删除团队</TooltipContent>
2187
- </Tooltip>
2188
- )}
2156
+ <Shield size={13} />
2157
+ 环境变量
2158
+ </button>
2159
+ )}
2160
+ {teamName !== 'default' && teamName !== 'my-project' && (
2161
+ <button
2162
+ type="button"
2163
+ className="flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-xs text-red-400 hover:bg-red-500/10"
2164
+ onClick={() => {
2165
+ setHeaderMenuOpen(false);
2166
+ handleDeleteTeam();
2167
+ }}
2168
+ >
2169
+ <Trash2 size={13} />
2170
+ 删除团队
2171
+ </button>
2172
+ )}
2173
+ </PopoverContent>
2174
+ </Popover>
2189
2175
  </div>
2190
2176
  </div>
2191
2177
  {data.config.description && (
@@ -2257,10 +2243,6 @@ export const TeamDetailView = ({
2257
2243
  })()}
2258
2244
  </div>
2259
2245
 
2260
- {!data.isAlive && !isTeamProvisioning ? (
2261
- <TeamOfflineStatusBanner teamName={teamName} onLaunch={handleStartCcConnectTeam} />
2262
- ) : null}
2263
-
2264
2246
  <div ref={provisioningBannerRef}>
2265
2247
  <TeamProvisioningBanner teamName={teamName} />
2266
2248
  </div>
@@ -2302,6 +2284,11 @@ export const TeamDetailView = ({
2302
2284
  title="外部派单"
2303
2285
  icon={<Columns3 size={14} />}
2304
2286
  badge={filteredTasks.length}
2287
+ headerExtra={
2288
+ <span className="ml-1.5 rounded bg-amber-500/15 px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-amber-500">
2289
+ Beta
2290
+ </span>
2291
+ }
2305
2292
  defaultOpen
2306
2293
  forceOpen={kanbanSearch.trim().length > 0}
2307
2294
  action={
@@ -2593,61 +2580,17 @@ export const TeamDetailView = ({
2593
2580
  }}
2594
2581
  />
2595
2582
 
2596
- <EditTeamDialog
2597
- open={editDialogOpen}
2598
- teamName={teamName}
2599
- currentName={data.config.name}
2600
- currentDescription={data.config.description ?? ''}
2601
- currentColor={data.config.color ?? ''}
2602
- currentAgentType={data.config.agentType ?? data.harness ?? 'cursor'}
2603
- currentWorkDir={data.workDir ?? data.config.projectPath ?? ''}
2604
- currentPermissionMode={
2605
- data.config.permissionMode ?? data.permissionMode ?? 'default'
2606
- }
2607
- currentLanguage={
2608
- data.config.language ??
2609
- (typeof rawTeamSettings.language === 'string' ? rawTeamSettings.language : 'zh')
2610
- }
2611
- currentShowContextIndicator={
2612
- data.config.showContextIndicator ??
2613
- (typeof rawTeamSettings.show_context_indicator === 'boolean'
2614
- ? rawTeamSettings.show_context_indicator
2615
- : true)
2616
- }
2617
- currentReplyFooter={
2618
- data.config.replyFooter ??
2619
- (typeof rawTeamSettings.reply_footer === 'boolean'
2620
- ? rawTeamSettings.reply_footer
2621
- : true)
2622
- }
2623
- currentInjectSender={
2624
- data.config.injectSender ??
2625
- (typeof rawTeamSettings.inject_sender === 'boolean'
2626
- ? rawTeamSettings.inject_sender
2627
- : false)
2628
- }
2629
- currentManagedSources={currentManagedSources}
2630
- currentDisabledCommands={currentDisabledCommands}
2631
- currentPlatformAllowFrom={currentPlatformAllowFrom}
2632
- currentProviderRefs={data.providerRefs ?? []}
2633
- globalProviders={data.globalProviders ?? []}
2634
- currentMembers={membersWithLiveBranches.filter((m) => !isLeadMember(m))}
2635
- leadMember={membersWithLiveBranches.find((m) => isLeadMember(m)) ?? null}
2636
- resolvedMemberColorMap={resolvedMemberColorMap}
2637
- isTeamAlive={data.isAlive && !isTeamProvisioning}
2638
- isTeamProvisioning={isTeamProvisioning}
2639
- projectPath={data.config.projectPath}
2640
- savedLaunchRequest={savedLaunchRequest}
2641
- onClose={() => setEditDialogOpen(false)}
2642
- onSaved={() => {
2643
- void fetchTeams();
2644
- void selectTeam(teamName);
2645
- }}
2646
- onDeleteTeam={
2647
- teamName !== 'default' && teamName !== 'my-project' ? handleDeleteTeam : undefined
2648
- }
2649
- onRestartTeam={handleRestartTeamFromEdit}
2650
- />
2583
+ <Dialog open={envDialogOpen} onOpenChange={setEnvDialogOpen}>
2584
+ <DialogContent className="max-h-[80vh] max-w-lg overflow-y-auto">
2585
+ <DialogHeader>
2586
+ <DialogTitle>项目环境变量</DialogTitle>
2587
+ <DialogDescription>
2588
+ 管理当前项目所需的环境变量,供 MCP 和 Skills 使用。
2589
+ </DialogDescription>
2590
+ </DialogHeader>
2591
+ <ProjectEnvPanel projectPath={data.config.projectPath ?? null} />
2592
+ </DialogContent>
2593
+ </Dialog>
2651
2594
 
2652
2595
  <Dialog
2653
2596
  open={removeMemberConfirm !== null}
@@ -2828,6 +2771,14 @@ export const TeamDetailView = ({
2828
2771
  {teamAgentRuntimeWatcher}
2829
2772
  {leadContextWatcher}
2830
2773
  {renderBody()}
2774
+ <EditTeamDialog
2775
+ open={editDialogOpen}
2776
+ teamName={teamName}
2777
+ onClose={() => setEditDialogOpen(false)}
2778
+ onDeleteTeam={
2779
+ teamName !== 'default' && teamName !== 'my-project' ? handleDeleteTeam : undefined
2780
+ }
2781
+ />
2831
2782
  </>
2832
2783
  );
2833
2784
  };
@@ -79,10 +79,6 @@ export const TeamListFilterPopover = ({
79
79
  () => teams.filter((t) => aliveSet.has(t.teamName)).length,
80
80
  [teams, aliveSet]
81
81
  );
82
- const offlineCount = useMemo(
83
- () => teams.filter((t) => !aliveSet.has(t.teamName)).length,
84
- [teams, aliveSet]
85
- );
86
82
 
87
83
  return (
88
84
  <Popover>
@@ -125,18 +121,6 @@ export const TeamListFilterPopover = ({
125
121
  <span className="text-[var(--color-text-muted)]">({runningCount})</span>
126
122
  </span>
127
123
  </label>
128
- {/* eslint-disable-next-line jsx-a11y/label-has-associated-control -- Radix Checkbox renders a button, not a native input */}
129
- <label className="flex cursor-pointer items-center gap-2 rounded-md px-1 py-0.5 text-xs text-[var(--color-text-secondary)] hover:bg-[var(--color-surface-raised)]">
130
- <Checkbox
131
- checked={filter.selectedStatuses.has('offline')}
132
- onCheckedChange={() => handleStatusToggle('offline')}
133
- />
134
- <span className="flex items-center gap-1.5">
135
- <span className="size-1.5 rounded-full bg-zinc-500" />
136
- 离线
137
- <span className="text-[var(--color-text-muted)]">({offlineCount})</span>
138
- </span>
139
- </label>
140
124
  </div>
141
125
  </div>
142
126
 
@@ -85,7 +85,7 @@ function generateUniqueName(sourceName: string, existingNames: string[]): string
85
85
  }
86
86
  }
87
87
 
88
- type TeamStatus = 'active' | 'idle' | 'provisioning' | 'offline';
88
+ type TeamStatus = 'active' | 'idle' | 'provisioning';
89
89
 
90
90
  function getRecentProjects(team: TeamSummary): string[] {
91
91
  const history = team.projectPathHistory;
@@ -162,7 +162,7 @@ function renderMemberChips(members: TeamSummaryMember[], isLight: boolean): Reac
162
162
 
163
163
  function renderTeamRecentPaths(
164
164
  team: TeamSummary,
165
- status: TeamStatus,
165
+ status: TeamStatus | null,
166
166
  matchesCurrentProject: boolean,
167
167
  isLight: boolean
168
168
  ): React.JSX.Element | null {
@@ -211,7 +211,7 @@ function resolveTeamStatus(
211
211
  aliveTeams: string[],
212
212
  currentProgress: ReturnType<typeof getCurrentProvisioningProgressForTeam>,
213
213
  leadActivityByTeam: Record<string, string>
214
- ): TeamStatus {
214
+ ): TeamStatus | null {
215
215
  if (aliveTeams.includes(teamName)) {
216
216
  return leadActivityByTeam[teamName] === 'active' ? 'active' : 'idle';
217
217
  }
@@ -223,10 +223,11 @@ function resolveTeamStatus(
223
223
  ) {
224
224
  return 'provisioning';
225
225
  }
226
- return 'offline';
226
+ return null;
227
227
  }
228
228
 
229
- const StatusBadge = ({ status }: { status: TeamStatus }): React.JSX.Element => {
229
+ const StatusBadge = ({ status }: { status: TeamStatus | null }): React.JSX.Element | null => {
230
+ if (!status) return null;
230
231
  switch (status) {
231
232
  case 'active':
232
233
  return (
@@ -249,13 +250,6 @@ const StatusBadge = ({ status }: { status: TeamStatus }): React.JSX.Element => {
249
250
  启动中...
250
251
  </span>
251
252
  );
252
- case 'offline':
253
- return (
254
- <span className="inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full bg-zinc-500/15 px-2 py-0.5 text-[10px] font-medium text-zinc-500">
255
- <span className="size-1.5 rounded-full bg-zinc-500" />
256
- 离线
257
- </span>
258
- );
259
253
  }
260
254
  };
261
255
 
@@ -436,9 +430,8 @@ export const TeamListView = (): React.JSX.Element => {
436
430
  getCurrentProvisioningProgressForTeam(provisioningState, t.teamName),
437
431
  leadActivityByTeam
438
432
  );
439
- const isRunning = status !== 'offline';
433
+ const isRunning = status !== null;
440
434
  if (filter.selectedStatuses.has('running') && isRunning) return true;
441
- if (filter.selectedStatuses.has('offline') && !isRunning) return true;
442
435
  return false;
443
436
  });
444
437
  }
@@ -1154,24 +1147,6 @@ export const TeamListView = (): React.JSX.Element => {
1154
1147
  })()}
1155
1148
  </div>
1156
1149
  <div className="flex shrink-0 gap-1">
1157
- {status === 'offline' && team.projectPath && (
1158
- <Tooltip>
1159
- <TooltipTrigger asChild>
1160
- <button
1161
- type="button"
1162
- className="shrink-0 rounded p-1 text-[var(--color-text-muted)] opacity-0 transition-opacity hover:bg-emerald-500/10 hover:text-emerald-300 disabled:opacity-50 group-hover:opacity-100"
1163
- onClick={(e) => handleLaunchTeam(team.teamName, team.projectPath, e)}
1164
- disabled={launchingTeamName === team.teamName}
1165
- aria-label="启动团队"
1166
- >
1167
- <Play size={14} fill="currentColor" />
1168
- </button>
1169
- </TooltipTrigger>
1170
- <TooltipContent side="bottom">
1171
- {launchingTeamName === team.teamName ? '启动中…' : '启动团队'}
1172
- </TooltipContent>
1173
- </Tooltip>
1174
- )}
1175
1150
  {!team.pendingCreate && (
1176
1151
  <Tooltip>
1177
1152
  <TooltipTrigger asChild>
@@ -44,7 +44,8 @@ import {
44
44
  X,
45
45
  } from 'lucide-react';
46
46
 
47
- import { ALL_AGENT_TYPES, AGENT_TYPE_LABELS } from '../HarnessCards';
47
+ import { AGENT_TYPE_LABELS } from '../HarnessCards';
48
+ import { HarnessSelect } from '../HarnessSelect';
48
49
  import { ProjectPathSelector } from './ProjectPathSelector';
49
50
  import { OptionalSettingsSection } from './OptionalSettingsSection';
50
51
  import { AutoResizeTextarea } from '@renderer/components/ui/auto-resize-textarea';
@@ -52,7 +53,13 @@ import { platformMeta, isQRPlatform } from './platformMeta';
52
53
  import PlatformSetupQR from './PlatformSetupQR';
53
54
  import PlatformManualForm from './PlatformManualForm';
54
55
 
55
- import type { Project, TeamCreateRequest } from '@shared/types';
56
+ import type {
57
+ EffortLevel,
58
+ Project,
59
+ TeamCreateRequest,
60
+ TeamFastMode,
61
+ TeamProviderId,
62
+ } from '@shared/types';
56
63
  import type { CcAgentType } from '@shared/types/ccConnect';
57
64
  import type { GlobalProvider } from '@shared/types/providers';
58
65
 
@@ -69,6 +76,14 @@ export interface TeamCopyData {
69
76
  teamName: string;
70
77
  description?: string;
71
78
  color?: string;
79
+ providerId?: TeamProviderId;
80
+ model?: string;
81
+ effort?: EffortLevel;
82
+ fastMode?: TeamFastMode;
83
+ limitContext?: boolean;
84
+ skipPermissions?: boolean;
85
+ templateSourceId?: string;
86
+ templateDirectoryId?: string;
72
87
  }
73
88
 
74
89
  // ---------------------------------------------------------------------------
@@ -549,18 +564,12 @@ export const CreateTeamDialog = ({
549
564
 
550
565
  <div className="space-y-1.5">
551
566
  <Label htmlFor="team-harness">Agent 类型</Label>
552
- <select
567
+ <HarnessSelect
553
568
  id="team-harness"
554
- className="flex w-full rounded-md border border-[var(--color-border)] bg-transparent px-3 py-2 text-sm"
555
569
  value={selectedHarness}
556
- onChange={(e) => setSelectedHarness(e.target.value as CcAgentType)}
557
- >
558
- {ALL_AGENT_TYPES.map((t) => (
559
- <option key={t} value={t}>
560
- {AGENT_TYPE_LABELS[t]}
561
- </option>
562
- ))}
563
- </select>
570
+ onChange={setSelectedHarness}
571
+ className="w-full"
572
+ />
564
573
  </div>
565
574
 
566
575
  <ProjectPathSelector