@yancyyu/openhermit 1.6.25 → 1.6.26
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 +4 -0
- package/bin/hermit.mjs +151 -62
- package/dist-renderer/assets/{ProjectEditorOverlay-CZ1LI0pd.js → ProjectEditorOverlay-Byepdwo2.js} +1 -1
- package/dist-renderer/assets/{TeamGraphOverlay-DvyxOPvU.js → TeamGraphOverlay-vvWu-2c9.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-D8IKEBh4.js → _basePickBy-DfsmMgXN.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-BDBpSAHY.js → _baseUniq-Bve-IKz5.js} +1 -1
- package/dist-renderer/assets/{arc-CZagJLek.js → arc-4cbkhagw.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-Cq083Uu6.js → architectureDiagram-VXUJARFQ-CC9i0bMK.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-CIEANvSv.js → blockDiagram-VD42YOAC-BjFruJ65.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-Ca4h_BlA.js → c4Diagram-YG6GDRKO-CrYzsQC1.js} +1 -1
- package/dist-renderer/assets/channel-BMMyVRy4.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-DW9HjNgA.js → chunk-4BX2VUAB-Bb9MCt7J.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-BddOEwBk.js → chunk-55IACEB6-BpOVOXVa.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-Cmu8IjLN.js → chunk-B4BG7PRW-GtEiO-7n.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-BU7nEH8e.js → chunk-DI55MBZ5-BRlzcOEj.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-BZNeq0CB.js → chunk-FMBD7UC4-DcvMVOZx.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-DMb3gYzN.js → chunk-QN33PNHL-B9pkjVpd.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-8wSSvqz0.js → chunk-QZHKN3VN-DzHPSm01.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-B4OLgw45.js → chunk-TZMSLE5B-BU9c0Hcn.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-Dz1VG1T3.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-Dz1VG1T3.js +1 -0
- package/dist-renderer/assets/clone-COsIIGZQ.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-CS9moNeT.js → cose-bilkent-S5V4N54A-BqOg0x3V.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-3pzdMwjZ.js → dagre-6UL2VRFP-C9JTWefj.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-CGTnMY5C.js → diagram-PSM6KHXK-ljleG6ui.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-Cyzp8dOw.js → diagram-QEK2KX5R-BbV-WSTr.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-D_5SvdXI.js → diagram-S2PKOQOG-CKi3DFby.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-bWPYfs9c.js → erDiagram-Q2GNP2WA-D3HE7b-j.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-C5z47CKB.js → flowDiagram-NV44I4VS-C2yLRmM0.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-eye9Cv6S.js → ganttDiagram-JELNMOA3-XEV4KtUf.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DekQZoF8.js → gitGraphDiagram-V2S2FVAM-ufaCCg7c.js} +1 -1
- package/dist-renderer/assets/{graph-kNnl-9Fl.js → graph-BzPvdBp0.js} +1 -1
- package/dist-renderer/assets/{index-CrOkTuIK.js → index-A5CMVuXA.js} +525 -525
- package/dist-renderer/assets/{index-CI2l57ID.js → index-BprOls_t.js} +1 -1
- package/dist-renderer/assets/index-CWpFqEvz.css +1 -0
- package/dist-renderer/assets/{index-DB0k9yRL.js → index-Cr91T9ef.js} +1 -1
- package/dist-renderer/assets/{index-CnxDIJh8.js → index-DHq6dXy7.js} +1 -1
- package/dist-renderer/assets/{index-ATiHUmmE.js → index-DUIDxnaf.js} +1 -1
- package/dist-renderer/assets/{index-hGBnMHVl.js → index-yNYjzR2R.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D3ilrGOS.js → infoDiagram-HS3SLOUP-DKP5zgHc.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BOCG2Rrk.js → journeyDiagram-XKPGCS4Q-Omd7tmzE.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-hZ03nCkx.js → kanban-definition-3W4ZIXB7-D7yw9yIY.js} +1 -1
- package/dist-renderer/assets/{layout-D5Mqy2My.js → layout-DZxAqFuM.js} +1 -1
- package/dist-renderer/assets/{linear-Clp9OpXU.js → linear-BXWJygRB.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-D-w-qhNz.js → mindmap-definition-VGOIOE7T-BfJ09SBb.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-D9K0-ecY.js → pieDiagram-ADFJNKIX-BYaLQhXj.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-B2f19Ki3.js → quadrantDiagram-AYHSOK5B-DeA0B1fw.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-VezNpCaU.js → requirementDiagram-UZGBJVZJ-DnFWn7-v.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-BpHjEoR9.js → sankeyDiagram-TZEHDZUN-L9bek20k.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-Tdb7IZ4t.js → sequenceDiagram-WL72ISMW-BBmcJUXb.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-BNA5Q-zz.js → stateDiagram-FKZM4ZOC-DrwPQvTq.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-w_4GEN2a.js → stateDiagram-v2-4FDKWEC3-BOUQrTH6.js} +1 -1
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BghtWMWY.js → timeline-definition-IT6M3QCI-Dldh9vsj.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-BVquWjHf.js → treemap-GDKQZRPO-BsGSs8-P.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-BSV5wEDU.js → xychartDiagram-PRI3JC2R-BsR_bj-d.js} +1 -1
- package/dist-renderer/index.html +2 -2
- package/package.json +2 -2
- package/src/main/server.ts +38 -10
- package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +2 -0
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +2 -0
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +2 -0
- package/src/renderer/components/settings/sections/HarnessSection.tsx +11 -0
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +10 -2
- package/src/renderer/components/team/TeamDetailView.tsx +15 -24
- package/src/renderer/components/team/TeamListView.tsx +21 -12
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +120 -0
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +95 -2
- package/src/renderer/utils/openHermitEvents.ts +9 -0
- package/src/shared/types/team.ts +5 -0
- package/dist-renderer/assets/channel-CqQK8EX1.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-9A3Cg8IA.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-9A3Cg8IA.js +0 -1
- package/dist-renderer/assets/clone-Bnr-WjeU.js +0 -1
- package/dist-renderer/assets/index-C4x095x4.css +0 -1
package/src/main/server.ts
CHANGED
|
@@ -50,16 +50,6 @@ import { TaskDispatchService } from './services/teams-mvp/TaskDispatchService';
|
|
|
50
50
|
import type { TaskBusConfig } from '@shared/types/team';
|
|
51
51
|
import { UpdateService } from './services/UpdateService';
|
|
52
52
|
|
|
53
|
-
process.on('uncaughtException', (err) => {
|
|
54
|
-
console.error('[openHermit:server] uncaughtException', err);
|
|
55
|
-
process.exit(1);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
process.on('unhandledRejection', (reason) => {
|
|
59
|
-
console.error('[openHermit:server] unhandledRejection', reason);
|
|
60
|
-
process.exit(1);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
53
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
64
54
|
const pkg = JSON.parse(readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
|
|
65
55
|
const REPO_ROOT = path.resolve(__dirname, '..', '..');
|
|
@@ -816,6 +806,16 @@ app.post('/api/teams/create', async (request, reply) => {
|
|
|
816
806
|
request.log.warn({ err, teamName: name }, 'failed to persist local team metadata');
|
|
817
807
|
}
|
|
818
808
|
|
|
809
|
+
// Bind provider refs if specified
|
|
810
|
+
const providerRefs = Array.isArray(body.providerRefs) ? body.providerRefs as string[] : [];
|
|
811
|
+
if (providerRefs.length > 0) {
|
|
812
|
+
try {
|
|
813
|
+
await cc.setProviderRefs(name, providerRefs);
|
|
814
|
+
} catch (err) {
|
|
815
|
+
request.log.warn({ err, teamName: name, providerRefs }, 'failed to set provider refs');
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
819
|
return { ok: true, teamName: name, runId: null };
|
|
820
820
|
} catch (err) {
|
|
821
821
|
return reply.code(500).send({ error: err instanceof Error ? err.message : String(err) });
|
|
@@ -915,6 +915,10 @@ app.get<{ Params: { name: string } }>('/api/teams/:name/data', async (request, r
|
|
|
915
915
|
typeof p.agent_mode === 'string' && p.agent_mode.trim().length > 0
|
|
916
916
|
? p.agent_mode.trim()
|
|
917
917
|
: permissionMode;
|
|
918
|
+
const [providerRefs, globalProviders] = await Promise.all([
|
|
919
|
+
cc.getProviderRefs(name).catch(() => []),
|
|
920
|
+
cc.listProviders().catch(() => []),
|
|
921
|
+
]);
|
|
918
922
|
|
|
919
923
|
return {
|
|
920
924
|
teamName: name,
|
|
@@ -955,6 +959,8 @@ app.get<{ Params: { name: string } }>('/api/teams/:name/data', async (request, r
|
|
|
955
959
|
description,
|
|
956
960
|
workDir: p.work_dir ?? workDir,
|
|
957
961
|
permissionMode: resolvedPermissionMode,
|
|
962
|
+
providerRefs,
|
|
963
|
+
globalProviders,
|
|
958
964
|
settings: {
|
|
959
965
|
...projectSettings,
|
|
960
966
|
language: resolvedLanguage,
|
|
@@ -1009,6 +1015,8 @@ app.get<{ Params: { name: string } }>('/api/teams/:name/data', async (request, r
|
|
|
1009
1015
|
description,
|
|
1010
1016
|
workDir,
|
|
1011
1017
|
permissionMode,
|
|
1018
|
+
providerRefs: [],
|
|
1019
|
+
globalProviders: [],
|
|
1012
1020
|
heartbeat: null,
|
|
1013
1021
|
settings: {
|
|
1014
1022
|
language,
|
|
@@ -1042,6 +1050,9 @@ app.delete<{ Params: { name: string }; Querystring: { deleteFiles?: string } }>(
|
|
|
1042
1050
|
'/api/teams/:name',
|
|
1043
1051
|
async (request, reply) => {
|
|
1044
1052
|
const teamName = request.params.name;
|
|
1053
|
+
if (teamName === 'default') {
|
|
1054
|
+
return reply.code(403).send({ error: 'default 团队不可删除' });
|
|
1055
|
+
}
|
|
1045
1056
|
try {
|
|
1046
1057
|
let restartRequired = false;
|
|
1047
1058
|
try {
|
|
@@ -3406,6 +3417,9 @@ async function applyTeamConfigUpdate(
|
|
|
3406
3417
|
const disabledCommands = Array.isArray(body.disabledCommands)
|
|
3407
3418
|
? normalizeStringArray(body.disabledCommands)
|
|
3408
3419
|
: undefined;
|
|
3420
|
+
const providerRefs = Array.isArray(body.providerRefs)
|
|
3421
|
+
? normalizeStringArray(body.providerRefs)
|
|
3422
|
+
: undefined;
|
|
3409
3423
|
const platformAllowFrom = body.platformAllowFrom
|
|
3410
3424
|
? normalizePlatformAllowFrom(body.platformAllowFrom)
|
|
3411
3425
|
: undefined;
|
|
@@ -3470,6 +3484,13 @@ async function applyTeamConfigUpdate(
|
|
|
3470
3484
|
ccSyncError = err instanceof Error ? err.message : String(err);
|
|
3471
3485
|
}
|
|
3472
3486
|
}
|
|
3487
|
+
if (providerRefs !== undefined) {
|
|
3488
|
+
try {
|
|
3489
|
+
await cc.setProviderRefs(teamName, providerRefs);
|
|
3490
|
+
} catch (err) {
|
|
3491
|
+
ccSyncError = err instanceof Error ? err.message : String(err);
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3473
3494
|
|
|
3474
3495
|
return {
|
|
3475
3496
|
name: name || teamName,
|
|
@@ -3486,6 +3507,7 @@ async function applyTeamConfigUpdate(
|
|
|
3486
3507
|
replyFooter: replyFooter ?? false,
|
|
3487
3508
|
injectSender: injectSender ?? false,
|
|
3488
3509
|
platformAllowFrom: platformAllowFrom ?? {},
|
|
3510
|
+
providerRefs: providerRefs ?? [],
|
|
3489
3511
|
ccSyncError,
|
|
3490
3512
|
};
|
|
3491
3513
|
}
|
|
@@ -3557,6 +3579,10 @@ app.get<{ Params: { name: string } }>('/api/teams/:name/config', async (request,
|
|
|
3557
3579
|
typeof p.agent_mode === 'string' && p.agent_mode.trim().length > 0
|
|
3558
3580
|
? p.agent_mode.trim()
|
|
3559
3581
|
: permissionMode;
|
|
3582
|
+
const [providerRefs, globalProviders] = await Promise.all([
|
|
3583
|
+
cc.getProviderRefs(name).catch(() => []),
|
|
3584
|
+
cc.listProviders().catch(() => []),
|
|
3585
|
+
]);
|
|
3560
3586
|
return {
|
|
3561
3587
|
name,
|
|
3562
3588
|
color,
|
|
@@ -3572,6 +3598,8 @@ app.get<{ Params: { name: string } }>('/api/teams/:name/config', async (request,
|
|
|
3572
3598
|
injectSender: resolvedInjectSender,
|
|
3573
3599
|
permissionMode: resolvedPermissionMode,
|
|
3574
3600
|
platformAllowFrom: resolvedPlatformAllowFrom,
|
|
3601
|
+
providerRefs,
|
|
3602
|
+
globalProviders,
|
|
3575
3603
|
settings: {
|
|
3576
3604
|
...projectSettings,
|
|
3577
3605
|
language: resolvedLanguage,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DialogTitle,
|
|
11
11
|
} from '@renderer/components/ui/dialog';
|
|
12
12
|
import { Input } from '@renderer/components/ui/input';
|
|
13
|
+
import { emitOpenHermitEvent, OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
|
|
13
14
|
import { Loader2, RefreshCw } from 'lucide-react';
|
|
14
15
|
|
|
15
16
|
import type { CliProviderId, CliProviderStatus } from '@shared/types';
|
|
@@ -127,6 +128,7 @@ export const ProviderRuntimeSettingsDialog = ({
|
|
|
127
128
|
setNewProviderBaseUrl('');
|
|
128
129
|
setNewProviderApiKey('');
|
|
129
130
|
await refreshProviders();
|
|
131
|
+
emitOpenHermitEvent(OPEN_HERMIT_EVENTS.providersChanged);
|
|
130
132
|
} catch (err) {
|
|
131
133
|
setAddError(err instanceof Error ? err.message : '添加 Provider 失败');
|
|
132
134
|
} finally {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
DialogTitle,
|
|
11
11
|
} from '@renderer/components/ui/dialog';
|
|
12
12
|
import { Textarea } from '@renderer/components/ui/textarea';
|
|
13
|
+
import { emitOpenHermitEvent, OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
|
|
13
14
|
import appIcon from '@renderer/favicon.png';
|
|
14
15
|
import { Check, FileEdit, Loader2, RefreshCw, RotateCcw, X } from 'lucide-react';
|
|
15
16
|
|
|
@@ -147,6 +148,7 @@ export const AdvancedSection = ({}: AdvancedSectionProps): React.JSX.Element =>
|
|
|
147
148
|
setRestartMsg(null);
|
|
148
149
|
try {
|
|
149
150
|
await api.ccSettings.restart();
|
|
151
|
+
emitOpenHermitEvent(OPEN_HERMIT_EVENTS.runtimeRestarted);
|
|
150
152
|
setRestartMsg('已重启');
|
|
151
153
|
} catch {
|
|
152
154
|
setRestartMsg('重启失败');
|
|
@@ -30,6 +30,7 @@ import { useStore } from '@renderer/store';
|
|
|
30
30
|
import { createLoadingMultimodelCliStatus } from '@renderer/store/slices/cliInstallerSlice';
|
|
31
31
|
import { getMainScreenCliProviders } from '@renderer/utils/claudeCodeOnlyProviders';
|
|
32
32
|
import { formatBytes } from '@renderer/utils/formatters';
|
|
33
|
+
import { emitOpenHermitEvent, OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
|
|
33
34
|
import { resolveProjectPathById } from '@renderer/utils/projectLookup';
|
|
34
35
|
import { refreshCliStatusForCurrentMode } from '@renderer/utils/refreshCliStatus';
|
|
35
36
|
import { getRuntimeDisplayName } from '@renderer/utils/runtimeDisplayName';
|
|
@@ -747,6 +748,7 @@ const GenericHarnessProviderDialog = ({
|
|
|
747
748
|
setNewProviderBaseUrl('');
|
|
748
749
|
setNewProviderModel('');
|
|
749
750
|
onRefresh();
|
|
751
|
+
emitOpenHermitEvent(OPEN_HERMIT_EVENTS.providersChanged);
|
|
750
752
|
} catch (err) {
|
|
751
753
|
setAddProviderError(err instanceof Error ? err.message : '添加 Provider 失败');
|
|
752
754
|
} finally {
|
|
@@ -11,6 +11,7 @@ import { providersApi } from '@renderer/api/providers';
|
|
|
11
11
|
import { ALL_AGENT_TYPES, AGENT_TYPE_LABELS } from '@renderer/components/team/HarnessCards';
|
|
12
12
|
import type { CcAgentType } from '@renderer/components/team/HarnessCards';
|
|
13
13
|
import { cn } from '@renderer/lib/utils';
|
|
14
|
+
import { OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
|
|
14
15
|
import { CheckCircle2 } from 'lucide-react';
|
|
15
16
|
|
|
16
17
|
import { SettingsSectionHeader } from '../components/SettingsSectionHeader';
|
|
@@ -70,6 +71,16 @@ export const HarnessSection = (): React.JSX.Element => {
|
|
|
70
71
|
void refresh();
|
|
71
72
|
}, [refresh]);
|
|
72
73
|
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const handleProvidersChanged = () => {
|
|
76
|
+
void refresh();
|
|
77
|
+
};
|
|
78
|
+
window.addEventListener(OPEN_HERMIT_EVENTS.providersChanged, handleProvidersChanged);
|
|
79
|
+
return () => {
|
|
80
|
+
window.removeEventListener(OPEN_HERMIT_EVENTS.providersChanged, handleProvidersChanged);
|
|
81
|
+
};
|
|
82
|
+
}, [refresh]);
|
|
83
|
+
|
|
73
84
|
// Build coverage map: agent type -> list of sources (providers + projects)
|
|
74
85
|
const coveredTypes = new Map<CcAgentType, string[]>();
|
|
75
86
|
for (const type of ALL_AGENT_TYPES) {
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from '@renderer/components/ui/dialog';
|
|
20
20
|
import { Input } from '@renderer/components/ui/input';
|
|
21
21
|
import { Label } from '@renderer/components/ui/label';
|
|
22
|
+
import { emitOpenHermitEvent, OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
|
|
22
23
|
import {
|
|
23
24
|
Select,
|
|
24
25
|
SelectContent,
|
|
@@ -213,7 +214,9 @@ async function addPlatform(
|
|
|
213
214
|
restart_required?: boolean;
|
|
214
215
|
};
|
|
215
216
|
if (!json.ok) throw new Error(json.error ?? '添加失败');
|
|
216
|
-
return {
|
|
217
|
+
return {
|
|
218
|
+
restartRequired: json.data?.restart_required === true || json.restart_required === true,
|
|
219
|
+
};
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
// ---------------------------------------------------------------------------
|
|
@@ -490,7 +493,11 @@ function AddPlatformDialog({
|
|
|
490
493
|
else if (v === 'false') ccOptions[k] = false;
|
|
491
494
|
else ccOptions[k] = v;
|
|
492
495
|
}
|
|
493
|
-
const result = await addPlatform(
|
|
496
|
+
const result = await addPlatform(
|
|
497
|
+
projectName,
|
|
498
|
+
platformType,
|
|
499
|
+
ccOptions as Record<string, string>
|
|
500
|
+
);
|
|
494
501
|
onAdded(projectName);
|
|
495
502
|
if (result.restartRequired) {
|
|
496
503
|
const shouldRestart = await confirm({
|
|
@@ -501,6 +508,7 @@ function AddPlatformDialog({
|
|
|
501
508
|
});
|
|
502
509
|
if (shouldRestart) {
|
|
503
510
|
await api.ccSettings.restart();
|
|
511
|
+
emitOpenHermitEvent(OPEN_HERMIT_EVENTS.runtimeRestarted);
|
|
504
512
|
}
|
|
505
513
|
}
|
|
506
514
|
} catch (e) {
|
|
@@ -1618,16 +1618,13 @@ export const TeamDetailView = ({
|
|
|
1618
1618
|
);
|
|
1619
1619
|
|
|
1620
1620
|
const handleRestartTeamFromEdit = useCallback(async (): Promise<void> => {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
});
|
|
1629
|
-
await Promise.all([fetchTeams(), selectTeam(teamName)]);
|
|
1630
|
-
}, [data?.config.projectPath, fetchTeams, launchTeam, selectTeam, teamName]);
|
|
1621
|
+
await api.ccSettings.restart();
|
|
1622
|
+
// Wait for cc-connect to come back, then refresh
|
|
1623
|
+
setTimeout(() => {
|
|
1624
|
+
void fetchTeams();
|
|
1625
|
+
void selectTeam(teamName);
|
|
1626
|
+
}, 3000);
|
|
1627
|
+
}, [fetchTeams, selectTeam, teamName]);
|
|
1631
1628
|
|
|
1632
1629
|
const handleSaveAndRestartFromEdit = useCallback(
|
|
1633
1630
|
async (runtimeConfig: {
|
|
@@ -1832,21 +1829,12 @@ export const TeamDetailView = ({
|
|
|
1832
1829
|
try {
|
|
1833
1830
|
const result = await deleteTeam(teamName);
|
|
1834
1831
|
if (result.restartRequired) {
|
|
1835
|
-
|
|
1836
|
-
title: '重启 cc-connect',
|
|
1837
|
-
message: '团队已从配置中删除。需要重启 cc-connect 才会停止对应运行时。',
|
|
1838
|
-
confirmLabel: '立即重启',
|
|
1839
|
-
cancelLabel: '稍后重启',
|
|
1840
|
-
variant: 'danger',
|
|
1841
|
-
});
|
|
1842
|
-
if (shouldRestart) {
|
|
1843
|
-
await api.ccSettings.restart();
|
|
1844
|
-
}
|
|
1832
|
+
await api.ccSettings.restart();
|
|
1845
1833
|
}
|
|
1846
1834
|
if (tabId) closeTab(tabId);
|
|
1847
1835
|
openTeamsTab();
|
|
1848
|
-
} catch {
|
|
1849
|
-
|
|
1836
|
+
} catch (err) {
|
|
1837
|
+
console.error('Failed to delete team:', err);
|
|
1850
1838
|
}
|
|
1851
1839
|
})();
|
|
1852
1840
|
}, [teamName, deleteTeam, openTeamsTab, closeTab, tabId]);
|
|
@@ -2163,6 +2151,7 @@ export const TeamDetailView = ({
|
|
|
2163
2151
|
{isTeamProvisioning ? '团队仍在编排中,暂时无法编辑' : '编辑团队'}
|
|
2164
2152
|
</TooltipContent>
|
|
2165
2153
|
</Tooltip>
|
|
2154
|
+
{teamName !== 'default' && (
|
|
2166
2155
|
<Tooltip>
|
|
2167
2156
|
<TooltipTrigger asChild>
|
|
2168
2157
|
<Button
|
|
@@ -2176,6 +2165,7 @@ export const TeamDetailView = ({
|
|
|
2176
2165
|
</TooltipTrigger>
|
|
2177
2166
|
<TooltipContent side="bottom">删除团队</TooltipContent>
|
|
2178
2167
|
</Tooltip>
|
|
2168
|
+
)}
|
|
2179
2169
|
</div>
|
|
2180
2170
|
</div>
|
|
2181
2171
|
{data.config.description && (
|
|
@@ -2653,6 +2643,8 @@ export const TeamDetailView = ({
|
|
|
2653
2643
|
currentManagedSources={currentManagedSources}
|
|
2654
2644
|
currentDisabledCommands={currentDisabledCommands}
|
|
2655
2645
|
currentPlatformAllowFrom={currentPlatformAllowFrom}
|
|
2646
|
+
currentProviderRefs={data.providerRefs ?? []}
|
|
2647
|
+
globalProviders={data.globalProviders ?? []}
|
|
2656
2648
|
currentMembers={membersWithLiveBranches.filter((m) => !isLeadMember(m))}
|
|
2657
2649
|
leadMember={membersWithLiveBranches.find((m) => isLeadMember(m)) ?? null}
|
|
2658
2650
|
resolvedMemberColorMap={resolvedMemberColorMap}
|
|
@@ -2665,9 +2657,8 @@ export const TeamDetailView = ({
|
|
|
2665
2657
|
void fetchTeams();
|
|
2666
2658
|
void selectTeam(teamName);
|
|
2667
2659
|
}}
|
|
2668
|
-
onDeleteTeam={handleDeleteTeam}
|
|
2660
|
+
onDeleteTeam={teamName !== 'default' ? handleDeleteTeam : undefined}
|
|
2669
2661
|
onRestartTeam={handleRestartTeamFromEdit}
|
|
2670
|
-
onSaveAndRestart={handleSaveAndRestartFromEdit}
|
|
2671
2662
|
/>
|
|
2672
2663
|
|
|
2673
2664
|
<Dialog
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from '@renderer/store/utils/stateResetHelpers';
|
|
34
34
|
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
|
35
35
|
import { buildTaskCountsByTeam, normalizePath } from '@renderer/utils/pathNormalize';
|
|
36
|
+
import { emitOpenHermitEvent, OPEN_HERMIT_EVENTS } from '@renderer/utils/openHermitEvents';
|
|
36
37
|
import { getBaseName } from '@renderer/utils/pathUtils';
|
|
37
38
|
import { nameColorSet } from '@renderer/utils/projectColor';
|
|
38
39
|
import {
|
|
@@ -541,19 +542,11 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
541
542
|
try {
|
|
542
543
|
const result = await deleteTeam(teamName);
|
|
543
544
|
if (result.restartRequired) {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
message: '团队已从配置中删除。需要重启 cc-connect 才会停止对应运行时。',
|
|
547
|
-
confirmLabel: '立即重启',
|
|
548
|
-
cancelLabel: '稍后重启',
|
|
549
|
-
variant: 'danger',
|
|
550
|
-
});
|
|
551
|
-
if (shouldRestart) {
|
|
552
|
-
await api.ccSettings.restart();
|
|
553
|
-
}
|
|
545
|
+
await api.ccSettings.restart();
|
|
546
|
+
emitOpenHermitEvent(OPEN_HERMIT_EVENTS.runtimeRestarted);
|
|
554
547
|
}
|
|
555
|
-
} catch {
|
|
556
|
-
|
|
548
|
+
} catch (err) {
|
|
549
|
+
console.error('Failed to delete team:', err);
|
|
557
550
|
}
|
|
558
551
|
}
|
|
559
552
|
})();
|
|
@@ -674,6 +667,19 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
674
667
|
void fetchAllTasks();
|
|
675
668
|
}, [fetchTeams, fetchAllTasks]);
|
|
676
669
|
|
|
670
|
+
useEffect(() => {
|
|
671
|
+
const refresh = () => {
|
|
672
|
+
void fetchTeams();
|
|
673
|
+
void fetchAllTasks();
|
|
674
|
+
};
|
|
675
|
+
window.addEventListener(OPEN_HERMIT_EVENTS.runtimeRestarted, refresh);
|
|
676
|
+
window.addEventListener(OPEN_HERMIT_EVENTS.teamsChanged, refresh);
|
|
677
|
+
return () => {
|
|
678
|
+
window.removeEventListener(OPEN_HERMIT_EVENTS.runtimeRestarted, refresh);
|
|
679
|
+
window.removeEventListener(OPEN_HERMIT_EVENTS.teamsChanged, refresh);
|
|
680
|
+
};
|
|
681
|
+
}, [fetchTeams, fetchAllTasks]);
|
|
682
|
+
|
|
677
683
|
const taskCountsByTeam = useMemo(() => buildTaskCountsByTeam(globalTasks), [globalTasks]);
|
|
678
684
|
|
|
679
685
|
const activeTeams = useMemo<ActiveTeamRef[]>(() => {
|
|
@@ -798,6 +804,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
798
804
|
async (request: TeamCreateRequest) => {
|
|
799
805
|
await createTeam(request);
|
|
800
806
|
await Promise.all([fetchTeams(), fetchAllTasks()]);
|
|
807
|
+
emitOpenHermitEvent(OPEN_HERMIT_EVENTS.teamsChanged);
|
|
801
808
|
window.setTimeout(() => {
|
|
802
809
|
void fetchTeams();
|
|
803
810
|
void fetchAllTasks();
|
|
@@ -1165,6 +1172,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1165
1172
|
<TooltipContent side="bottom">复制团队</TooltipContent>
|
|
1166
1173
|
</Tooltip>
|
|
1167
1174
|
)}
|
|
1175
|
+
{team.teamName !== 'default' && (
|
|
1168
1176
|
<Tooltip>
|
|
1169
1177
|
<TooltipTrigger asChild>
|
|
1170
1178
|
<button
|
|
@@ -1179,6 +1187,7 @@ export const TeamListView = (): React.JSX.Element => {
|
|
|
1179
1187
|
</TooltipTrigger>
|
|
1180
1188
|
<TooltipContent side="bottom">删除团队</TooltipContent>
|
|
1181
1189
|
</Tooltip>
|
|
1190
|
+
)}
|
|
1182
1191
|
</div>
|
|
1183
1192
|
</div>
|
|
1184
1193
|
<div className="mt-2 flex min-h-10 items-start gap-2">
|
|
@@ -54,6 +54,9 @@ import PlatformManualForm from './PlatformManualForm';
|
|
|
54
54
|
|
|
55
55
|
import type { Project, TeamCreateRequest } from '@shared/types';
|
|
56
56
|
import type { CcAgentType } from '@shared/types/ccConnect';
|
|
57
|
+
import type { GlobalProvider } from '@shared/types/providers';
|
|
58
|
+
|
|
59
|
+
import { providersApi } from '@renderer/api/providers';
|
|
57
60
|
|
|
58
61
|
export interface ActiveTeamRef {
|
|
59
62
|
teamName: string;
|
|
@@ -252,6 +255,10 @@ export const CreateTeamDialog = ({
|
|
|
252
255
|
const [projectsLoading, setProjectsLoading] = useState(false);
|
|
253
256
|
const [projectsError, setProjectsError] = useState<string | null>(null);
|
|
254
257
|
|
|
258
|
+
// ── Global providers ─────────────────────────────────────────────────
|
|
259
|
+
const [globalProviders, setGlobalProviders] = useState<GlobalProvider[]>([]);
|
|
260
|
+
const [selectedProviderRef, setSelectedProviderRef] = useState<string | null>(null);
|
|
261
|
+
|
|
255
262
|
// ── Errors / submission ──────────────────────────────────────────────
|
|
256
263
|
const [localError, setLocalError] = useState<string | null>(null);
|
|
257
264
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
@@ -273,6 +280,27 @@ export const CreateTeamDialog = ({
|
|
|
273
280
|
: selectedProjectPath.trim()
|
|
274
281
|
: customCwd.trim();
|
|
275
282
|
|
|
283
|
+
const compatibleProviders = useMemo(
|
|
284
|
+
() =>
|
|
285
|
+
globalProviders.filter(
|
|
286
|
+
(p) => !p.agent_types || p.agent_types.length === 0 || p.agent_types.includes(selectedHarness)
|
|
287
|
+
),
|
|
288
|
+
[globalProviders, selectedHarness]
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
const selectProviderRef = (providerName: string) => {
|
|
292
|
+
setSelectedProviderRef((prev) => prev === providerName ? null : providerName);
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
// Clear selected provider when harness changes and it's no longer compatible
|
|
296
|
+
useEffect(() => {
|
|
297
|
+
setSelectedProviderRef((prev) => {
|
|
298
|
+
if (!prev) return prev;
|
|
299
|
+
const compatible = new Set(compatibleProviders.map((p) => p.name));
|
|
300
|
+
return compatible.has(prev) ? prev : null;
|
|
301
|
+
});
|
|
302
|
+
}, [compatibleProviders]);
|
|
303
|
+
|
|
276
304
|
const conflictingTeam = useMemo(() => {
|
|
277
305
|
if (!activeTeams?.length || !effectiveCwd) return null;
|
|
278
306
|
const norm = normalizePath(effectiveCwd);
|
|
@@ -309,6 +337,23 @@ export const CreateTeamDialog = ({
|
|
|
309
337
|
};
|
|
310
338
|
}, [open]);
|
|
311
339
|
|
|
340
|
+
// ── Load global providers on open ────────────────────────────────────
|
|
341
|
+
useEffect(() => {
|
|
342
|
+
if (!open) return;
|
|
343
|
+
let cancelled = false;
|
|
344
|
+
void (async () => {
|
|
345
|
+
try {
|
|
346
|
+
const result = await providersApi.list();
|
|
347
|
+
if (!cancelled) setGlobalProviders(result.providers ?? []);
|
|
348
|
+
} catch {
|
|
349
|
+
if (!cancelled) setGlobalProviders([]);
|
|
350
|
+
}
|
|
351
|
+
})();
|
|
352
|
+
return () => {
|
|
353
|
+
cancelled = true;
|
|
354
|
+
};
|
|
355
|
+
}, [open]);
|
|
356
|
+
|
|
312
357
|
// ── Auto-select default project path ─────────────────────────────────
|
|
313
358
|
useEffect(() => {
|
|
314
359
|
if (!open || cwdMode !== 'project' || selectedProjectPath) return;
|
|
@@ -337,6 +382,7 @@ export const CreateTeamDialog = ({
|
|
|
337
382
|
setFieldErrors({});
|
|
338
383
|
setIsSubmitting(false);
|
|
339
384
|
setConflictDismissed(false);
|
|
385
|
+
setSelectedProviderRef(null);
|
|
340
386
|
};
|
|
341
387
|
|
|
342
388
|
// ── Platform selection ───────────────────────────────────────────────
|
|
@@ -402,6 +448,7 @@ export const CreateTeamDialog = ({
|
|
|
402
448
|
harness: selectedHarness,
|
|
403
449
|
platform: selectedPlatform || 'bridge',
|
|
404
450
|
platformOptions: {},
|
|
451
|
+
providerRefs: selectedProviderRef ? [selectedProviderRef] : undefined,
|
|
405
452
|
};
|
|
406
453
|
await onCreate(request);
|
|
407
454
|
onOpenTeam(request.teamName, effectiveCwd || undefined);
|
|
@@ -527,6 +574,79 @@ export const CreateTeamDialog = ({
|
|
|
527
574
|
projectsError={projectsError}
|
|
528
575
|
fieldError={fieldErrors.cwd}
|
|
529
576
|
/>
|
|
577
|
+
|
|
578
|
+
{/* Provider selection */}
|
|
579
|
+
<div className="rounded-lg border border-[var(--color-border-subtle)] bg-white/[0.02] p-3">
|
|
580
|
+
<div className="flex items-start justify-between gap-3">
|
|
581
|
+
<div>
|
|
582
|
+
<p className="text-xs font-medium text-[var(--color-text)]">Provider(可选)</p>
|
|
583
|
+
<p className="mt-1 text-[11px] leading-relaxed text-[var(--color-text-muted)]">
|
|
584
|
+
留空时使用本机 {AGENT_TYPE_LABELS[selectedHarness] ?? selectedHarness} 默认配置和登录状态。
|
|
585
|
+
只有需要给该团队指定模型供应商时,才绑定下面的全局 Provider。
|
|
586
|
+
</p>
|
|
587
|
+
</div>
|
|
588
|
+
{selectedProviderRef ? (
|
|
589
|
+
<button
|
|
590
|
+
type="button"
|
|
591
|
+
className="shrink-0 rounded-md border border-[var(--color-border)] px-2 py-1 text-[11px] text-[var(--color-text-muted)] hover:bg-white/5"
|
|
592
|
+
onClick={() => setSelectedProviderRef(null)}
|
|
593
|
+
>
|
|
594
|
+
使用本机默认
|
|
595
|
+
</button>
|
|
596
|
+
) : null}
|
|
597
|
+
</div>
|
|
598
|
+
|
|
599
|
+
<div className="mt-3 space-y-2">
|
|
600
|
+
{compatibleProviders.length > 0 ? (
|
|
601
|
+
compatibleProviders.map((provider) => {
|
|
602
|
+
const checked = selectedProviderRef === provider.name;
|
|
603
|
+
const endpoint = provider.endpoints?.[selectedHarness] ?? provider.base_url ?? '默认端点';
|
|
604
|
+
const model =
|
|
605
|
+
provider.agent_models?.[selectedHarness] ??
|
|
606
|
+
provider.model ??
|
|
607
|
+
provider.models?.[0]?.model ??
|
|
608
|
+
'未指定模型';
|
|
609
|
+
return (
|
|
610
|
+
<button
|
|
611
|
+
key={provider.name}
|
|
612
|
+
type="button"
|
|
613
|
+
onClick={() => selectProviderRef(provider.name)}
|
|
614
|
+
className={`w-full rounded-lg border px-3 py-2 text-left transition-colors ${
|
|
615
|
+
checked
|
|
616
|
+
? 'border-indigo-400/60 bg-indigo-500/10'
|
|
617
|
+
: 'border-[var(--color-border-subtle)] bg-black/10 hover:border-[var(--color-border)] hover:bg-white/[0.04]'
|
|
618
|
+
}`}
|
|
619
|
+
>
|
|
620
|
+
<div className="flex items-center justify-between gap-3">
|
|
621
|
+
<div className="min-w-0">
|
|
622
|
+
<p className="truncate text-xs font-medium text-[var(--color-text)]">
|
|
623
|
+
{provider.name}
|
|
624
|
+
</p>
|
|
625
|
+
<p className="mt-0.5 truncate text-[11px] text-[var(--color-text-muted)]">
|
|
626
|
+
{model} · {endpoint}
|
|
627
|
+
</p>
|
|
628
|
+
</div>
|
|
629
|
+
<span
|
|
630
|
+
className={`shrink-0 rounded-full px-2 py-0.5 text-[10px] ${
|
|
631
|
+
checked
|
|
632
|
+
? 'bg-indigo-400/20 text-indigo-200'
|
|
633
|
+
: 'bg-white/5 text-[var(--color-text-muted)]'
|
|
634
|
+
}`}
|
|
635
|
+
>
|
|
636
|
+
{checked ? '已绑定' : '可绑定'}
|
|
637
|
+
</span>
|
|
638
|
+
</div>
|
|
639
|
+
</button>
|
|
640
|
+
);
|
|
641
|
+
})
|
|
642
|
+
) : (
|
|
643
|
+
<div className="rounded-md border border-dashed border-[var(--color-border)] px-3 py-3 text-xs text-[var(--color-text-muted)]">
|
|
644
|
+
暂无适用于 {AGENT_TYPE_LABELS[selectedHarness] ?? selectedHarness} 的全局 Provider。
|
|
645
|
+
可先在「设置 → Harness 配置」中添加;不添加也会使用本机默认登录态。
|
|
646
|
+
</div>
|
|
647
|
+
)}
|
|
648
|
+
</div>
|
|
649
|
+
</div>
|
|
530
650
|
</div>
|
|
531
651
|
)}
|
|
532
652
|
|