@yancyyu/openhermit 1.5.8 → 1.5.10

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 (107) hide show
  1. package/README.md +10 -1
  2. package/bin/alias-loader.mjs +51 -0
  3. package/bin/hermit.mjs +14 -5
  4. package/dist-renderer/assets/{ProjectEditorOverlay-BNoDw9T1.js → ProjectEditorOverlay-C5D83Zxv.js} +1 -1
  5. package/dist-renderer/assets/{TeamGraphOverlay-CfGRKQIu.js → TeamGraphOverlay-ajzuM1-u.js} +1 -1
  6. package/dist-renderer/assets/{_basePickBy-Ct8Hm5_h.js → _basePickBy-C9H2zmVj.js} +1 -1
  7. package/dist-renderer/assets/{_baseUniq-BofrAFBx.js → _baseUniq-CpGZGemc.js} +1 -1
  8. package/dist-renderer/assets/{arc-AbJgatzR.js → arc-CbGBDw-m.js} +1 -1
  9. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-gpniCJVk.js → architectureDiagram-VXUJARFQ-nuKXUIpb.js} +1 -1
  10. package/dist-renderer/assets/{blockDiagram-VD42YOAC-aBbbmONC.js → blockDiagram-VD42YOAC-DHUUE7Jc.js} +1 -1
  11. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-DJio1IsU.js → c4Diagram-YG6GDRKO-OILHhqLM.js} +1 -1
  12. package/dist-renderer/assets/channel-DpUKLLrj.js +1 -0
  13. package/dist-renderer/assets/{chunk-4BX2VUAB-D1_HKao2.js → chunk-4BX2VUAB-dqNpZaQ8.js} +1 -1
  14. package/dist-renderer/assets/{chunk-55IACEB6-NAmVxF4k.js → chunk-55IACEB6-BCoSJQM-.js} +1 -1
  15. package/dist-renderer/assets/{chunk-B4BG7PRW-Ce829laz.js → chunk-B4BG7PRW-BLbg8yVR.js} +1 -1
  16. package/dist-renderer/assets/{chunk-DI55MBZ5-Ct2Le12y.js → chunk-DI55MBZ5-CUUWOs1Q.js} +1 -1
  17. package/dist-renderer/assets/{chunk-FMBD7UC4-Cie3DzKk.js → chunk-FMBD7UC4-D9geTN5P.js} +1 -1
  18. package/dist-renderer/assets/{chunk-QN33PNHL-4f5Yb50e.js → chunk-QN33PNHL-BGT8-BRX.js} +1 -1
  19. package/dist-renderer/assets/{chunk-QZHKN3VN-D9ranl9c.js → chunk-QZHKN3VN-CC8ebGaM.js} +1 -1
  20. package/dist-renderer/assets/{chunk-TZMSLE5B-bdGZWlEy.js → chunk-TZMSLE5B-CajekcT6.js} +1 -1
  21. package/dist-renderer/assets/classDiagram-2ON5EDUG-LL85aSlz.js +1 -0
  22. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-LL85aSlz.js +1 -0
  23. package/dist-renderer/assets/clone-BHWsFzFA.js +1 -0
  24. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-C6tvfcVi.js → cose-bilkent-S5V4N54A-C_x7hSy3.js} +1 -1
  25. package/dist-renderer/assets/{dagre-6UL2VRFP-B-4qcZam.js → dagre-6UL2VRFP-C4Y1k4DZ.js} +1 -1
  26. package/dist-renderer/assets/{diagram-PSM6KHXK-CwT3TLjx.js → diagram-PSM6KHXK-oRIeULoh.js} +1 -1
  27. package/dist-renderer/assets/{diagram-QEK2KX5R-BWH6-ZFd.js → diagram-QEK2KX5R-DwSqw5HF.js} +1 -1
  28. package/dist-renderer/assets/{diagram-S2PKOQOG-DfpPnfi1.js → diagram-S2PKOQOG-DqjGYje2.js} +1 -1
  29. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-BFbEFR4x.js → erDiagram-Q2GNP2WA-CEV5bBgg.js} +1 -1
  30. package/dist-renderer/assets/{flowDiagram-NV44I4VS-Dg3cf5hW.js → flowDiagram-NV44I4VS-BQQkrRyu.js} +1 -1
  31. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-B21y55W5.js → ganttDiagram-JELNMOA3-CLy4WR1G.js} +1 -1
  32. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BDV3BJzn.js → gitGraphDiagram-V2S2FVAM-6W3ioQu_.js} +1 -1
  33. package/dist-renderer/assets/{graph-BfaZ4hZt.js → graph-BnLKQvhH.js} +1 -1
  34. package/dist-renderer/assets/{index-CCqtDawH.js → index-B4aiRxoU.js} +1 -1
  35. package/dist-renderer/assets/{index-pMg_LlsS.js → index-B8lKqPVq.js} +1 -1
  36. package/dist-renderer/assets/{index-CZltVMDP.js → index-BRuhNKyU.js} +12 -12
  37. package/dist-renderer/assets/{index-BMXHMpkG.js → index-BufvLVIl.js} +1 -1
  38. package/dist-renderer/assets/{index-Ct0-y9TF.js → index-C1xShqKH.js} +1 -1
  39. package/dist-renderer/assets/{index-CVMSpK8C.js → index-zIOLLI7O.js} +1 -1
  40. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DvMlS0CL.js → infoDiagram-HS3SLOUP-BoBweEEY.js} +1 -1
  41. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DIyMluRv.js → journeyDiagram-XKPGCS4Q-DLL0V5oP.js} +1 -1
  42. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-CVOx8f-7.js → kanban-definition-3W4ZIXB7-HsFtEDG3.js} +1 -1
  43. package/dist-renderer/assets/{layout-BPKIXUf4.js → layout-ClIooAAq.js} +1 -1
  44. package/dist-renderer/assets/{linear-CScZGLr2.js → linear-r3RJcj8y.js} +1 -1
  45. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-CmDQ7Wo6.js → mindmap-definition-VGOIOE7T-BA_P1U4V.js} +1 -1
  46. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-DbVClin-.js → pieDiagram-ADFJNKIX-CzPAfkTB.js} +1 -1
  47. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CAB0MYcW.js → quadrantDiagram-AYHSOK5B-PvdPWzFJ.js} +1 -1
  48. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-w2Lfpg3T.js → requirementDiagram-UZGBJVZJ-CHqIL_Od.js} +1 -1
  49. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-kvG1QoKY.js → sankeyDiagram-TZEHDZUN-ConzpACM.js} +1 -1
  50. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-DCVBQ23J.js → sequenceDiagram-WL72ISMW-Zryq4oxP.js} +1 -1
  51. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-ItZ0JBvq.js → stateDiagram-FKZM4ZOC-BA9V7NHF.js} +1 -1
  52. package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-Hpmw4dMm.js → stateDiagram-v2-4FDKWEC3-CGnaujD-.js} +1 -1
  53. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BzSFaAjV.js → timeline-definition-IT6M3QCI-DPs2ZjMm.js} +1 -1
  54. package/dist-renderer/assets/{treemap-GDKQZRPO-fSz4hQn0.js → treemap-GDKQZRPO-B0lzrLxb.js} +1 -1
  55. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-CT1kaGlv.js → xychartDiagram-PRI3JC2R-CINGmMxX.js} +1 -1
  56. package/dist-renderer/index.html +1 -1
  57. package/package.json +2 -1
  58. package/src/main/server.ts +993 -764
  59. package/src/main/services/UpdateService.ts +4 -1
  60. package/src/main/services/ccConnect/CcConnectBridge.ts +1 -8
  61. package/src/main/services/ccConnect/CcConnectClient.ts +7 -2
  62. package/src/main/services/teams-mvp/TeamProvisioningService.ts +14 -4
  63. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +11 -6
  64. package/src/renderer/App.tsx +18 -7
  65. package/src/renderer/api/httpClient.ts +136 -42
  66. package/src/renderer/components/chat/ChatHistory.tsx +11 -8
  67. package/src/renderer/components/dashboard/DashboardView.tsx +4 -2
  68. package/src/renderer/components/extensions/ExtensionStoreView.tsx +2 -7
  69. package/src/renderer/components/layout/Sidebar.tsx +3 -1
  70. package/src/renderer/components/schedules/SchedulesView.tsx +15 -13
  71. package/src/renderer/components/settings/SettingsTabs.tsx +2 -1
  72. package/src/renderer/components/settings/hooks/useSettingsHandlers.ts +4 -5
  73. package/src/renderer/components/settings/sections/AdvancedSection.tsx +19 -4
  74. package/src/renderer/components/settings/sections/CliStatusSection.tsx +63 -59
  75. package/src/renderer/components/settings/sections/GeneralSection.tsx +5 -11
  76. package/src/renderer/components/settings/sections/HarnessSection.tsx +30 -15
  77. package/src/renderer/components/settings/sections/PlatformsSection.tsx +110 -51
  78. package/src/renderer/components/sidebar/SidebarSessions.tsx +100 -67
  79. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +26 -43
  80. package/src/renderer/components/team/CcSessionsSection.tsx +34 -14
  81. package/src/renderer/components/team/TeamDetailView.tsx +150 -148
  82. package/src/renderer/components/team/TeamEmptyState.tsx +27 -16
  83. package/src/renderer/components/team/TeamListView.tsx +4 -2
  84. package/src/renderer/components/team/activity/ActivityItem.tsx +6 -1
  85. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +282 -75
  86. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +2 -1
  87. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +64 -21
  88. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +68 -19
  89. package/src/renderer/components/team/dialogs/ProjectPathSelector.tsx +20 -16
  90. package/src/renderer/components/team/dialogs/platformMeta.ts +66 -11
  91. package/src/renderer/components/team/editor/EditorFileTree.tsx +9 -7
  92. package/src/renderer/components/team/kanban/KanbanBoard.tsx +7 -10
  93. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +1 -3
  94. package/src/renderer/components/team/members/MemberDetailDialog.tsx +1 -5
  95. package/src/renderer/components/team/messages/MessageComposer.tsx +3 -1
  96. package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -26
  97. package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +1 -3
  98. package/src/renderer/components/team/schedule/ScheduleSection.tsx +9 -10
  99. package/src/renderer/store/slices/scheduleSlice.ts +4 -1
  100. package/src/renderer/store/slices/teamSlice.ts +3 -1
  101. package/src/shared/types/api.ts +70 -21
  102. package/src/shared/utils/leadDetection.ts +5 -1
  103. package/tsconfig.json +26 -0
  104. package/dist-renderer/assets/channel-CZ8sd5Xf.js +0 -1
  105. package/dist-renderer/assets/classDiagram-2ON5EDUG-CMcfSKj5.js +0 -1
  106. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CMcfSKj5.js +0 -1
  107. package/dist-renderer/assets/clone-CMuwA8RV.js +0 -1
@@ -33,7 +33,16 @@ import { cn } from '@renderer/lib/utils';
33
33
  import { useStore } from '@renderer/store';
34
34
  import { isEphemeralProjectPath } from '@shared/utils/ephemeralProjectPath';
35
35
  import { normalizePath } from '@renderer/utils/pathNormalize';
36
- import { AlertTriangle, CheckCircle2, FolderKanban, Info, Loader2, Settings2, Smartphone, X } from 'lucide-react';
36
+ import {
37
+ AlertTriangle,
38
+ CheckCircle2,
39
+ FolderKanban,
40
+ Info,
41
+ Loader2,
42
+ Settings2,
43
+ Smartphone,
44
+ X,
45
+ } from 'lucide-react';
37
46
 
38
47
  import { ALL_AGENT_TYPES, AGENT_TYPE_LABELS } from '../HarnessCards';
39
48
  import { ProjectPathSelector } from './ProjectPathSelector';
@@ -71,21 +80,90 @@ interface PlatformOption {
71
80
  }
72
81
 
73
82
  const PLATFORM_OPTIONS: PlatformOption[] = [
74
- { key: 'feishu', label: '飞书 / Lark', color: 'bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400', icon: 'qr' },
75
- { key: 'weixin', label: '微信', color: 'bg-green-50 dark:bg-green-900/30 text-green-600 dark:text-green-400', icon: 'qr' },
76
- { key: 'telegram', label: 'Telegram', color: 'bg-sky-50 dark:bg-sky-900/30 text-sky-600 dark:text-sky-400', icon: 'settings' },
77
- { key: 'discord', label: 'Discord', color: 'bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400', icon: 'settings' },
78
- { key: 'slack', label: 'Slack', color: 'bg-purple-50 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400', icon: 'settings' },
79
- { key: 'dingtalk', label: '钉钉', color: 'bg-orange-50 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400', icon: 'settings' },
80
- { key: 'wecom', label: '企业微信', color: 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400', icon: 'settings' },
81
- { key: 'qq', label: 'QQ (OneBot)', color: 'bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400', icon: 'settings' },
82
- { key: 'qqbot', label: 'QQ Bot (官方)', color: 'bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400', icon: 'settings' },
83
- { key: 'line', label: 'LINE', color: 'bg-lime-50 dark:bg-lime-900/30 text-lime-600 dark:text-lime-400', icon: 'settings' },
84
- { key: 'weibo', label: '微博', color: 'bg-red-50 dark:bg-red-900/30 text-red-600 dark:text-red-400', icon: 'settings' },
85
- { key: 'bridge', label: 'Bridge (默认)', color: 'bg-gray-50 dark:bg-gray-800/30 text-gray-600 dark:text-gray-400', icon: 'settings' },
83
+ {
84
+ key: 'feishu',
85
+ label: '飞书 / Lark',
86
+ color: 'bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400',
87
+ icon: 'qr',
88
+ },
89
+ {
90
+ key: 'weixin',
91
+ label: '微信',
92
+ color: 'bg-green-50 dark:bg-green-900/30 text-green-600 dark:text-green-400',
93
+ icon: 'qr',
94
+ },
95
+ {
96
+ key: 'telegram',
97
+ label: 'Telegram',
98
+ color: 'bg-sky-50 dark:bg-sky-900/30 text-sky-600 dark:text-sky-400',
99
+ icon: 'settings',
100
+ },
101
+ {
102
+ key: 'discord',
103
+ label: 'Discord',
104
+ color: 'bg-indigo-50 dark:bg-indigo-900/30 text-indigo-600 dark:text-indigo-400',
105
+ icon: 'settings',
106
+ },
107
+ {
108
+ key: 'slack',
109
+ label: 'Slack',
110
+ color: 'bg-purple-50 dark:bg-purple-900/30 text-purple-600 dark:text-purple-400',
111
+ icon: 'settings',
112
+ },
113
+ {
114
+ key: 'dingtalk',
115
+ label: '钉钉',
116
+ color: 'bg-orange-50 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400',
117
+ icon: 'settings',
118
+ },
119
+ {
120
+ key: 'wecom',
121
+ label: '企业微信',
122
+ color: 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400',
123
+ icon: 'settings',
124
+ },
125
+ {
126
+ key: 'qq',
127
+ label: 'QQ (OneBot)',
128
+ color: 'bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400',
129
+ icon: 'settings',
130
+ },
131
+ {
132
+ key: 'qqbot',
133
+ label: 'QQ Bot (官方)',
134
+ color: 'bg-cyan-50 dark:bg-cyan-900/30 text-cyan-600 dark:text-cyan-400',
135
+ icon: 'settings',
136
+ },
137
+ {
138
+ key: 'line',
139
+ label: 'LINE',
140
+ color: 'bg-lime-50 dark:bg-lime-900/30 text-lime-600 dark:text-lime-400',
141
+ icon: 'settings',
142
+ },
143
+ {
144
+ key: 'weibo',
145
+ label: '微博',
146
+ color: 'bg-red-50 dark:bg-red-900/30 text-red-600 dark:text-red-400',
147
+ icon: 'settings',
148
+ },
149
+ {
150
+ key: 'bridge',
151
+ label: 'Bridge (默认)',
152
+ color: 'bg-gray-50 dark:bg-gray-800/30 text-gray-600 dark:text-gray-400',
153
+ icon: 'settings',
154
+ },
86
155
  ];
87
156
 
88
- const TEAM_COLOR_NAMES = ['blue', 'green', 'red', 'yellow', 'purple', 'cyan', 'orange', 'pink'] as const;
157
+ const TEAM_COLOR_NAMES = [
158
+ 'blue',
159
+ 'green',
160
+ 'red',
161
+ 'yellow',
162
+ 'purple',
163
+ 'cyan',
164
+ 'orange',
165
+ 'pink',
166
+ ] as const;
89
167
 
90
168
  // ---------------------------------------------------------------------------
91
169
  // Wizard step types
@@ -115,29 +193,52 @@ interface CreateTeamDialogProps {
115
193
  /** Sanitize team name: non-alphanumeric → `-`, then lowercase. */
116
194
  function sanitizeTeamName(name: string): string {
117
195
  const trimmed = name.trim();
118
- let result = name.replace(/[^a-zA-Z0-9]/g, '-').replace(/-{2,}/g, '-').toLowerCase();
196
+ let result = name
197
+ .replace(/[^a-zA-Z0-9]/g, '-')
198
+ .replace(/-{2,}/g, '-')
199
+ .toLowerCase();
119
200
  while (result.startsWith('-')) result = result.slice(1);
120
201
  while (result.endsWith('-')) result = result.slice(0, -1);
121
202
  if (!result && trimmed) {
122
203
  let hash = 2166136261;
123
- for (const ch of name) { hash ^= ch.codePointAt(0) ?? 0; hash = Math.imul(hash, 16777619); }
204
+ for (const ch of name) {
205
+ hash ^= ch.codePointAt(0) ?? 0;
206
+ hash = Math.imul(hash, 16777619);
207
+ }
124
208
  result = `team-${(hash >>> 0).toString(36)}`;
125
209
  }
126
210
  return result;
127
211
  }
128
212
 
129
213
  export const CreateTeamDialog = ({
130
- open, canCreate, provisioningErrorsByTeam, clearProvisioningError,
131
- existingTeamNames, provisioningTeamNames = [], activeTeams, defaultProjectPath,
132
- onClose, onCreate, onOpenTeam,
214
+ open,
215
+ canCreate,
216
+ provisioningErrorsByTeam,
217
+ clearProvisioningError,
218
+ existingTeamNames,
219
+ provisioningTeamNames = [],
220
+ activeTeams,
221
+ defaultProjectPath,
222
+ onClose,
223
+ onCreate,
224
+ onOpenTeam,
133
225
  }: CreateTeamDialogProps): React.JSX.Element => {
134
226
  const { isLight } = useTheme();
135
227
 
136
228
  // ── Draft state (persisted) ──────────────────────────────────────────
137
229
  const {
138
- teamName, setTeamName, cwdMode, setCwdMode, selectedProjectPath,
139
- setSelectedProjectPath, customCwd, setCustomCwd, teamColor, setTeamColor,
140
- isLoaded: draftLoaded, clearDraft,
230
+ teamName,
231
+ setTeamName,
232
+ cwdMode,
233
+ setCwdMode,
234
+ selectedProjectPath,
235
+ setSelectedProjectPath,
236
+ customCwd,
237
+ setCustomCwd,
238
+ teamColor,
239
+ setTeamColor,
240
+ isLoaded: draftLoaded,
241
+ clearDraft,
141
242
  } = useCreateTeamDraft();
142
243
 
143
244
  // ── Wizard state ─────────────────────────────────────────────────────
@@ -165,17 +266,22 @@ export const CreateTeamDialog = ({
165
266
  const isNameTaken = existingTeamNames.includes(sanitizedTeamName);
166
267
  const isNameProvisioning = provisioningTeamNames.includes(sanitizedTeamName) && !isNameTaken;
167
268
 
168
- const effectiveCwd = cwdMode === 'project'
169
- ? (isEphemeralProjectPath(selectedProjectPath) ? '' : selectedProjectPath.trim())
170
- : customCwd.trim();
269
+ const effectiveCwd =
270
+ cwdMode === 'project'
271
+ ? isEphemeralProjectPath(selectedProjectPath)
272
+ ? ''
273
+ : selectedProjectPath.trim()
274
+ : customCwd.trim();
171
275
 
172
276
  const conflictingTeam = useMemo(() => {
173
277
  if (!activeTeams?.length || !effectiveCwd) return null;
174
278
  const norm = normalizePath(effectiveCwd);
175
- return activeTeams.find(t => normalizePath(t.projectPath) === norm) ?? null;
279
+ return activeTeams.find((t) => normalizePath(t.projectPath) === norm) ?? null;
176
280
  }, [activeTeams, effectiveCwd]);
177
281
  const [conflictDismissed, setConflictDismissed] = useState(false);
178
- useEffect(() => { setConflictDismissed(false); }, [conflictingTeam?.teamName, effectiveCwd]);
282
+ useEffect(() => {
283
+ setConflictDismissed(false);
284
+ }, [conflictingTeam?.teamName, effectiveCwd]);
179
285
 
180
286
  // ── Load projects on open ────────────────────────────────────────────
181
287
  useEffect(() => {
@@ -185,8 +291,10 @@ export const CreateTeamDialog = ({
185
291
  let cancelled = false;
186
292
  void (async () => {
187
293
  try {
188
- const next = (await api.getProjects()).filter(p => !isEphemeralProjectPath(p.path));
189
- if (!cancelled) { setProjects(next); }
294
+ const next = (await api.getProjects()).filter((p) => !isEphemeralProjectPath(p.path));
295
+ if (!cancelled) {
296
+ setProjects(next);
297
+ }
190
298
  } catch (e: unknown) {
191
299
  if (!cancelled) {
192
300
  setProjectsError(e instanceof Error ? e.message : '加载项目列表失败');
@@ -196,17 +304,24 @@ export const CreateTeamDialog = ({
196
304
  if (!cancelled) setProjectsLoading(false);
197
305
  }
198
306
  })();
199
- return () => { cancelled = true; };
307
+ return () => {
308
+ cancelled = true;
309
+ };
200
310
  }, [open]);
201
311
 
202
312
  // ── Auto-select default project path ─────────────────────────────────
203
313
  useEffect(() => {
204
314
  if (!open || cwdMode !== 'project' || selectedProjectPath) return;
205
- const selectable = projects.filter(p => !isEphemeralProjectPath(p.path));
315
+ const selectable = projects.filter((p) => !isEphemeralProjectPath(p.path));
206
316
  if (selectable.length === 0) return;
207
317
  if (defaultProjectPath && !isEphemeralProjectPath(defaultProjectPath)) {
208
- const match = selectable.find(p => normalizePath(p.path) === normalizePath(defaultProjectPath));
209
- if (match) { setSelectedProjectPath(match.path); return; }
318
+ const match = selectable.find(
319
+ (p) => normalizePath(p.path) === normalizePath(defaultProjectPath)
320
+ );
321
+ if (match) {
322
+ setSelectedProjectPath(match.path);
323
+ return;
324
+ }
210
325
  }
211
326
  setSelectedProjectPath(selectable[0].path);
212
327
  }, [open, cwdMode, projects, selectedProjectPath, defaultProjectPath]);
@@ -262,8 +377,14 @@ export const CreateTeamDialog = ({
262
377
  setLocalError(isNameProvisioning ? '团队正在启动中' : '团队名称已存在');
263
378
  return;
264
379
  }
265
- if (!sanitizedTeamName) { setLocalError('请输入团队名称'); return; }
266
- if (!effectiveCwd) { setLocalError('请选择工作目录'); return; }
380
+ if (!sanitizedTeamName) {
381
+ setLocalError('请输入团队名称');
382
+ return;
383
+ }
384
+ if (!effectiveCwd) {
385
+ setLocalError('请选择工作目录');
386
+ return;
387
+ }
267
388
 
268
389
  setFieldErrors({});
269
390
  setLocalError(null);
@@ -296,7 +417,15 @@ export const CreateTeamDialog = ({
296
417
 
297
418
  // ── Render ───────────────────────────────────────────────────────────
298
419
  return (
299
- <Dialog open={open} onOpenChange={(next: boolean) => { if (!next) { resetState(); onClose(); } }}>
420
+ <Dialog
421
+ open={open}
422
+ onOpenChange={(next: boolean) => {
423
+ if (!next) {
424
+ resetState();
425
+ onClose();
426
+ }
427
+ }}
428
+ >
300
429
  <DialogContent className="w-[calc(100vw-2rem)] max-w-2xl sm:w-[40rem]">
301
430
  <DialogHeader>
302
431
  <DialogTitle className="text-sm">创建团队</DialogTitle>
@@ -310,14 +439,27 @@ export const CreateTeamDialog = ({
310
439
  </DialogHeader>
311
440
 
312
441
  {conflictingTeam && !conflictDismissed ? (
313
- <div className="rounded-md border p-3 text-xs" style={{ backgroundColor: 'var(--warning-bg)', borderColor: 'var(--warning-border)', color: 'var(--warning-text)' }}>
442
+ <div
443
+ className="rounded-md border p-3 text-xs"
444
+ style={{
445
+ backgroundColor: 'var(--warning-bg)',
446
+ borderColor: 'var(--warning-border)',
447
+ color: 'var(--warning-text)',
448
+ }}
449
+ >
314
450
  <div className="flex items-start gap-2">
315
451
  <AlertTriangle className="mt-0.5 size-4 shrink-0" />
316
452
  <div className="min-w-0 flex-1 space-y-1">
317
- <p className="font-medium">该工作目录下已有团队"{conflictingTeam.displayName}"正在运行</p>
453
+ <p className="font-medium">
454
+ 该工作目录下已有团队"{conflictingTeam.displayName}"正在运行
455
+ </p>
318
456
  <p className="opacity-80">在同一目录同时运行两个团队存在风险。</p>
319
457
  </div>
320
- <button type="button" className="shrink-0 rounded p-0.5 opacity-60 hover:opacity-100" onClick={() => setConflictDismissed(true)}>
458
+ <button
459
+ type="button"
460
+ className="shrink-0 rounded p-0.5 opacity-60 hover:opacity-100"
461
+ onClick={() => setConflictDismissed(true)}
462
+ >
321
463
  <X className="size-3.5" />
322
464
  </button>
323
465
  </div>
@@ -331,16 +473,29 @@ export const CreateTeamDialog = ({
331
473
  <Label htmlFor="team-name">团队名称</Label>
332
474
  <Input
333
475
  id="team-name"
334
- className={cn('h-8 text-xs', fieldErrors.teamName && 'border-[var(--field-error-border)]')}
476
+ className={cn(
477
+ 'h-8 text-xs',
478
+ fieldErrors.teamName && 'border-[var(--field-error-border)]'
479
+ )}
335
480
  value={teamName}
336
- onChange={e => setTeamName(e.target.value)}
481
+ onChange={(e) => setTeamName(e.target.value)}
337
482
  placeholder="my-team"
338
483
  autoFocus
339
484
  />
340
- {isNameTaken && <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>团队名称已存在</p>}
341
- {isNameProvisioning && <p className="text-[11px]" style={{ color: 'var(--warning-text)' }}>同名团队正在启动中</p>}
485
+ {isNameTaken && (
486
+ <p className="text-[11px]" style={{ color: 'var(--field-error-text)' }}>
487
+ 团队名称已存在
488
+ </p>
489
+ )}
490
+ {isNameProvisioning && (
491
+ <p className="text-[11px]" style={{ color: 'var(--warning-text)' }}>
492
+ 同名团队正在启动中
493
+ </p>
494
+ )}
342
495
  {sanitizedTeamName && sanitizedTeamName !== teamName.trim() && (
343
- <p className="text-[11px] text-[var(--color-text-muted)]">内部标识:<span className="font-mono">{sanitizedTeamName}</span></p>
496
+ <p className="text-[11px] text-[var(--color-text-muted)]">
497
+ 内部标识:<span className="font-mono">{sanitizedTeamName}</span>
498
+ </p>
344
499
  )}
345
500
  </div>
346
501
 
@@ -350,10 +505,12 @@ export const CreateTeamDialog = ({
350
505
  id="team-harness"
351
506
  className="flex w-full rounded-md border border-[var(--color-border)] bg-transparent px-3 py-2 text-sm"
352
507
  value={selectedHarness}
353
- onChange={e => setSelectedHarness(e.target.value as CcAgentType)}
508
+ onChange={(e) => setSelectedHarness(e.target.value as CcAgentType)}
354
509
  >
355
- {ALL_AGENT_TYPES.map(t => (
356
- <option key={t} value={t}>{AGENT_TYPE_LABELS[t]}</option>
510
+ {ALL_AGENT_TYPES.map((t) => (
511
+ <option key={t} value={t}>
512
+ {AGENT_TYPE_LABELS[t]}
513
+ </option>
357
514
  ))}
358
515
  </select>
359
516
  </div>
@@ -376,19 +533,23 @@ export const CreateTeamDialog = ({
376
533
  {/* ── Step 2: Platform selection ── */}
377
534
  {step === 'platform' && (
378
535
  <div className="space-y-3 py-2">
379
- <p className="text-sm text-gray-500 dark:text-gray-400 mb-2">选择要绑定的平台渠道:</p>
380
- <div className="grid grid-cols-2 gap-2 max-h-80 overflow-y-auto">
536
+ <p className="mb-2 text-sm text-gray-500 dark:text-gray-400">选择要绑定的平台渠道:</p>
537
+ <div className="grid max-h-80 grid-cols-2 gap-2 overflow-y-auto">
381
538
  {PLATFORM_OPTIONS.map(({ key, label, color, icon }) => (
382
539
  <button
383
540
  key={key}
384
541
  onClick={() => handlePlatformSelect(key)}
385
- className="flex items-center gap-2.5 p-3 rounded-xl border border-gray-200 dark:border-gray-700 hover:border-blue-500/50 hover:bg-blue-500/5 transition-all text-left"
542
+ className="flex items-center gap-2.5 rounded-xl border border-gray-200 p-3 text-left transition-all hover:border-blue-500/50 hover:bg-blue-500/5 dark:border-gray-700"
386
543
  >
387
- <div className={`w-9 h-9 rounded-lg ${color} flex items-center justify-center shrink-0`}>
544
+ <div
545
+ className={`h-9 w-9 rounded-lg ${color} flex shrink-0 items-center justify-center`}
546
+ >
388
547
  {icon === 'qr' ? <Smartphone size={16} /> : <Settings2 size={16} />}
389
548
  </div>
390
549
  <div className="min-w-0">
391
- <div className="text-sm font-medium text-gray-900 dark:text-white truncate">{label}</div>
550
+ <div className="truncate text-sm font-medium text-gray-900 dark:text-white">
551
+ {label}
552
+ </div>
392
553
  <div className="text-[11px] text-gray-400">
393
554
  {icon === 'qr' ? '扫码绑定' : '手动配置'}
394
555
  </div>
@@ -397,22 +558,27 @@ export const CreateTeamDialog = ({
397
558
  ))}
398
559
  </div>
399
560
  <div className="flex justify-start pt-2">
400
- <Button variant="outline" size="sm" onClick={() => setStep('name')}>返回</Button>
561
+ <Button variant="outline" size="sm" onClick={() => setStep('name')}>
562
+ 返回
563
+ </Button>
401
564
  </div>
402
565
  </div>
403
566
  )}
404
567
 
405
568
  {/* ── Step 3a: QR setup (feishu/weixin) ── */}
406
- {step === 'qr' && (selectedPlatform === 'feishu' || selectedPlatform === 'lark' || selectedPlatform === 'weixin') && (
407
- <PlatformSetupQR
408
- platformType={selectedPlatform as 'feishu' | 'lark' | 'weixin'}
409
- projectName={sanitizedTeamName}
410
- workDir={effectiveCwd}
411
- agentType={selectedHarness}
412
- onComplete={handleQRComplete}
413
- onCancel={() => setStep('platform')}
414
- />
415
- )}
569
+ {step === 'qr' &&
570
+ (selectedPlatform === 'feishu' ||
571
+ selectedPlatform === 'lark' ||
572
+ selectedPlatform === 'weixin') && (
573
+ <PlatformSetupQR
574
+ platformType={selectedPlatform as 'feishu' | 'lark' | 'weixin'}
575
+ projectName={sanitizedTeamName}
576
+ workDir={effectiveCwd}
577
+ agentType={selectedHarness}
578
+ onComplete={handleQRComplete}
579
+ onCancel={() => setStep('platform')}
580
+ />
581
+ )}
416
582
 
417
583
  {/* ── Step 3b: Manual form (telegram/slack/etc.) ── */}
418
584
  {step === 'form' && platformMeta[selectedPlatform] && (
@@ -432,8 +598,10 @@ export const CreateTeamDialog = ({
432
598
  <div className="space-y-4 py-4">
433
599
  <div className="flex flex-col items-center gap-3 py-4">
434
600
  <CheckCircle2 size={48} className="text-green-500" />
435
- <p className="text-sm font-medium text-green-700 dark:text-green-400">团队已创建成功!</p>
436
- <p className="text-xs text-gray-500 text-center">
601
+ <p className="text-sm font-medium text-green-700 dark:text-green-400">
602
+ 团队已创建成功!
603
+ </p>
604
+ <p className="text-center text-xs text-gray-500">
437
605
  {selectedPlatform && selectedPlatform !== 'bridge'
438
606
  ? '平台绑定完成,重启服务使配置生效'
439
607
  : 'Bridge 模式已启用,无需额外配置'}
@@ -446,12 +614,26 @@ export const CreateTeamDialog = ({
446
614
  <DialogFooter className="pt-4 sm:justify-between">
447
615
  <div className="min-w-0">
448
616
  {localError && (
449
- <p className="rounded border p-2 text-xs" style={{ color: 'var(--field-error-text)', borderColor: 'var(--field-error-border)', backgroundColor: 'var(--field-error-bg)' }}>
617
+ <p
618
+ className="rounded border p-2 text-xs"
619
+ style={{
620
+ color: 'var(--field-error-text)',
621
+ borderColor: 'var(--field-error-border)',
622
+ backgroundColor: 'var(--field-error-bg)',
623
+ }}
624
+ >
450
625
  {localError}
451
626
  </p>
452
627
  )}
453
628
  {provisioningErrorsByTeam[sanitizedTeamName] && (
454
- <p className="rounded border p-2 text-xs mt-1" style={{ color: 'var(--field-error-text)', borderColor: 'var(--field-error-border)', backgroundColor: 'var(--field-error-bg)' }}>
629
+ <p
630
+ className="mt-1 rounded border p-2 text-xs"
631
+ style={{
632
+ color: 'var(--field-error-text)',
633
+ borderColor: 'var(--field-error-border)',
634
+ backgroundColor: 'var(--field-error-bg)',
635
+ }}
636
+ >
455
637
  {provisioningErrorsByTeam[sanitizedTeamName]}
456
638
  </p>
457
639
  )}
@@ -460,21 +642,46 @@ export const CreateTeamDialog = ({
460
642
  <div className="flex shrink-0 items-center gap-2">
461
643
  {step === 'done' ? (
462
644
  <>
463
- <Button variant="outline" size="sm" onClick={() => { clearDraft(); resetState(); onClose(); }}>关闭</Button>
464
- <Button size="sm" onClick={() => {
465
- onOpenTeam(sanitizedTeamName, effectiveCwd);
466
- clearDraft(); resetState(); onClose();
467
- }}>打开团队</Button>
645
+ <Button
646
+ variant="outline"
647
+ size="sm"
648
+ onClick={() => {
649
+ clearDraft();
650
+ resetState();
651
+ onClose();
652
+ }}
653
+ >
654
+ 关闭
655
+ </Button>
656
+ <Button
657
+ size="sm"
658
+ onClick={() => {
659
+ onOpenTeam(sanitizedTeamName, effectiveCwd);
660
+ clearDraft();
661
+ resetState();
662
+ onClose();
663
+ }}
664
+ >
665
+ 打开团队
666
+ </Button>
468
667
  </>
469
668
  ) : step === 'name' ? (
470
669
  <>
471
- <Button variant="outline" size="sm" onClick={onClose}>取消</Button>
472
- <Button size="sm" disabled={!sanitizedTeamName || !effectiveCwd} onClick={() => setStep('platform')}>
670
+ <Button variant="outline" size="sm" onClick={onClose}>
671
+ 取消
672
+ </Button>
673
+ <Button
674
+ size="sm"
675
+ disabled={!sanitizedTeamName || !effectiveCwd}
676
+ onClick={() => setStep('platform')}
677
+ >
473
678
  下一步
474
679
  </Button>
475
680
  </>
476
681
  ) : step === 'platform' ? (
477
- <Button variant="outline" size="sm" onClick={() => setStep('name')}>返回</Button>
682
+ <Button variant="outline" size="sm" onClick={() => setStep('name')}>
683
+ 返回
684
+ </Button>
478
685
  ) : null}
479
686
  </div>
480
687
  </DialogFooter>
@@ -227,7 +227,8 @@ export const EditTeamDialog = ({
227
227
  <div>
228
228
  <h3 className="text-sm font-medium text-[var(--color-text)]">Agent 配置</h3>
229
229
  <p className="mt-0.5 text-xs text-[var(--color-text-muted)]">
230
- 这里直接维护 cc-connect 项目的基础运行参数。运行时模型和 Provider 请到 Harness 配置中管理。
230
+ 这里直接维护 cc-connect 项目的基础运行参数。运行时模型和 Provider 请到 Harness
231
+ 配置中管理。
231
232
  </p>
232
233
  </div>
233
234