@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.
Files changed (177) hide show
  1. package/dist-renderer/assets/ProjectEditorOverlay-DsQt4FHy.js +52 -0
  2. package/dist-renderer/assets/{TeamGraphOverlay-Ba5njic5.js → TeamGraphOverlay-BjZC53xf.js} +1 -1
  3. package/dist-renderer/assets/{_basePickBy-BvnK-OC1.js → _basePickBy-CrWocIjq.js} +1 -1
  4. package/dist-renderer/assets/{_baseUniq-DmFYXx9G.js → _baseUniq-B6d8ysWi.js} +1 -1
  5. package/dist-renderer/assets/{arc-DX4ZQFY4.js → arc-DAIYCFP8.js} +1 -1
  6. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DfYr3vEN.js → architectureDiagram-VXUJARFQ-B3UudXJh.js} +1 -1
  7. package/dist-renderer/assets/{blockDiagram-VD42YOAC-DuXdVeWn.js → blockDiagram-VD42YOAC-DbptKQ4W.js} +1 -1
  8. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-Bw2nixXe.js → c4Diagram-YG6GDRKO-C4WQuZpV.js} +1 -1
  9. package/dist-renderer/assets/channel-DbjZvWii.js +1 -0
  10. package/dist-renderer/assets/{chunk-4BX2VUAB-DLiNGQoE.js → chunk-4BX2VUAB-Dp7fVpI_.js} +1 -1
  11. package/dist-renderer/assets/{chunk-55IACEB6-B1L_8VIF.js → chunk-55IACEB6-B8KGfbAy.js} +1 -1
  12. package/dist-renderer/assets/{chunk-B4BG7PRW-DaZMWKGk.js → chunk-B4BG7PRW-BG1oJrjA.js} +1 -1
  13. package/dist-renderer/assets/{chunk-DI55MBZ5-ku-dflJG.js → chunk-DI55MBZ5-DRmxNjht.js} +1 -1
  14. package/dist-renderer/assets/{chunk-FMBD7UC4-DV-mF1dP.js → chunk-FMBD7UC4-D6VLvy16.js} +1 -1
  15. package/dist-renderer/assets/{chunk-QN33PNHL-ByGcDFQ0.js → chunk-QN33PNHL-DZou1667.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QZHKN3VN-7dv-Min8.js → chunk-QZHKN3VN-CghmasSh.js} +1 -1
  17. package/dist-renderer/assets/{chunk-TZMSLE5B-WdXL5fTu.js → chunk-TZMSLE5B-B7apcMPK.js} +1 -1
  18. package/dist-renderer/assets/classDiagram-2ON5EDUG-D_FGxxsl.js +1 -0
  19. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-D_FGxxsl.js +1 -0
  20. package/dist-renderer/assets/clone-CJ1kxO2J.js +1 -0
  21. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-CNcsvqPl.js → cose-bilkent-S5V4N54A-05e5uQDp.js} +1 -1
  22. package/dist-renderer/assets/{dagre-6UL2VRFP-DBNx4qqx.js → dagre-6UL2VRFP-B06bRykF.js} +1 -1
  23. package/dist-renderer/assets/{diagram-PSM6KHXK-BfVlT6sT.js → diagram-PSM6KHXK-CY7VYQ7c.js} +1 -1
  24. package/dist-renderer/assets/{diagram-QEK2KX5R-HvVjs0K6.js → diagram-QEK2KX5R-BjKEH7dD.js} +1 -1
  25. package/dist-renderer/assets/{diagram-S2PKOQOG-DYb_KnWS.js → diagram-S2PKOQOG-Bf4ELS1_.js} +1 -1
  26. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-Ba-IgI5G.js → erDiagram-Q2GNP2WA-DJ753_L9.js} +1 -1
  27. package/dist-renderer/assets/{flowDiagram-NV44I4VS-2iDN8Kpj.js → flowDiagram-NV44I4VS-B71S-lC-.js} +1 -1
  28. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-Byjf8Fa3.js → ganttDiagram-JELNMOA3-C_U42mSZ.js} +1 -1
  29. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DbKvfZ_j.js → gitGraphDiagram-V2S2FVAM-DKUJU4Ns.js} +1 -1
  30. package/dist-renderer/assets/{graph-Enirf-f8.js → graph-DY3qbzqj.js} +1 -1
  31. package/dist-renderer/assets/{index-DY1zqsb6.js → index-BlOrAXp3.js} +551 -537
  32. package/dist-renderer/assets/{index-AjxP_rE_.js → index-Bs27J5gB.js} +1 -1
  33. package/dist-renderer/assets/{index-CtlzGepK.js → index-C8B_nKOF.js} +1 -1
  34. package/dist-renderer/assets/index-CmZPUEhS.css +1 -0
  35. package/dist-renderer/assets/{index-COZPUWJW.js → index-DLKyDr4T.js} +1 -1
  36. package/dist-renderer/assets/{index-DdhqolqE.js → index-Dhsk3_DD.js} +1 -1
  37. package/dist-renderer/assets/{index-ChR1D6ZF.js → index-GpUvV2xs.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D6uicwz1.js → infoDiagram-HS3SLOUP-BNs0y3IG.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DqwZsXlQ.js → journeyDiagram-XKPGCS4Q-CqPnw4UV.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-fCDVhVUm.js → kanban-definition-3W4ZIXB7-SLlzcUJ2.js} +1 -1
  41. package/dist-renderer/assets/{layout-CPFgj98r.js → layout-BZLlNmbr.js} +1 -1
  42. package/dist-renderer/assets/{linear-CYiQ7Y3M.js → linear-qz6v45xy.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-D31dS2KE.js → mindmap-definition-VGOIOE7T-B1-kmEWV.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-BOsCJfds.js → pieDiagram-ADFJNKIX-B8a02iNx.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CYTVQCfr.js → quadrantDiagram-AYHSOK5B-BKv1Xfou.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-CODCFpkt.js → requirementDiagram-UZGBJVZJ-B3DUpZi2.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-Z4ce9ZtZ.js → sankeyDiagram-TZEHDZUN-DmPzuTsy.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-CmS9TxhW.js → sequenceDiagram-WL72ISMW-Bo7RelRb.js} +1 -1
  49. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-o9k-ns3q.js → stateDiagram-FKZM4ZOC-1epX98gV.js} +1 -1
  50. package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-CxHMyEt1.js → stateDiagram-v2-4FDKWEC3-03Ym9PTr.js} +1 -1
  51. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-B6T3zrde.js → timeline-definition-IT6M3QCI-r6isC62H.js} +1 -1
  52. package/dist-renderer/assets/{treemap-GDKQZRPO-CVd5GNDw.js → treemap-GDKQZRPO-CGKpOUF2.js} +1 -1
  53. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-CleBrdqc.js → xychartDiagram-PRI3JC2R-t4-rwdAw.js} +1 -1
  54. package/dist-renderer/index.html +2 -2
  55. package/package.json +4 -1
  56. package/src/main/ipc/extensions.ts +353 -0
  57. package/src/main/server.ts +907 -184
  58. package/src/main/services/extensions/ExtensionFacadeService.ts +135 -0
  59. package/src/main/services/extensions/catalog/GlamaMcpEnrichmentService.ts +190 -0
  60. package/src/main/services/extensions/catalog/McpCatalogAggregator.ts +150 -0
  61. package/src/main/services/extensions/catalog/OfficialMcpRegistryService.ts +381 -0
  62. package/src/main/services/extensions/catalog/PluginCatalogService.ts +392 -0
  63. package/src/main/services/extensions/credentials/CredentialService.ts +343 -0
  64. package/src/main/services/extensions/install/McpInstallService.ts +407 -0
  65. package/src/main/services/extensions/install/PluginInstallService.ts +198 -0
  66. package/src/main/services/extensions/runtime/ClaudeCodeAdapter.ts +199 -0
  67. package/src/main/services/extensions/runtime/CodexAdapter.ts +100 -0
  68. package/src/main/services/extensions/runtime/CursorAdapter.ts +154 -0
  69. package/src/main/services/extensions/runtime/ExtensionsRuntimeAdapter.ts +172 -0
  70. package/src/main/services/extensions/runtime/GeminiAdapter.ts +91 -0
  71. package/src/main/services/extensions/runtime/HarnessInstallAdapter.ts +49 -0
  72. package/src/main/services/extensions/runtime/McpConfigStateReader.ts +209 -0
  73. package/src/main/services/extensions/runtime/OpenCodeAdapter.ts +91 -0
  74. package/src/main/services/extensions/runtime/adapterRegistry.ts +54 -0
  75. package/src/main/services/extensions/runtime/mcpDiagnosticsParser.ts +214 -0
  76. package/src/main/services/extensions/runtime/mcpRuntimeJson.ts +45 -0
  77. package/src/main/services/extensions/skills/SkillImportService.ts +155 -0
  78. package/src/main/services/extensions/skills/SkillMetadataParser.ts +323 -0
  79. package/src/main/services/extensions/skills/SkillPlanService.ts +411 -0
  80. package/src/main/services/extensions/skills/SkillReviewService.ts +73 -0
  81. package/src/main/services/extensions/skills/SkillRootsResolver.ts +49 -0
  82. package/src/main/services/extensions/skills/SkillScaffoldService.ts +89 -0
  83. package/src/main/services/extensions/skills/SkillScanner.ts +117 -0
  84. package/src/main/services/extensions/skills/SkillValidator.ts +69 -0
  85. package/src/main/services/extensions/skills/SkillsCatalogService.ts +92 -0
  86. package/src/main/services/extensions/skills/SkillsMutationService.ts +146 -0
  87. package/src/main/services/extensions/skills/SkillsWatcherService.ts +134 -0
  88. package/src/main/services/extensions/state/McpInstallationStateService.ts +42 -0
  89. package/src/main/services/extensions/state/PluginInstallationStateService.ts +281 -0
  90. package/src/main/services/identity/AgentTeamsIdentityStore.ts +218 -0
  91. package/src/main/services/runtime/providerAwareCliEnv.ts +60 -0
  92. package/src/main/services/session-intelligence/UsageTelemetryService.ts +33 -18
  93. package/src/main/services/team/ClaudeBinaryResolver.ts +469 -0
  94. package/src/main/services/team/ClaudeDoctorProbe.ts +0 -0
  95. package/src/main/services/team/cliFlavor.ts +54 -0
  96. package/src/main/services/teams-mvp/CollaborationBoardService.ts +310 -0
  97. package/src/main/services/teams-mvp/TaskDispatchService.ts +883 -95
  98. package/src/main/services/teams-mvp/TeamProvisioningService.ts +58 -19
  99. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +25 -2
  100. package/src/main/services/teams-mvp/index.ts +3 -0
  101. package/src/main/utils/atomicWrite.ts +72 -0
  102. package/src/main/utils/childProcess.ts +554 -0
  103. package/src/main/utils/cliEnv.ts +54 -0
  104. package/src/main/utils/cliPathMerge.ts +97 -0
  105. package/src/main/utils/pathDecoder.ts +664 -0
  106. package/src/main/utils/pathValidation.ts +432 -0
  107. package/src/main/utils/shellEnv.ts +331 -0
  108. package/src/renderer/App.tsx +5 -0
  109. package/src/renderer/api/httpClient.ts +128 -0
  110. package/src/renderer/components/extensions/ExtensionStoreView.tsx +59 -34
  111. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
  112. package/src/renderer/components/extensions/common/ExtensionToast.tsx +141 -0
  113. package/src/renderer/components/extensions/common/HarnessSelector.tsx +71 -0
  114. package/src/renderer/components/extensions/env/EnvVarPanel.tsx +335 -0
  115. package/src/renderer/components/extensions/env/ProjectEnvPanel.tsx +239 -0
  116. package/src/renderer/components/extensions/mcp/CustomMcpServerDialog.tsx +14 -223
  117. package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +11 -0
  118. package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +51 -1
  119. package/src/renderer/components/extensions/skills/SkillsPanel.tsx +1 -126
  120. package/src/renderer/components/layout/PaneContent.tsx +2 -0
  121. package/src/renderer/components/layout/SortableTab.tsx +1 -0
  122. package/src/renderer/components/layout/TabBarActions.tsx +12 -12
  123. package/src/renderer/components/schedules/SchedulesView.tsx +54 -22
  124. package/src/renderer/components/settings/sections/AdvancedSection.tsx +1 -1
  125. package/src/renderer/components/settings/sections/HarnessSection.tsx +2 -6
  126. package/src/renderer/components/settings/sections/TaskBusSection.tsx +144 -84
  127. package/src/renderer/components/sidebar/SidebarSessions.tsx +23 -0
  128. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +1 -7
  129. package/src/renderer/components/tasks/TasksView.tsx +343 -0
  130. package/src/renderer/components/team/HarnessSelect.tsx +71 -0
  131. package/src/renderer/components/team/TeamDetailView.tsx +55 -98
  132. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +21 -12
  133. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +8 -13
  134. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +1 -1
  135. package/src/renderer/components/team/editor/EditorContextMenu.tsx +8 -23
  136. package/src/renderer/components/team/editor/EditorFileTree.tsx +0 -4
  137. package/src/renderer/components/team/editor/EditorSelectionMenu.tsx +1 -8
  138. package/src/renderer/components/team/editor/ProjectEditorOverlay.tsx +0 -10
  139. package/src/renderer/components/team/kanban/KanbanBoard.tsx +31 -65
  140. package/src/renderer/components/team/members/MemberDetailDialog.tsx +8 -33
  141. package/src/renderer/components/team/messages/MessageComposer.tsx +39 -3
  142. package/src/renderer/components/team/messages/MessagesPanel.tsx +100 -26
  143. package/src/renderer/components/team/messages/StatusBlock.tsx +2 -24
  144. package/src/renderer/components/team/schedule/ScheduleEmptyState.tsx +1 -1
  145. package/src/renderer/components/terminal/TerminalPanel.tsx +156 -0
  146. package/src/renderer/components/ui/MentionableTextarea.tsx +0 -1
  147. package/src/renderer/hooks/useExtensionsTabState.ts +2 -2
  148. package/src/renderer/store/slices/extensionsSlice.ts +42 -107
  149. package/src/renderer/store/slices/scheduleSlice.ts +21 -0
  150. package/src/renderer/store/slices/teamSlice.ts +67 -25
  151. package/src/renderer/types/tabs.ts +1 -0
  152. package/src/shared/types/api.ts +58 -0
  153. package/src/shared/types/extensions/index.ts +1 -0
  154. package/src/shared/types/extensions/mcp.ts +2 -0
  155. package/src/shared/types/extensions/plugin.ts +2 -1
  156. package/src/shared/types/extensions/skill.ts +7 -0
  157. package/src/shared/types/team.ts +104 -1
  158. package/src/shared/utils/providerExtensionCapabilities.ts +1 -1
  159. package/dist-renderer/assets/ProjectEditorOverlay-A4DZTvSy.js +0 -57
  160. package/dist-renderer/assets/channel-Pre42N5O.js +0 -1
  161. package/dist-renderer/assets/classDiagram-2ON5EDUG-CdJsTJsj.js +0 -1
  162. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CdJsTJsj.js +0 -1
  163. package/dist-renderer/assets/clone-BjQBiNfj.js +0 -1
  164. package/dist-renderer/assets/index-BIOJremZ.css +0 -1
  165. package/src/features/recent-projects/main/adapters/input/http/registerRecentProjectsHttp.ts +0 -30
  166. package/src/features/recent-projects/main/adapters/output/presenters/DashboardRecentProjectsPresenter.ts +0 -27
  167. package/src/features/recent-projects/main/adapters/output/sources/ClaudeRecentProjectsSourceAdapter.ts +0 -91
  168. package/src/features/recent-projects/main/adapters/output/sources/CodexRecentProjectsSourceAdapter.ts +0 -326
  169. package/src/features/recent-projects/main/composition/createRecentProjectsFeature.ts +0 -43
  170. package/src/features/recent-projects/main/index.ts +0 -3
  171. package/src/features/recent-projects/main/infrastructure/cache/InMemoryRecentProjectsCache.ts +0 -34
  172. package/src/features/recent-projects/main/infrastructure/codex/CodexAppServerClient.ts +0 -116
  173. package/src/features/recent-projects/main/infrastructure/identity/RecentProjectIdentityResolver.ts +0 -20
  174. package/src/features/recent-projects/main/infrastructure/identity/normalizeIdentityPath.ts +0 -10
  175. package/src/renderer/components/extensions/apikeys/ApiKeyCard.tsx +0 -143
  176. package/src/renderer/components/extensions/apikeys/ApiKeyFormDialog.tsx +0 -282
  177. 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 [telemetryEnabled, setTelemetryEnabled] = useState(false);
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
- setTelemetryEnabled(data.telemetry.enabled);
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/telemetry/status')
233
+ fetch('/api/settings/task-bus')
230
234
  .then((r) => r.json())
231
- .then((s: TelemetryStatus) => {
232
- if (s.connected) setConnected(true);
233
- if ('sessions' in s && s.sessions > 0) setTelemetryStatus(s);
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 (telemetryEnabled) {
249
+ if (enabled && collectionEnabled) {
239
250
  fetch('/api/telemetry/status')
240
251
  .then((r) => r.json())
241
- .then((s: TelemetryStatus) => setTelemetryStatus(s))
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
- }, [telemetryEnabled]);
260
+ }, [enabled, collectionEnabled]);
247
261
 
248
262
  const buildConfig = (
249
263
  overrides: Partial<{
250
264
  enabled: boolean;
251
- telemetryEnabled: boolean;
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.telemetryEnabled ?? telemetryEnabled,
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 toggleTelemetry = async (value: boolean) => {
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
- setTelemetryEnabled(false);
302
- const config = buildConfig({ telemetryEnabled: false });
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
- // Optimistic update: toggle on immediately
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
- setTelemetryEnabled(false);
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({ telemetryEnabled: true });
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
- setTelemetryEnabled(false);
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('采集失败,请检查 Redis 连接'))
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="开启后自动为所有团队注入跨团队协作指令到 CLAUDE.md"
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)]">(数据上报必填)</span>
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
- {/* 数据采集 - 不依赖 Redis */}
469
- <div style={{ borderColor: 'var(--color-border-subtle)' }}>
470
- <SettingRow
471
- label="数据采集"
472
- description="扫描本地 ~/.claude/projects 会话文件,采集使用指标(会话、消息、Token、工作时长)"
473
- >
474
- <div className="flex items-center gap-2">
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
- {telemetryEnabled && (
494
- <>
495
- <div className="flex items-center gap-3 border-b py-3" style={{ borderColor: 'var(--color-border-subtle)' }}>
496
- <Button
497
- size="sm"
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
- {/* 数据上报 - 依赖 Redis,最下面 */}
584
+ {/* 分布式团队协作 - 最下面 */}
525
585
  <div>
526
586
  <SettingRow
527
- label="数据上报"
528
- description="将采集数据上报到 Redis,供团队看板使用"
587
+ label="分布式团队协作"
588
+ description="开启后 Hermit 平台识别 @团队 并创建跨团队协作任务;Agent 只读取团队列表,不直接派发"
529
589
  >
530
590
  <SettingsToggle
531
- enabled={telemetryEnabled && connected}
532
- onChange={(value) => void toggleTelemetry(value)}
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>数据上报需要 Redis;请先配置并测试 Redis 连接。</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={`flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors ${
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 ? (