@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.
- package/README.md +10 -1
- package/bin/alias-loader.mjs +51 -0
- package/bin/hermit.mjs +14 -5
- package/dist-renderer/assets/{ProjectEditorOverlay-BNoDw9T1.js → ProjectEditorOverlay-C5D83Zxv.js} +1 -1
- package/dist-renderer/assets/{TeamGraphOverlay-CfGRKQIu.js → TeamGraphOverlay-ajzuM1-u.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-Ct8Hm5_h.js → _basePickBy-C9H2zmVj.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-BofrAFBx.js → _baseUniq-CpGZGemc.js} +1 -1
- package/dist-renderer/assets/{arc-AbJgatzR.js → arc-CbGBDw-m.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-gpniCJVk.js → architectureDiagram-VXUJARFQ-nuKXUIpb.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-aBbbmONC.js → blockDiagram-VD42YOAC-DHUUE7Jc.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-DJio1IsU.js → c4Diagram-YG6GDRKO-OILHhqLM.js} +1 -1
- package/dist-renderer/assets/channel-DpUKLLrj.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-D1_HKao2.js → chunk-4BX2VUAB-dqNpZaQ8.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-NAmVxF4k.js → chunk-55IACEB6-BCoSJQM-.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-Ce829laz.js → chunk-B4BG7PRW-BLbg8yVR.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-Ct2Le12y.js → chunk-DI55MBZ5-CUUWOs1Q.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-Cie3DzKk.js → chunk-FMBD7UC4-D9geTN5P.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-4f5Yb50e.js → chunk-QN33PNHL-BGT8-BRX.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-D9ranl9c.js → chunk-QZHKN3VN-CC8ebGaM.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-bdGZWlEy.js → chunk-TZMSLE5B-CajekcT6.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-LL85aSlz.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-LL85aSlz.js +1 -0
- package/dist-renderer/assets/clone-BHWsFzFA.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-C6tvfcVi.js → cose-bilkent-S5V4N54A-C_x7hSy3.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-B-4qcZam.js → dagre-6UL2VRFP-C4Y1k4DZ.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-CwT3TLjx.js → diagram-PSM6KHXK-oRIeULoh.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-BWH6-ZFd.js → diagram-QEK2KX5R-DwSqw5HF.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-DfpPnfi1.js → diagram-S2PKOQOG-DqjGYje2.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-BFbEFR4x.js → erDiagram-Q2GNP2WA-CEV5bBgg.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-Dg3cf5hW.js → flowDiagram-NV44I4VS-BQQkrRyu.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-B21y55W5.js → ganttDiagram-JELNMOA3-CLy4WR1G.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BDV3BJzn.js → gitGraphDiagram-V2S2FVAM-6W3ioQu_.js} +1 -1
- package/dist-renderer/assets/{graph-BfaZ4hZt.js → graph-BnLKQvhH.js} +1 -1
- package/dist-renderer/assets/{index-CCqtDawH.js → index-B4aiRxoU.js} +1 -1
- package/dist-renderer/assets/{index-pMg_LlsS.js → index-B8lKqPVq.js} +1 -1
- package/dist-renderer/assets/{index-CZltVMDP.js → index-BRuhNKyU.js} +12 -12
- package/dist-renderer/assets/{index-BMXHMpkG.js → index-BufvLVIl.js} +1 -1
- package/dist-renderer/assets/{index-Ct0-y9TF.js → index-C1xShqKH.js} +1 -1
- package/dist-renderer/assets/{index-CVMSpK8C.js → index-zIOLLI7O.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DvMlS0CL.js → infoDiagram-HS3SLOUP-BoBweEEY.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DIyMluRv.js → journeyDiagram-XKPGCS4Q-DLL0V5oP.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-CVOx8f-7.js → kanban-definition-3W4ZIXB7-HsFtEDG3.js} +1 -1
- package/dist-renderer/assets/{layout-BPKIXUf4.js → layout-ClIooAAq.js} +1 -1
- package/dist-renderer/assets/{linear-CScZGLr2.js → linear-r3RJcj8y.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-CmDQ7Wo6.js → mindmap-definition-VGOIOE7T-BA_P1U4V.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-DbVClin-.js → pieDiagram-ADFJNKIX-CzPAfkTB.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CAB0MYcW.js → quadrantDiagram-AYHSOK5B-PvdPWzFJ.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-w2Lfpg3T.js → requirementDiagram-UZGBJVZJ-CHqIL_Od.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-kvG1QoKY.js → sankeyDiagram-TZEHDZUN-ConzpACM.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-DCVBQ23J.js → sequenceDiagram-WL72ISMW-Zryq4oxP.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-ItZ0JBvq.js → stateDiagram-FKZM4ZOC-BA9V7NHF.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-Hpmw4dMm.js → stateDiagram-v2-4FDKWEC3-CGnaujD-.js} +1 -1
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BzSFaAjV.js → timeline-definition-IT6M3QCI-DPs2ZjMm.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-fSz4hQn0.js → treemap-GDKQZRPO-B0lzrLxb.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-CT1kaGlv.js → xychartDiagram-PRI3JC2R-CINGmMxX.js} +1 -1
- package/dist-renderer/index.html +1 -1
- package/package.json +2 -1
- package/src/main/server.ts +993 -764
- package/src/main/services/UpdateService.ts +4 -1
- package/src/main/services/ccConnect/CcConnectBridge.ts +1 -8
- package/src/main/services/ccConnect/CcConnectClient.ts +7 -2
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +14 -4
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +11 -6
- package/src/renderer/App.tsx +18 -7
- package/src/renderer/api/httpClient.ts +136 -42
- package/src/renderer/components/chat/ChatHistory.tsx +11 -8
- package/src/renderer/components/dashboard/DashboardView.tsx +4 -2
- package/src/renderer/components/extensions/ExtensionStoreView.tsx +2 -7
- package/src/renderer/components/layout/Sidebar.tsx +3 -1
- package/src/renderer/components/schedules/SchedulesView.tsx +15 -13
- package/src/renderer/components/settings/SettingsTabs.tsx +2 -1
- package/src/renderer/components/settings/hooks/useSettingsHandlers.ts +4 -5
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +19 -4
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +63 -59
- package/src/renderer/components/settings/sections/GeneralSection.tsx +5 -11
- package/src/renderer/components/settings/sections/HarnessSection.tsx +30 -15
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +110 -51
- package/src/renderer/components/sidebar/SidebarSessions.tsx +100 -67
- package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +26 -43
- package/src/renderer/components/team/CcSessionsSection.tsx +34 -14
- package/src/renderer/components/team/TeamDetailView.tsx +150 -148
- package/src/renderer/components/team/TeamEmptyState.tsx +27 -16
- package/src/renderer/components/team/TeamListView.tsx +4 -2
- package/src/renderer/components/team/activity/ActivityItem.tsx +6 -1
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +282 -75
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +2 -1
- package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +64 -21
- package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +68 -19
- package/src/renderer/components/team/dialogs/ProjectPathSelector.tsx +20 -16
- package/src/renderer/components/team/dialogs/platformMeta.ts +66 -11
- package/src/renderer/components/team/editor/EditorFileTree.tsx +9 -7
- package/src/renderer/components/team/kanban/KanbanBoard.tsx +7 -10
- package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +1 -3
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +1 -5
- package/src/renderer/components/team/messages/MessageComposer.tsx +3 -1
- package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -26
- package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +1 -3
- package/src/renderer/components/team/schedule/ScheduleSection.tsx +9 -10
- package/src/renderer/store/slices/scheduleSlice.ts +4 -1
- package/src/renderer/store/slices/teamSlice.ts +3 -1
- package/src/shared/types/api.ts +70 -21
- package/src/shared/utils/leadDetection.ts +5 -1
- package/tsconfig.json +26 -0
- package/dist-renderer/assets/channel-CZ8sd5Xf.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-CMcfSKj5.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CMcfSKj5.js +0 -1
- 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 {
|
|
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
|
-
{
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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 = [
|
|
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
|
|
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) {
|
|
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,
|
|
131
|
-
|
|
132
|
-
|
|
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,
|
|
139
|
-
|
|
140
|
-
|
|
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 =
|
|
169
|
-
|
|
170
|
-
|
|
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(() => {
|
|
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) {
|
|
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 () => {
|
|
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(
|
|
209
|
-
|
|
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) {
|
|
266
|
-
|
|
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
|
|
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
|
|
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"
|
|
453
|
+
<p className="font-medium">
|
|
454
|
+
该工作目录下已有团队"{conflictingTeam.displayName}"正在运行
|
|
455
|
+
</p>
|
|
318
456
|
<p className="opacity-80">在同一目录同时运行两个团队存在风险。</p>
|
|
319
457
|
</div>
|
|
320
|
-
<button
|
|
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(
|
|
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 &&
|
|
341
|
-
|
|
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)]"
|
|
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}>
|
|
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
|
|
380
|
-
<div className="grid grid-cols-2 gap-2
|
|
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
|
|
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
|
|
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
|
|
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')}
|
|
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' &&
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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"
|
|
436
|
-
|
|
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
|
|
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
|
|
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
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
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}
|
|
472
|
-
|
|
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')}
|
|
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
|
|