@yancyyu/openhermit 1.6.28 → 1.6.30
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/dist-renderer/assets/ProjectEditorOverlay-DsQt4FHy.js +52 -0
- package/dist-renderer/assets/{TeamGraphOverlay-Ba5njic5.js → TeamGraphOverlay-BjZC53xf.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-BvnK-OC1.js → _basePickBy-CrWocIjq.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-DmFYXx9G.js → _baseUniq-B6d8ysWi.js} +1 -1
- package/dist-renderer/assets/{arc-DX4ZQFY4.js → arc-DAIYCFP8.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DfYr3vEN.js → architectureDiagram-VXUJARFQ-B3UudXJh.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-DuXdVeWn.js → blockDiagram-VD42YOAC-DbptKQ4W.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-Bw2nixXe.js → c4Diagram-YG6GDRKO-C4WQuZpV.js} +1 -1
- package/dist-renderer/assets/channel-DbjZvWii.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-DLiNGQoE.js → chunk-4BX2VUAB-Dp7fVpI_.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-B1L_8VIF.js → chunk-55IACEB6-B8KGfbAy.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-DaZMWKGk.js → chunk-B4BG7PRW-BG1oJrjA.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-ku-dflJG.js → chunk-DI55MBZ5-DRmxNjht.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-DV-mF1dP.js → chunk-FMBD7UC4-D6VLvy16.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-ByGcDFQ0.js → chunk-QN33PNHL-DZou1667.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-7dv-Min8.js → chunk-QZHKN3VN-CghmasSh.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-WdXL5fTu.js → chunk-TZMSLE5B-B7apcMPK.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-D_FGxxsl.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-D_FGxxsl.js +1 -0
- package/dist-renderer/assets/clone-CJ1kxO2J.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-CNcsvqPl.js → cose-bilkent-S5V4N54A-05e5uQDp.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-DBNx4qqx.js → dagre-6UL2VRFP-B06bRykF.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-BfVlT6sT.js → diagram-PSM6KHXK-CY7VYQ7c.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-HvVjs0K6.js → diagram-QEK2KX5R-BjKEH7dD.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-DYb_KnWS.js → diagram-S2PKOQOG-Bf4ELS1_.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-Ba-IgI5G.js → erDiagram-Q2GNP2WA-DJ753_L9.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-2iDN8Kpj.js → flowDiagram-NV44I4VS-B71S-lC-.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-Byjf8Fa3.js → ganttDiagram-JELNMOA3-C_U42mSZ.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DbKvfZ_j.js → gitGraphDiagram-V2S2FVAM-DKUJU4Ns.js} +1 -1
- package/dist-renderer/assets/{graph-Enirf-f8.js → graph-DY3qbzqj.js} +1 -1
- package/dist-renderer/assets/{index-DY1zqsb6.js → index-BlOrAXp3.js} +551 -537
- package/dist-renderer/assets/{index-AjxP_rE_.js → index-Bs27J5gB.js} +1 -1
- package/dist-renderer/assets/{index-CtlzGepK.js → index-C8B_nKOF.js} +1 -1
- package/dist-renderer/assets/index-CmZPUEhS.css +1 -0
- package/dist-renderer/assets/{index-COZPUWJW.js → index-DLKyDr4T.js} +1 -1
- package/dist-renderer/assets/{index-DdhqolqE.js → index-Dhsk3_DD.js} +1 -1
- package/dist-renderer/assets/{index-ChR1D6ZF.js → index-GpUvV2xs.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D6uicwz1.js → infoDiagram-HS3SLOUP-BNs0y3IG.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DqwZsXlQ.js → journeyDiagram-XKPGCS4Q-CqPnw4UV.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-fCDVhVUm.js → kanban-definition-3W4ZIXB7-SLlzcUJ2.js} +1 -1
- package/dist-renderer/assets/{layout-CPFgj98r.js → layout-BZLlNmbr.js} +1 -1
- package/dist-renderer/assets/{linear-CYiQ7Y3M.js → linear-qz6v45xy.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-D31dS2KE.js → mindmap-definition-VGOIOE7T-B1-kmEWV.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-BOsCJfds.js → pieDiagram-ADFJNKIX-B8a02iNx.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CYTVQCfr.js → quadrantDiagram-AYHSOK5B-BKv1Xfou.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-CODCFpkt.js → requirementDiagram-UZGBJVZJ-B3DUpZi2.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-Z4ce9ZtZ.js → sankeyDiagram-TZEHDZUN-DmPzuTsy.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-CmS9TxhW.js → sequenceDiagram-WL72ISMW-Bo7RelRb.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-o9k-ns3q.js → stateDiagram-FKZM4ZOC-1epX98gV.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-CxHMyEt1.js → stateDiagram-v2-4FDKWEC3-03Ym9PTr.js} +1 -1
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-B6T3zrde.js → timeline-definition-IT6M3QCI-r6isC62H.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-CVd5GNDw.js → treemap-GDKQZRPO-CGKpOUF2.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-CleBrdqc.js → xychartDiagram-PRI3JC2R-t4-rwdAw.js} +1 -1
- package/dist-renderer/index.html +2 -2
- package/package.json +4 -1
- package/src/main/ipc/extensions.ts +353 -0
- package/src/main/server.ts +907 -184
- package/src/main/services/extensions/ExtensionFacadeService.ts +135 -0
- package/src/main/services/extensions/catalog/GlamaMcpEnrichmentService.ts +190 -0
- package/src/main/services/extensions/catalog/McpCatalogAggregator.ts +150 -0
- package/src/main/services/extensions/catalog/OfficialMcpRegistryService.ts +381 -0
- package/src/main/services/extensions/catalog/PluginCatalogService.ts +392 -0
- package/src/main/services/extensions/credentials/CredentialService.ts +343 -0
- package/src/main/services/extensions/install/McpInstallService.ts +407 -0
- package/src/main/services/extensions/install/PluginInstallService.ts +198 -0
- package/src/main/services/extensions/runtime/ClaudeCodeAdapter.ts +199 -0
- package/src/main/services/extensions/runtime/CodexAdapter.ts +100 -0
- package/src/main/services/extensions/runtime/CursorAdapter.ts +154 -0
- package/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts +172 -0
- package/src/main/services/extensions/runtime/GeminiAdapter.ts +91 -0
- package/src/main/services/extensions/runtime/HarnessInstallAdapter.ts +49 -0
- package/src/main/services/extensions/runtime/McpConfigStateReader.ts +209 -0
- package/src/main/services/extensions/runtime/OpenCodeAdapter.ts +91 -0
- package/src/main/services/extensions/runtime/adapterRegistry.ts +54 -0
- package/src/main/services/extensions/runtime/mcpDiagnosticsParser.ts +214 -0
- package/src/main/services/extensions/runtime/mcpRuntimeJson.ts +45 -0
- package/src/main/services/extensions/skills/SkillImportService.ts +155 -0
- package/src/main/services/extensions/skills/SkillMetadataParser.ts +323 -0
- package/src/main/services/extensions/skills/SkillPlanService.ts +411 -0
- package/src/main/services/extensions/skills/SkillReviewService.ts +73 -0
- package/src/main/services/extensions/skills/SkillRootsResolver.ts +49 -0
- package/src/main/services/extensions/skills/SkillScaffoldService.ts +89 -0
- package/src/main/services/extensions/skills/SkillScanner.ts +117 -0
- package/src/main/services/extensions/skills/SkillValidator.ts +69 -0
- package/src/main/services/extensions/skills/SkillsCatalogService.ts +92 -0
- package/src/main/services/extensions/skills/SkillsMutationService.ts +146 -0
- package/src/main/services/extensions/skills/SkillsWatcherService.ts +134 -0
- package/src/main/services/extensions/state/McpInstallationStateService.ts +42 -0
- package/src/main/services/extensions/state/PluginInstallationStateService.ts +281 -0
- package/src/main/services/identity/AgentTeamsIdentityStore.ts +218 -0
- package/src/main/services/runtime/providerAwareCliEnv.ts +60 -0
- package/src/main/services/session-intelligence/UsageTelemetryService.ts +33 -18
- package/src/main/services/team/ClaudeBinaryResolver.ts +469 -0
- package/src/main/services/team/ClaudeDoctorProbe.ts +0 -0
- package/src/main/services/team/cliFlavor.ts +54 -0
- package/src/main/services/teams-mvp/CollaborationBoardService.ts +310 -0
- package/src/main/services/teams-mvp/TaskDispatchService.ts +883 -95
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +58 -19
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +25 -2
- package/src/main/services/teams-mvp/index.ts +3 -0
- package/src/main/utils/atomicWrite.ts +72 -0
- package/src/main/utils/childProcess.ts +554 -0
- package/src/main/utils/cliEnv.ts +54 -0
- package/src/main/utils/cliPathMerge.ts +97 -0
- package/src/main/utils/pathDecoder.ts +664 -0
- package/src/main/utils/pathValidation.ts +432 -0
- package/src/main/utils/shellEnv.ts +331 -0
- package/src/renderer/App.tsx +5 -0
- package/src/renderer/api/httpClient.ts +128 -0
- package/src/renderer/components/extensions/ExtensionStoreView.tsx +59 -34
- package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
- package/src/renderer/components/extensions/common/ExtensionToast.tsx +141 -0
- package/src/renderer/components/extensions/common/HarnessSelector.tsx +71 -0
- package/src/renderer/components/extensions/env/EnvVarPanel.tsx +335 -0
- package/src/renderer/components/extensions/env/ProjectEnvPanel.tsx +239 -0
- package/src/renderer/components/extensions/mcp/CustomMcpServerDialog.tsx +14 -223
- package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +11 -0
- package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +51 -1
- package/src/renderer/components/extensions/skills/SkillsPanel.tsx +1 -126
- package/src/renderer/components/layout/PaneContent.tsx +2 -0
- package/src/renderer/components/layout/SortableTab.tsx +1 -0
- package/src/renderer/components/layout/TabBarActions.tsx +12 -12
- package/src/renderer/components/schedules/SchedulesView.tsx +54 -22
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +1 -1
- package/src/renderer/components/settings/sections/HarnessSection.tsx +2 -6
- package/src/renderer/components/settings/sections/TaskBusSection.tsx +144 -84
- package/src/renderer/components/sidebar/SidebarSessions.tsx +23 -0
- package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +1 -7
- package/src/renderer/components/tasks/TasksView.tsx +343 -0
- package/src/renderer/components/team/HarnessSelect.tsx +71 -0
- package/src/renderer/components/team/TeamDetailView.tsx +55 -98
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +21 -12
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +8 -13
- package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +1 -1
- package/src/renderer/components/team/editor/EditorContextMenu.tsx +8 -23
- package/src/renderer/components/team/editor/EditorFileTree.tsx +0 -4
- package/src/renderer/components/team/editor/EditorSelectionMenu.tsx +1 -8
- package/src/renderer/components/team/editor/ProjectEditorOverlay.tsx +0 -10
- package/src/renderer/components/team/kanban/KanbanBoard.tsx +31 -65
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +8 -33
- package/src/renderer/components/team/messages/MessageComposer.tsx +39 -3
- package/src/renderer/components/team/messages/MessagesPanel.tsx +100 -26
- package/src/renderer/components/team/messages/StatusBlock.tsx +2 -24
- package/src/renderer/components/team/schedule/ScheduleEmptyState.tsx +1 -1
- package/src/renderer/components/terminal/TerminalPanel.tsx +156 -0
- package/src/renderer/components/ui/MentionableTextarea.tsx +0 -1
- package/src/renderer/hooks/useExtensionsTabState.ts +2 -2
- package/src/renderer/store/slices/extensionsSlice.ts +42 -107
- package/src/renderer/store/slices/scheduleSlice.ts +21 -0
- package/src/renderer/store/slices/teamSlice.ts +67 -25
- package/src/renderer/types/tabs.ts +1 -0
- package/src/shared/types/api.ts +58 -0
- package/src/shared/types/extensions/index.ts +1 -0
- package/src/shared/types/extensions/mcp.ts +2 -0
- package/src/shared/types/extensions/plugin.ts +2 -1
- package/src/shared/types/extensions/skill.ts +7 -0
- package/src/shared/types/team.ts +104 -1
- package/src/shared/utils/providerExtensionCapabilities.ts +1 -1
- package/dist-renderer/assets/ProjectEditorOverlay-A4DZTvSy.js +0 -57
- package/dist-renderer/assets/channel-Pre42N5O.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-CdJsTJsj.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CdJsTJsj.js +0 -1
- package/dist-renderer/assets/clone-BjQBiNfj.js +0 -1
- package/dist-renderer/assets/index-BIOJremZ.css +0 -1
- package/src/features/recent-projects/main/adapters/input/http/registerRecentProjectsHttp.ts +0 -30
- package/src/features/recent-projects/main/adapters/output/presenters/DashboardRecentProjectsPresenter.ts +0 -27
- package/src/features/recent-projects/main/adapters/output/sources/ClaudeRecentProjectsSourceAdapter.ts +0 -91
- package/src/features/recent-projects/main/adapters/output/sources/CodexRecentProjectsSourceAdapter.ts +0 -326
- package/src/features/recent-projects/main/composition/createRecentProjectsFeature.ts +0 -43
- package/src/features/recent-projects/main/index.ts +0 -3
- package/src/features/recent-projects/main/infrastructure/cache/InMemoryRecentProjectsCache.ts +0 -34
- package/src/features/recent-projects/main/infrastructure/codex/CodexAppServerClient.ts +0 -116
- package/src/features/recent-projects/main/infrastructure/identity/RecentProjectIdentityResolver.ts +0 -20
- package/src/features/recent-projects/main/infrastructure/identity/normalizeIdentityPath.ts +0 -10
- package/src/renderer/components/extensions/apikeys/ApiKeyCard.tsx +0 -143
- package/src/renderer/components/extensions/apikeys/ApiKeyFormDialog.tsx +0 -282
- package/src/renderer/components/extensions/apikeys/ApiKeysPanel.tsx +0 -280
|
@@ -202,7 +202,9 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
202
202
|
const [connected, setConnected] = useState(false);
|
|
203
203
|
const [message, setMessage] = useState<string | null>(null);
|
|
204
204
|
|
|
205
|
-
const [
|
|
205
|
+
const [collectionEnabled, setCollectionEnabled] = useState(false);
|
|
206
|
+
const [uploadEnabled, setUploadEnabled] = useState(false);
|
|
207
|
+
const [collaborationEnabled, setCollaborationEnabled] = useState(false);
|
|
206
208
|
const [telemetryPlatform, setTelemetryPlatform] = useState('claudecode');
|
|
207
209
|
const [scanning, setScanning] = useState(false);
|
|
208
210
|
const [telemetryStatus, setTelemetryStatus] = useState<TelemetryStatus | null>(null);
|
|
@@ -218,44 +220,60 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
218
220
|
setPassword(data.redis.password ?? '');
|
|
219
221
|
}
|
|
220
222
|
if (data.telemetry) {
|
|
221
|
-
|
|
223
|
+
setCollectionEnabled(data.telemetry.enabled);
|
|
224
|
+
setUploadEnabled(data.telemetry.uploadEnabled ?? false);
|
|
222
225
|
setTelemetryPlatform(data.telemetry.platform ?? 'claudecode');
|
|
223
226
|
}
|
|
227
|
+
setCollaborationEnabled(data.collaboration ?? false);
|
|
224
228
|
})
|
|
225
229
|
.catch(() => {})
|
|
226
230
|
.finally(() => setLoading(false));
|
|
227
231
|
|
|
228
232
|
// Restore telemetry status + Redis connection state on mount
|
|
229
|
-
fetch('/api/
|
|
233
|
+
fetch('/api/settings/task-bus')
|
|
230
234
|
.then((r) => r.json())
|
|
231
|
-
.then((
|
|
232
|
-
if (
|
|
233
|
-
|
|
235
|
+
.then((busConfig: TaskBusConfig) => {
|
|
236
|
+
if (busConfig.enabled) {
|
|
237
|
+
fetch('/api/telemetry/status')
|
|
238
|
+
.then((r) => r.json())
|
|
239
|
+
.then((s: TelemetryStatus) => {
|
|
240
|
+
if (s.connected) setConnected(true);
|
|
241
|
+
if ('sessions' in s && s.sessions > 0) setTelemetryStatus(s);
|
|
242
|
+
})
|
|
243
|
+
.catch(() => {});
|
|
244
|
+
}
|
|
234
245
|
})
|
|
235
246
|
.catch(() => {});
|
|
236
247
|
|
|
237
248
|
const poll = setInterval(() => {
|
|
238
|
-
if (
|
|
249
|
+
if (enabled && collectionEnabled) {
|
|
239
250
|
fetch('/api/telemetry/status')
|
|
240
251
|
.then((r) => r.json())
|
|
241
|
-
.then((s: TelemetryStatus) =>
|
|
252
|
+
.then((s: TelemetryStatus) => {
|
|
253
|
+
setTelemetryStatus(s);
|
|
254
|
+
setConnected(s.connected === true);
|
|
255
|
+
})
|
|
242
256
|
.catch(() => {});
|
|
243
257
|
}
|
|
244
258
|
}, 30000);
|
|
245
259
|
return () => clearInterval(poll);
|
|
246
|
-
}, [
|
|
260
|
+
}, [enabled, collectionEnabled]);
|
|
247
261
|
|
|
248
262
|
const buildConfig = (
|
|
249
263
|
overrides: Partial<{
|
|
250
264
|
enabled: boolean;
|
|
251
|
-
|
|
265
|
+
collectionEnabled: boolean;
|
|
266
|
+
uploadEnabled: boolean;
|
|
267
|
+
collaborationEnabled: boolean;
|
|
252
268
|
telemetryPlatform: string;
|
|
253
269
|
}> = {}
|
|
254
270
|
): TaskBusConfig => ({
|
|
255
271
|
enabled: overrides.enabled ?? enabled,
|
|
256
272
|
redis: { host, port, password: password || undefined },
|
|
273
|
+
collaboration: overrides.collaborationEnabled ?? collaborationEnabled,
|
|
257
274
|
telemetry: {
|
|
258
|
-
enabled: overrides.
|
|
275
|
+
enabled: overrides.collectionEnabled ?? collectionEnabled,
|
|
276
|
+
uploadEnabled: overrides.uploadEnabled ?? uploadEnabled,
|
|
259
277
|
platform: (overrides.telemetryPlatform ?? telemetryPlatform) as 'claudecode',
|
|
260
278
|
},
|
|
261
279
|
});
|
|
@@ -296,45 +314,58 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
296
314
|
.catch(() => setMessage('操作失败'));
|
|
297
315
|
};
|
|
298
316
|
|
|
299
|
-
const
|
|
317
|
+
const toggleCollection = async (value: boolean) => {
|
|
318
|
+
setCollectionEnabled(value);
|
|
319
|
+
const config = buildConfig({ collectionEnabled: value });
|
|
320
|
+
try {
|
|
321
|
+
await fetch('/api/settings/task-bus', {
|
|
322
|
+
method: 'PUT',
|
|
323
|
+
headers: { 'Content-Type': 'application/json' },
|
|
324
|
+
body: JSON.stringify(config),
|
|
325
|
+
});
|
|
326
|
+
if (value) triggerScan();
|
|
327
|
+
else setTelemetryStatus(null);
|
|
328
|
+
} catch {
|
|
329
|
+
setCollectionEnabled(!value);
|
|
330
|
+
setMessage('操作失败');
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
const toggleUpload = async (value: boolean) => {
|
|
300
335
|
if (!value) {
|
|
301
|
-
|
|
302
|
-
const config = buildConfig({
|
|
336
|
+
setUploadEnabled(false);
|
|
337
|
+
const config = buildConfig({ uploadEnabled: false });
|
|
303
338
|
fetch('/api/settings/task-bus', {
|
|
304
339
|
method: 'PUT',
|
|
305
340
|
headers: { 'Content-Type': 'application/json' },
|
|
306
341
|
body: JSON.stringify(config),
|
|
307
342
|
}).catch(() => setMessage('操作失败'));
|
|
308
|
-
setTelemetryStatus(null);
|
|
309
343
|
return;
|
|
310
344
|
}
|
|
311
345
|
|
|
312
|
-
//
|
|
313
|
-
setTelemetryEnabled(true);
|
|
314
|
-
|
|
315
|
-
// Test Redis if not already connected
|
|
346
|
+
// Upload requires Redis
|
|
316
347
|
let redisReady = connected;
|
|
317
348
|
if (!redisReady) {
|
|
318
349
|
setMessage('正在测试 Redis 连接...');
|
|
319
350
|
redisReady = await testRedisConnection();
|
|
320
351
|
if (!redisReady) {
|
|
321
|
-
|
|
352
|
+
setUploadEnabled(false);
|
|
322
353
|
setMessage('Redis 连接失败,无法启用数据上报');
|
|
323
354
|
return;
|
|
324
355
|
}
|
|
325
356
|
}
|
|
326
357
|
|
|
358
|
+
setUploadEnabled(true);
|
|
327
359
|
setMessage(null);
|
|
328
|
-
const config = buildConfig({
|
|
360
|
+
const config = buildConfig({ uploadEnabled: true });
|
|
329
361
|
try {
|
|
330
362
|
await fetch('/api/settings/task-bus', {
|
|
331
363
|
method: 'PUT',
|
|
332
364
|
headers: { 'Content-Type': 'application/json' },
|
|
333
365
|
body: JSON.stringify(config),
|
|
334
366
|
});
|
|
335
|
-
triggerScan();
|
|
336
367
|
} catch {
|
|
337
|
-
|
|
368
|
+
setUploadEnabled(false);
|
|
338
369
|
setMessage('操作失败');
|
|
339
370
|
}
|
|
340
371
|
};
|
|
@@ -349,7 +380,7 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
349
380
|
setTelemetryStatus(result);
|
|
350
381
|
}
|
|
351
382
|
})
|
|
352
|
-
.catch(() => setMessage('
|
|
383
|
+
.catch(() => setMessage('采集失败,请检查本地 Claude Code 会话目录'))
|
|
353
384
|
.finally(() => setScanning(false));
|
|
354
385
|
};
|
|
355
386
|
|
|
@@ -362,6 +393,18 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
362
393
|
}).catch(() => {});
|
|
363
394
|
};
|
|
364
395
|
|
|
396
|
+
const toggleCollaboration = (value: boolean) => {
|
|
397
|
+
setCollaborationEnabled(value);
|
|
398
|
+
const config = buildConfig({ collaborationEnabled: value });
|
|
399
|
+
fetch('/api/settings/task-bus', {
|
|
400
|
+
method: 'PUT',
|
|
401
|
+
headers: { 'Content-Type': 'application/json' },
|
|
402
|
+
body: JSON.stringify(config),
|
|
403
|
+
})
|
|
404
|
+
.then(() => setMessage(value ? '已开启分布式团队协作' : '已关闭分布式团队协作'))
|
|
405
|
+
.catch(() => setMessage('操作失败'));
|
|
406
|
+
};
|
|
407
|
+
|
|
365
408
|
if (loading) {
|
|
366
409
|
return (
|
|
367
410
|
<div className="flex items-center justify-center py-12">
|
|
@@ -372,11 +415,65 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
372
415
|
|
|
373
416
|
return (
|
|
374
417
|
<div>
|
|
418
|
+
<SettingsSectionHeader title="本地数据采集" icon={<BarChart3 size={12} />} />
|
|
419
|
+
|
|
420
|
+
<SettingRow
|
|
421
|
+
label="数据采集"
|
|
422
|
+
description="扫描本机 ~/.claude/projects 会话文件,采集使用指标;不需要 Redis,也不会上传对话内容"
|
|
423
|
+
>
|
|
424
|
+
<div className="flex items-center gap-2">
|
|
425
|
+
<select
|
|
426
|
+
value={telemetryPlatform}
|
|
427
|
+
onChange={(e) => {
|
|
428
|
+
const nextPlatform = e.target.value;
|
|
429
|
+
setTelemetryPlatform(nextPlatform);
|
|
430
|
+
saveTelemetryPlatform(nextPlatform);
|
|
431
|
+
}}
|
|
432
|
+
className="rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2 py-1 text-xs outline-none focus:border-indigo-500/50"
|
|
433
|
+
>
|
|
434
|
+
<option value="claudecode">Claude Code</option>
|
|
435
|
+
</select>
|
|
436
|
+
<SettingsToggle
|
|
437
|
+
enabled={collectionEnabled}
|
|
438
|
+
onChange={(value) => void toggleCollection(value)}
|
|
439
|
+
/>
|
|
440
|
+
</div>
|
|
441
|
+
</SettingRow>
|
|
442
|
+
|
|
443
|
+
{collectionEnabled && (
|
|
444
|
+
<>
|
|
445
|
+
<div
|
|
446
|
+
className="flex items-center gap-3 border-b py-3"
|
|
447
|
+
style={{ borderColor: 'var(--color-border-subtle)' }}
|
|
448
|
+
>
|
|
449
|
+
<Button
|
|
450
|
+
size="sm"
|
|
451
|
+
variant="outline"
|
|
452
|
+
onClick={triggerScan}
|
|
453
|
+
disabled={scanning}
|
|
454
|
+
className="gap-1.5"
|
|
455
|
+
>
|
|
456
|
+
{scanning ? <Loader2 size={12} className="animate-spin" /> : <BarChart3 size={12} />}
|
|
457
|
+
{scanning ? '采集中...' : '立即采集'}
|
|
458
|
+
</Button>
|
|
459
|
+
<span className="text-[10px] text-[var(--color-text-muted)]">
|
|
460
|
+
本地扫描,不依赖团队总线或 Redis。
|
|
461
|
+
</span>
|
|
462
|
+
</div>
|
|
463
|
+
|
|
464
|
+
{telemetryStatus && (
|
|
465
|
+
<div className="py-3">
|
|
466
|
+
<UsageDashboard status={telemetryStatus} />
|
|
467
|
+
</div>
|
|
468
|
+
)}
|
|
469
|
+
</>
|
|
470
|
+
)}
|
|
471
|
+
|
|
375
472
|
<SettingsSectionHeader title="团队总线" icon={<Radio size={12} />} />
|
|
376
473
|
|
|
377
474
|
<SettingRow
|
|
378
475
|
label="启用团队总线"
|
|
379
|
-
description="
|
|
476
|
+
description="用于 Redis 连接、数据上报和跨团队协作;本地数据采集不依赖它"
|
|
380
477
|
>
|
|
381
478
|
<SettingsToggle enabled={enabled} onChange={toggle} />
|
|
382
479
|
</SettingRow>
|
|
@@ -388,7 +485,9 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
388
485
|
<div className="flex items-center gap-2 px-1 pb-2">
|
|
389
486
|
<span className="text-sm font-medium text-red-500">*</span>
|
|
390
487
|
<span className="text-sm font-medium">Redis</span>
|
|
391
|
-
<span className="text-xs text-[var(--color-text-muted)]"
|
|
488
|
+
<span className="text-xs text-[var(--color-text-muted)]">
|
|
489
|
+
(上报和跨团队协作必填)
|
|
490
|
+
</span>
|
|
392
491
|
<div className="ml-auto flex items-center gap-2">
|
|
393
492
|
{connected ? (
|
|
394
493
|
<span className="flex items-center gap-1 text-xs text-emerald-500">
|
|
@@ -465,78 +564,39 @@ export function TaskBusSection(): React.JSX.Element {
|
|
|
465
564
|
</div>
|
|
466
565
|
</div>
|
|
467
566
|
|
|
468
|
-
{/*
|
|
469
|
-
<div
|
|
470
|
-
<SettingRow
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
<select
|
|
476
|
-
value={telemetryPlatform}
|
|
477
|
-
onChange={(e) => {
|
|
478
|
-
const nextPlatform = e.target.value;
|
|
479
|
-
setTelemetryPlatform(nextPlatform);
|
|
480
|
-
saveTelemetryPlatform(nextPlatform);
|
|
481
|
-
}}
|
|
482
|
-
className="rounded-md border border-[var(--color-border)] bg-[var(--color-bg)] px-2 py-1 text-xs outline-none focus:border-indigo-500/50"
|
|
483
|
-
>
|
|
484
|
-
<option value="claudecode">Claude Code</option>
|
|
485
|
-
</select>
|
|
486
|
-
<SettingsToggle
|
|
487
|
-
enabled={telemetryEnabled}
|
|
488
|
-
onChange={(value) => void toggleTelemetry(value)}
|
|
489
|
-
/>
|
|
490
|
-
</div>
|
|
567
|
+
{/* 数据上报 - 依赖 Redis,最下面 */}
|
|
568
|
+
<div>
|
|
569
|
+
<SettingRow label="数据上报" description="将采集数据上报到 Redis,供团队看板使用">
|
|
570
|
+
<SettingsToggle
|
|
571
|
+
enabled={uploadEnabled}
|
|
572
|
+
onChange={(value) => void toggleUpload(value)}
|
|
573
|
+
/>
|
|
491
574
|
</SettingRow>
|
|
492
575
|
|
|
493
|
-
{
|
|
494
|
-
|
|
495
|
-
<
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
variant="outline"
|
|
499
|
-
onClick={triggerScan}
|
|
500
|
-
disabled={scanning}
|
|
501
|
-
className="gap-1.5"
|
|
502
|
-
>
|
|
503
|
-
{scanning ? (
|
|
504
|
-
<Loader2 size={12} className="animate-spin" />
|
|
505
|
-
) : (
|
|
506
|
-
<BarChart3 size={12} />
|
|
507
|
-
)}
|
|
508
|
-
{scanning ? '采集中...' : '立即采集'}
|
|
509
|
-
</Button>
|
|
510
|
-
<span className="text-[10px] text-[var(--color-text-muted)]">
|
|
511
|
-
扫描本地 ~/.claude/projects 下的会话文件
|
|
512
|
-
</span>
|
|
513
|
-
</div>
|
|
514
|
-
|
|
515
|
-
{telemetryStatus && (
|
|
516
|
-
<div className="py-3">
|
|
517
|
-
<UsageDashboard status={telemetryStatus} />
|
|
518
|
-
</div>
|
|
519
|
-
)}
|
|
520
|
-
</>
|
|
576
|
+
{!connected && (
|
|
577
|
+
<div className="flex items-center gap-2 px-1 py-2 text-xs text-amber-500">
|
|
578
|
+
<AlertCircle size={12} />
|
|
579
|
+
<span>数据上报需要 Redis;请先配置并测试 Redis 连接。</span>
|
|
580
|
+
</div>
|
|
521
581
|
)}
|
|
522
582
|
</div>
|
|
523
583
|
|
|
524
|
-
{/*
|
|
584
|
+
{/* 分布式团队协作 - 最下面 */}
|
|
525
585
|
<div>
|
|
526
586
|
<SettingRow
|
|
527
|
-
label="
|
|
528
|
-
description="
|
|
587
|
+
label="分布式团队协作"
|
|
588
|
+
description="开启后 Hermit 平台识别 @团队 并创建跨团队协作任务;Agent 只读取团队列表,不直接派发"
|
|
529
589
|
>
|
|
530
590
|
<SettingsToggle
|
|
531
|
-
enabled={
|
|
532
|
-
onChange={(value) => void
|
|
591
|
+
enabled={collaborationEnabled}
|
|
592
|
+
onChange={(value) => void toggleCollaboration(value)}
|
|
533
593
|
/>
|
|
534
594
|
</SettingRow>
|
|
535
595
|
|
|
536
|
-
{!connected && (
|
|
596
|
+
{!connected && collaborationEnabled && (
|
|
537
597
|
<div className="flex items-center gap-2 px-1 py-2 text-xs text-amber-500">
|
|
538
598
|
<AlertCircle size={12} />
|
|
539
|
-
<span
|
|
599
|
+
<span>跨团队协作需要 Redis 连接。</span>
|
|
540
600
|
</div>
|
|
541
601
|
)}
|
|
542
602
|
</div>
|
|
@@ -402,6 +402,29 @@ const SessionRow = ({
|
|
|
402
402
|
};
|
|
403
403
|
}, [historyLimit, isExpanded, session.teamName, session.id]);
|
|
404
404
|
|
|
405
|
+
// While a live session stays expanded, keep its detail fresh with a silent
|
|
406
|
+
// refetch (no skeleton flash) so newly arrived messages show without needing
|
|
407
|
+
// to collapse and reopen.
|
|
408
|
+
useEffect(() => {
|
|
409
|
+
if (!isExpanded || !session.live) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const intervalId = window.setInterval(() => {
|
|
413
|
+
if (document.visibilityState !== 'visible') {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
void (async () => {
|
|
417
|
+
try {
|
|
418
|
+
const d = await api.teams.getSessionDetail(session.teamName, session.id, historyLimit);
|
|
419
|
+
setDetail(d);
|
|
420
|
+
} catch {
|
|
421
|
+
// silent — transient fetch failures are retried on the next tick
|
|
422
|
+
}
|
|
423
|
+
})();
|
|
424
|
+
}, REFRESH_INTERVAL_MS);
|
|
425
|
+
return () => window.clearInterval(intervalId);
|
|
426
|
+
}, [isExpanded, session.live, session.teamName, session.id, historyLimit]);
|
|
427
|
+
|
|
405
428
|
const handleLoadMoreHistory = useCallback(() => {
|
|
406
429
|
if (loadingDetail || loadingMoreHistory || !hasMoreHistory) {
|
|
407
430
|
return;
|
|
@@ -217,13 +217,7 @@ const TeamWorkspace = ({
|
|
|
217
217
|
<button
|
|
218
218
|
key={entry.name}
|
|
219
219
|
type="button"
|
|
220
|
-
className=
|
|
221
|
-
entry.isDirectory
|
|
222
|
-
? 'cursor-pointer hover:bg-[var(--color-surface-raised)]'
|
|
223
|
-
: onFileClick
|
|
224
|
-
? 'cursor-pointer hover:bg-[var(--color-surface-raised)]'
|
|
225
|
-
: 'hover:bg-[var(--color-surface-raised)]/50 cursor-default'
|
|
226
|
-
}`}
|
|
220
|
+
className="flex w-full cursor-pointer items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors hover:bg-[var(--color-surface-raised)]"
|
|
227
221
|
onClick={() => handleEntryClick(entry)}
|
|
228
222
|
>
|
|
229
223
|
{entry.isDirectory ? (
|