@yancyyu/openhermit 1.6.37 → 1.6.39

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 (205) hide show
  1. package/dist-renderer/assets/ProjectEditorOverlay-krO5vQxX.js +58 -0
  2. package/dist-renderer/assets/{TeamGraphOverlay-DYT3bwFR.js → TeamGraphOverlay-DqhQzcTr.js} +1 -1
  3. package/dist-renderer/assets/{_basePickBy-Dbt_EU-e.js → _basePickBy-B7kSYPxr.js} +1 -1
  4. package/dist-renderer/assets/{_baseUniq-DWo68sXI.js → _baseUniq-CnjxqwAk.js} +1 -1
  5. package/dist-renderer/assets/{arc-DXH1iZQK.js → arc-CLeZuINP.js} +1 -1
  6. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-cjffS2Qr.js → architectureDiagram-VXUJARFQ-QKtqaqdY.js} +1 -1
  7. package/dist-renderer/assets/{blockDiagram-VD42YOAC-BKdZF02Y.js → blockDiagram-VD42YOAC-BqdrzO_f.js} +1 -1
  8. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-CN27pqaI.js → c4Diagram-YG6GDRKO-gwPlCxDC.js} +1 -1
  9. package/dist-renderer/assets/channel-DpMHF50r.js +1 -0
  10. package/dist-renderer/assets/{chunk-4BX2VUAB-CXPCI7g_.js → chunk-4BX2VUAB-C6XLurL4.js} +1 -1
  11. package/dist-renderer/assets/{chunk-55IACEB6-BGAXQZRC.js → chunk-55IACEB6-Ds6quhEP.js} +1 -1
  12. package/dist-renderer/assets/{chunk-B4BG7PRW-TPDaA_KQ.js → chunk-B4BG7PRW-5UlA1_e9.js} +1 -1
  13. package/dist-renderer/assets/{chunk-DI55MBZ5-D1ADe_tq.js → chunk-DI55MBZ5-ywFrqIsY.js} +1 -1
  14. package/dist-renderer/assets/{chunk-FMBD7UC4-Beimtg3a.js → chunk-FMBD7UC4-C7ifUA17.js} +1 -1
  15. package/dist-renderer/assets/{chunk-QN33PNHL-OjNBu854.js → chunk-QN33PNHL-BxGCo80U.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QZHKN3VN-DinqvbH8.js → chunk-QZHKN3VN-B2CuaZs6.js} +1 -1
  17. package/dist-renderer/assets/{chunk-TZMSLE5B-BfFtlPSZ.js → chunk-TZMSLE5B-Ds1hInvp.js} +1 -1
  18. package/dist-renderer/assets/classDiagram-2ON5EDUG-CBYCBVRl.js +1 -0
  19. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CBYCBVRl.js +1 -0
  20. package/dist-renderer/assets/clone-DcMF6Psb.js +1 -0
  21. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-D9z9Dgt7.js → cose-bilkent-S5V4N54A-Cz1GVtLp.js} +1 -1
  22. package/dist-renderer/assets/{dagre-6UL2VRFP-n1g-DhEE.js → dagre-6UL2VRFP-BrmR-P4h.js} +1 -1
  23. package/dist-renderer/assets/{diagram-PSM6KHXK-BvxFq-BE.js → diagram-PSM6KHXK-DbNjC5Rg.js} +1 -1
  24. package/dist-renderer/assets/{diagram-QEK2KX5R-wVnJuwza.js → diagram-QEK2KX5R-qkRX5_Mq.js} +1 -1
  25. package/dist-renderer/assets/{diagram-S2PKOQOG-B707WJQw.js → diagram-S2PKOQOG-CyL5rCv2.js} +1 -1
  26. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-C-_1dGHs.js → erDiagram-Q2GNP2WA-Dox3-bA5.js} +1 -1
  27. package/dist-renderer/assets/{flowDiagram-NV44I4VS-CMTSi3H6.js → flowDiagram-NV44I4VS-BtkaxlDL.js} +1 -1
  28. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DZ0bNrAA.js → ganttDiagram-JELNMOA3-Dhy_d9GK.js} +1 -1
  29. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DNVfGooQ.js → gitGraphDiagram-V2S2FVAM-B5XRhIQA.js} +1 -1
  30. package/dist-renderer/assets/{graph-865j_tM_.js → graph-CsoEwUhS.js} +1 -1
  31. package/dist-renderer/assets/{index-C_F9N5x-.js → index-BWPWmJNo.js} +1 -1
  32. package/dist-renderer/assets/{index-LwDIsXJN.js → index-Bu2R-Se7.js} +586 -740
  33. package/dist-renderer/assets/index-CnWV3BhG.css +32 -0
  34. package/dist-renderer/assets/{index-DuUaf8at.js → index-D-3KgskL.js} +1 -1
  35. package/dist-renderer/assets/{index-BTx1nc4T.js → index-DGEBzLNT.js} +1 -1
  36. package/dist-renderer/assets/{index-2EW-eu3q.js → index-NhHNs2Oo.js} +1 -1
  37. package/dist-renderer/assets/{index-4dEMStJj.js → index-h17WuEyf.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-CyqtElLq.js → infoDiagram-HS3SLOUP-hMGmNojH.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BvjQ0Hm0.js → journeyDiagram-XKPGCS4Q-DXV2rBDl.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-CJJ-k0zT.js → kanban-definition-3W4ZIXB7-Bf99WLRy.js} +1 -1
  41. package/dist-renderer/assets/{layout-CnV6rQAG.js → layout-C3XWrpwo.js} +1 -1
  42. package/dist-renderer/assets/{linear-Cw3UQgyX.js → linear-OEEcn8KN.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-C5tDaGSK.js → mindmap-definition-VGOIOE7T-Dpi3S2x4.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-CiIpPsau.js → pieDiagram-ADFJNKIX-xTPPhtNx.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-C3gtowNj.js → quadrantDiagram-AYHSOK5B-euniyDlz.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-CXBTrAnU.js → requirementDiagram-UZGBJVZJ-D9Uiw4kF.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-wziX77xG.js → sankeyDiagram-TZEHDZUN-CySU4nED.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-sYqopcrj.js → sequenceDiagram-WL72ISMW-JVGpET6V.js} +1 -1
  49. package/dist-renderer/assets/splashScene-D0YB9uxm.js +17 -0
  50. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-Bl1-0_Cp.js → stateDiagram-FKZM4ZOC-B2FY5qqi.js} +1 -1
  51. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DcoMiR8H.js +1 -0
  52. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-CIRjJUBo.js → timeline-definition-IT6M3QCI-DmycNUUe.js} +1 -1
  53. package/dist-renderer/assets/{treemap-GDKQZRPO-CVPuNe1n.js → treemap-GDKQZRPO-DPq4gZuB.js} +1 -1
  54. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-3nT9yHwp.js → xychartDiagram-PRI3JC2R-J6VVJzRq.js} +1 -1
  55. package/dist-renderer/index.html +20 -53
  56. package/package.json +25 -18
  57. package/src/main/ipc/extensions.ts +30 -50
  58. package/src/main/server.ts +890 -247
  59. package/src/main/services/extensions/ExtensionFacadeService.ts +4 -56
  60. package/src/main/services/extensions/catalog/PluginCatalogService.ts +4 -2
  61. package/src/main/services/extensions/library/McpLibraryService.ts +243 -0
  62. package/src/main/services/session-intelligence/ConversationTelemetryService.ts +1101 -0
  63. package/src/main/services/session-intelligence/LocalSessionScanner.ts +512 -0
  64. package/src/main/services/session-intelligence/SessionUsageParser.ts +4 -4
  65. package/src/main/services/session-intelligence/UsageTelemetryService.ts +14 -1
  66. package/src/main/services/system-manager/SystemManagerConfigService.ts +122 -0
  67. package/src/main/services/system-manager/SystemManagerPtyService.ts +233 -0
  68. package/src/main/services/system-manager/WorkflowPromptService.ts +75 -0
  69. package/src/main/services/teams-mvp/TaskDispatchService.ts +32 -8
  70. package/src/main/services/teams-mvp/TeamProvisioningService.ts +39 -2
  71. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +22 -4
  72. package/src/main/utils/teamProjectResolution.ts +15 -0
  73. package/src/renderer/App.tsx +8 -4
  74. package/src/renderer/api/httpClient.ts +174 -38
  75. package/src/renderer/api/providers.ts +23 -2
  76. package/src/renderer/assets/participant-avatars/01.svg +3 -0
  77. package/src/renderer/assets/participant-avatars/02.svg +3 -0
  78. package/src/renderer/assets/participant-avatars/03.svg +3 -0
  79. package/src/renderer/assets/participant-avatars/04.svg +3 -0
  80. package/src/renderer/assets/participant-avatars/05.svg +3 -0
  81. package/src/renderer/assets/participant-avatars/06.svg +3 -0
  82. package/src/renderer/assets/participant-avatars/07.svg +3 -0
  83. package/src/renderer/assets/participant-avatars/08.svg +3 -0
  84. package/src/renderer/assets/participant-avatars/09.svg +3 -0
  85. package/src/renderer/assets/participant-avatars/10.svg +3 -0
  86. package/src/renderer/assets/participant-avatars/11.svg +3 -0
  87. package/src/renderer/assets/participant-avatars/12.svg +3 -0
  88. package/src/renderer/assets/participant-avatars/13.svg +3 -0
  89. package/src/renderer/components/common/TerminalPane.tsx +213 -0
  90. package/src/renderer/components/dashboard/DashboardView.tsx +9 -36
  91. package/src/renderer/components/extensions/ExtensionStoreView.tsx +12 -221
  92. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
  93. package/src/renderer/components/extensions/mcp/McpLibraryEnableDialog.tsx +305 -0
  94. package/src/renderer/components/extensions/mcp/McpLibraryEntryDialog.tsx +418 -0
  95. package/src/renderer/components/extensions/mcp/McpLibraryPanel.tsx +404 -0
  96. package/src/renderer/components/extensions/plugins/PluginCard.tsx +10 -2
  97. package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +40 -22
  98. package/src/renderer/components/extensions/skills/SkillsLibraryPanel.tsx +335 -0
  99. package/src/renderer/components/layout/PaneContent.tsx +8 -1
  100. package/src/renderer/components/layout/Sidebar.tsx +11 -54
  101. package/src/renderer/components/layout/SortableTab.tsx +20 -31
  102. package/src/renderer/components/layout/TabBar.tsx +1 -1
  103. package/src/renderer/components/layout/TabContextMenu.tsx +1 -1
  104. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +768 -157
  105. package/src/renderer/components/schedules/SchedulesView.tsx +51 -462
  106. package/src/renderer/components/schedules/calendar/CalendarDayView.tsx +173 -0
  107. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +113 -0
  108. package/src/renderer/components/schedules/calendar/CalendarHeader.tsx +148 -0
  109. package/src/renderer/components/schedules/calendar/CalendarMonthView.tsx +142 -0
  110. package/src/renderer/components/schedules/calendar/CalendarWeekView.tsx +219 -0
  111. package/src/renderer/components/schedules/calendar/ScheduleCalendarBoard.tsx +41 -0
  112. package/src/renderer/components/schedules/calendar/TeamGanttView.tsx +405 -0
  113. package/src/renderer/components/schedules/calendar/computeOccurrences.ts +234 -0
  114. package/src/renderer/components/schedules/calendar/index.ts +2 -0
  115. package/src/renderer/components/schedules/calendar/types.ts +44 -0
  116. package/src/renderer/components/settings/SettingsTabs.tsx +50 -55
  117. package/src/renderer/components/settings/SettingsView.tsx +30 -35
  118. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +5 -1
  119. package/src/renderer/components/settings/components/SettingsSelect.tsx +5 -3
  120. package/src/renderer/components/settings/components/SettingsToggle.tsx +2 -2
  121. package/src/renderer/components/settings/sections/AdvancedSection.tsx +11 -42
  122. package/src/renderer/components/settings/sections/CliStatusSection.tsx +71 -112
  123. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  124. package/src/renderer/components/settings/sections/GeneralSection.tsx +11 -3
  125. package/src/renderer/components/settings/sections/HarnessSection.tsx +18 -14
  126. package/src/renderer/components/settings/sections/PlatformsSection.tsx +3 -3
  127. package/src/renderer/components/settings/sections/TaskBusSection.tsx +33 -40
  128. package/src/renderer/components/settings/sections/index.ts +0 -1
  129. package/src/renderer/components/sidebar/SidebarSessions.tsx +182 -4
  130. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +4 -4
  131. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +39 -4
  132. package/src/renderer/components/splash/splashScene.ts +121 -929
  133. package/src/renderer/components/system-manager/FolderBrowser.tsx +163 -0
  134. package/src/renderer/components/system-manager/SystemManagerView.tsx +351 -0
  135. package/src/renderer/components/tasks/TasksView.tsx +112 -134
  136. package/src/renderer/components/team/CcSessionsSection.tsx +431 -89
  137. package/src/renderer/components/team/CollapsibleTeamSection.tsx +17 -32
  138. package/src/renderer/components/team/TeamDetailView.tsx +325 -114
  139. package/src/renderer/components/team/TeamListView.tsx +108 -123
  140. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +2 -2
  141. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +84 -306
  142. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +259 -342
  143. package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +1 -1
  144. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +17 -15
  145. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +221 -0
  146. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +7 -0
  147. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +1 -1
  148. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +361 -0
  149. package/src/renderer/components/team/dialogs/platformMeta.ts +122 -11
  150. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +17 -5
  151. package/src/renderer/components/team/kanban/KanbanBoard.tsx +9 -9
  152. package/src/renderer/components/team/members/MemberCard.tsx +14 -47
  153. package/src/renderer/components/team/members/MemberDetailDialog.tsx +3 -95
  154. package/src/renderer/components/team/members/MemberDetailStats.tsx +50 -65
  155. package/src/renderer/components/team/messages/MessageComposer.tsx +8 -110
  156. package/src/renderer/components/team/messages/MessagesPanel.tsx +131 -114
  157. package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +2 -2
  158. package/src/renderer/components/team/tools/AddMcpInline.tsx +57 -0
  159. package/src/renderer/components/team/tools/AddSkillInline.tsx +61 -0
  160. package/src/renderer/components/team/tools/McpChip.tsx +45 -0
  161. package/src/renderer/components/team/tools/SkillChip.tsx +35 -0
  162. package/src/renderer/components/team/tools/ToolsSection.tsx +556 -0
  163. package/src/renderer/hooks/useExtensionsTabState.ts +3 -114
  164. package/src/renderer/index.css +39 -22
  165. package/src/renderer/index.html +17 -50
  166. package/src/renderer/store/index.ts +2 -1
  167. package/src/renderer/store/slices/scheduleSlice.ts +1 -1
  168. package/src/renderer/store/slices/teamSlice.ts +45 -168
  169. package/src/renderer/utils/claudeCodeOnlyProviders.ts +3 -10
  170. package/src/renderer/utils/memberHelpers.ts +5 -17
  171. package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +4 -2
  172. package/src/renderer/utils/providerSlashCommands.ts +0 -5
  173. package/src/renderer/utils/scheduleFormatters.ts +3 -1
  174. package/src/renderer/utils/teamMessageFiltering.ts +14 -1
  175. package/src/renderer/utils/teamModelAvailability.ts +18 -2
  176. package/src/shared/types/api.ts +121 -2
  177. package/src/shared/types/ccConnect.ts +2 -0
  178. package/src/shared/types/extensions/api.ts +9 -0
  179. package/src/shared/types/extensions/index.ts +4 -0
  180. package/src/shared/types/extensions/mcp.ts +41 -0
  181. package/src/shared/types/index.ts +3 -0
  182. package/src/shared/types/systemManager.ts +49 -0
  183. package/src/shared/types/team.ts +29 -0
  184. package/src/shared/types/terminal.ts +4 -2
  185. package/src/shared/utils/extensionNormalizers.ts +29 -0
  186. package/src/shared/utils/providerExtensionCapabilities.ts +2 -2
  187. package/dist-renderer/assets/ProjectEditorOverlay-Va_Vz-zz.js +0 -52
  188. package/dist-renderer/assets/channel-5dJIx68e.js +0 -1
  189. package/dist-renderer/assets/classDiagram-2ON5EDUG-BMGXWJ2d.js +0 -1
  190. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-BMGXWJ2d.js +0 -1
  191. package/dist-renderer/assets/clone-D7FWfGY9.js +0 -1
  192. package/dist-renderer/assets/index-B2z_IyRH.css +0 -1
  193. package/dist-renderer/assets/splashScene-C8lWNnm4.js +0 -1
  194. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DOYYvDbi.js +0 -1
  195. package/src/main/services/extensions/catalog/GlamaMcpEnrichmentService.ts +0 -190
  196. package/src/main/services/extensions/catalog/McpCatalogAggregator.ts +0 -150
  197. package/src/main/services/extensions/catalog/OfficialMcpRegistryService.ts +0 -381
  198. package/src/main/services/extensions/install/McpInstallService.ts +0 -407
  199. package/src/main/services/extensions/state/McpInstallationStateService.ts +0 -42
  200. package/src/renderer/components/extensions/mcp/McpServerCard.tsx +0 -314
  201. package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +0 -765
  202. package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +0 -593
  203. package/src/renderer/components/extensions/skills/SkillDetailDialog.tsx +0 -372
  204. package/src/renderer/components/extensions/skills/SkillImportDialog.tsx +0 -343
  205. package/src/renderer/components/extensions/skills/SkillsPanel.tsx +0 -659
@@ -17,6 +17,7 @@ import {
17
17
  AlertCircle,
18
18
  ChevronDown,
19
19
  ChevronRight,
20
+ Download,
20
21
  Loader2,
21
22
  MessageSquare,
22
23
  Radio,
@@ -25,7 +26,14 @@ import {
25
26
  X,
26
27
  } from 'lucide-react';
27
28
 
28
- import type { CcSession, CcSessionDetail, TeamSummary } from '@shared/types';
29
+ import type {
30
+ CcSession,
31
+ CcSessionDetail,
32
+ ConversationTelemetryResponse,
33
+ ConversationTelemetryRow,
34
+ TeamChangeEvent,
35
+ TeamSummary,
36
+ } from '@shared/types';
29
37
 
30
38
  const PAGE_SIZE = 8;
31
39
  const REFRESH_INTERVAL_MS = 2000;
@@ -48,6 +56,9 @@ export const SidebarSessions = (): React.JSX.Element => {
48
56
  const [visibleCount, setVisibleCount] = useState(PAGE_SIZE);
49
57
  const [searchQuery, setSearchQuery] = useState('');
50
58
  const [cancellingId, setCancellingId] = useState<string | null>(null);
59
+ const [exporting, setExporting] = useState(false);
60
+ const [telemetryRows, setTelemetryRows] = useState<ConversationTelemetryRow[]>([]);
61
+ const [loadingTelemetry, setLoadingTelemetry] = useState(false);
51
62
  const [expandedId, setExpandedId] = useState<string | null>(null);
52
63
  const refreshInFlightRef = useRef(false);
53
64
  const needsRefreshRef = useRef(false);
@@ -143,6 +154,35 @@ export const SidebarSessions = (): React.JSX.Element => {
143
154
  void fetchAll();
144
155
  }, [fetchAll]);
145
156
 
157
+ useEffect(() => {
158
+ let cancelled = false;
159
+ setLoadingTelemetry(true);
160
+ const params = new URLSearchParams({
161
+ includeContent: 'summary',
162
+ includeToolResults: 'false',
163
+ includeSystemMessages: 'false',
164
+ limit: '100000',
165
+ });
166
+ void fetch(`/api/telemetry/conversations?${params.toString()}`)
167
+ .then(async (res) => {
168
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
169
+ return (await res.json()) as ConversationTelemetryResponse;
170
+ })
171
+ .then((data) => {
172
+ if (!cancelled) setTelemetryRows(data.rows);
173
+ })
174
+ .catch((err) => {
175
+ console.error('Failed to load conversation telemetry:', err);
176
+ if (!cancelled) setTelemetryRows([]);
177
+ })
178
+ .finally(() => {
179
+ if (!cancelled) setLoadingTelemetry(false);
180
+ });
181
+ return () => {
182
+ cancelled = true;
183
+ };
184
+ }, []);
185
+
146
186
  useEffect(() => {
147
187
  setVisibleCount(PAGE_SIZE);
148
188
  setExpandedId(null);
@@ -161,6 +201,20 @@ export const SidebarSessions = (): React.JSX.Element => {
161
201
  if (scopedTeamName && change.teamName !== scopedTeamName) {
162
202
  return;
163
203
  }
204
+ // Only refresh the session list on events that may change session state.
205
+ // Skip high-frequency events like lead-context, tool-activity, lead-activity
206
+ // that don't affect the session list.
207
+ const sessionRelevantTypes: ReadonlySet<string> = new Set([
208
+ 'inbox',
209
+ 'lead-message',
210
+ 'task',
211
+ 'config',
212
+ 'process',
213
+ 'member-spawn',
214
+ ]);
215
+ if (!sessionRelevantTypes.has(change.type)) {
216
+ return;
217
+ }
164
218
  // Incremental refresh for the changed team — lightweight, no blocking
165
219
  void refreshTeam(change.teamName);
166
220
  });
@@ -195,14 +249,78 @@ export const SidebarSessions = (): React.JSX.Element => {
195
249
  setExpandedId((prev) => (prev === sessionId ? null : sessionId));
196
250
  }, []);
197
251
 
252
+ const handleExportAllSessions = useCallback(async () => {
253
+ setExporting(true);
254
+ try {
255
+ const params = new URLSearchParams({
256
+ format: 'csv',
257
+ includeContent: 'summary',
258
+ includeToolResults: 'false',
259
+ includeSystemMessages: 'false',
260
+ });
261
+ if (scopedTeamName) {
262
+ params.set('teamName', scopedTeamName);
263
+ }
264
+ const res = await fetch(`/api/telemetry/conversations/export?${params.toString()}`);
265
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
266
+ const payload = (await res.json()) as { filename: string; mimeType: string; content: string };
267
+ const blob = new Blob([`${payload.content}`], {
268
+ type: payload.mimeType || 'text/csv;charset=utf-8',
269
+ });
270
+ const url = URL.createObjectURL(blob);
271
+ const link = document.createElement('a');
272
+ link.href = url;
273
+ link.download = payload.filename || 'conversation-telemetry.csv';
274
+ document.body.appendChild(link);
275
+ link.click();
276
+ link.remove();
277
+ URL.revokeObjectURL(url);
278
+ } catch (err) {
279
+ console.error('Failed to export conversation telemetry:', err);
280
+ setError(err instanceof Error ? err.message : '导出失败');
281
+ } finally {
282
+ setExporting(false);
283
+ }
284
+ }, [scopedTeamName]);
285
+
286
+ const telemetryBySession = useMemo(() => {
287
+ const map = new Map<string, ConversationTelemetryRow>();
288
+ for (const row of telemetryRows) {
289
+ if (row.session.ccSessionId) map.set(row.session.ccSessionId, row);
290
+ map.set(row.session.sessionKey, row);
291
+ }
292
+ return map;
293
+ }, [telemetryRows]);
294
+
198
295
  // Filter + sort
199
296
  const filtered = allSessions.filter((s) => {
200
297
  if (!searchQuery.trim()) return true;
201
298
  const q = searchQuery.toLowerCase();
299
+ const telemetry = telemetryBySession.get(s.id) ?? telemetryBySession.get(s.sessionKey);
202
300
  const title = (s.title || '').toLowerCase();
203
301
  const team = s.teamDisplayName.toLowerCase();
204
- const lastMsg = (s.lastMessage?.content || '').toLowerCase();
205
- return title.includes(q) || team.includes(q) || lastMsg.includes(q);
302
+ const sessionKey = s.sessionKey.toLowerCase();
303
+ const platform = s.platform.toLowerCase();
304
+ const userName = (s.userName || telemetry?.identity.userName || '').toLowerCase();
305
+ const chatName = (s.chatName || telemetry?.identity.chatName || '').toLowerCase();
306
+ const firstQuestion = (telemetry?.content.firstUserMessage || '').toLowerCase();
307
+ const lastQuestion = (telemetry?.content.lastUserMessage || '').toLowerCase();
308
+ const lastMsg = (
309
+ s.lastMessage?.content ||
310
+ telemetry?.content.lastMessageContent ||
311
+ ''
312
+ ).toLowerCase();
313
+ return [
314
+ title,
315
+ team,
316
+ sessionKey,
317
+ platform,
318
+ userName,
319
+ chatName,
320
+ firstQuestion,
321
+ lastQuestion,
322
+ lastMsg,
323
+ ].some((value) => value.includes(q));
206
324
  });
207
325
 
208
326
  const allSorted = [...filtered].sort(
@@ -261,7 +379,7 @@ export const SidebarSessions = (): React.JSX.Element => {
261
379
 
262
380
  return (
263
381
  <div className="flex h-full flex-col overflow-hidden">
264
- {/* Search */}
382
+ {/* Search / export */}
265
383
  <div className="flex shrink-0 items-center gap-1.5 border-b px-2 py-1.5">
266
384
  <Search size={12} className="shrink-0 text-[var(--color-text-muted)]" />
267
385
  <input
@@ -283,6 +401,16 @@ export const SidebarSessions = (): React.JSX.Element => {
283
401
  <X size={12} />
284
402
  </button>
285
403
  )}
404
+ <button
405
+ type="button"
406
+ className="inline-flex shrink-0 items-center gap-1 rounded-md px-1.5 py-0.5 text-[10px] text-[var(--color-text-muted)] transition-colors hover:bg-[var(--color-surface-raised)] hover:text-[var(--color-text)] disabled:cursor-not-allowed disabled:opacity-50"
407
+ onClick={() => void handleExportAllSessions()}
408
+ disabled={exporting}
409
+ title="导出所有会话为 CSV 表格"
410
+ >
411
+ {exporting ? <Loader2 size={12} className="animate-spin" /> : <Download size={12} />}
412
+ 导出表格
413
+ </button>
286
414
  </div>
287
415
 
288
416
  {/* Session list */}
@@ -425,6 +553,56 @@ const SessionRow = ({
425
553
  return () => window.clearInterval(intervalId);
426
554
  }, [isExpanded, session.live, session.teamName, session.id, historyLimit]);
427
555
 
556
+ // SSE-driven immediate refresh: when inbox or lead-message events arrive for
557
+ // this session's team, refresh the detail right away instead of waiting for
558
+ // the next polling cycle. This makes agent replies appear in <100ms.
559
+ useEffect(() => {
560
+ if (!isExpanded) {
561
+ return;
562
+ }
563
+ const unsubscribe = api.teams.onTeamChange?.((_event, change: TeamChangeEvent) => {
564
+ if (change.teamName !== session.teamName) {
565
+ return;
566
+ }
567
+ if (change.type !== 'inbox' && change.type !== 'lead-message') {
568
+ return;
569
+ }
570
+ void (async () => {
571
+ try {
572
+ const d = await api.teams.getSessionDetail(session.teamName, session.id, historyLimit);
573
+ setDetail(d);
574
+ } catch {
575
+ // silent
576
+ }
577
+ })();
578
+ });
579
+ return () => {
580
+ if (typeof unsubscribe === 'function') {
581
+ unsubscribe();
582
+ }
583
+ };
584
+ }, [isExpanded, session.teamName, session.id, historyLimit]);
585
+
586
+ // Final refresh when session transitions from live → non-live.
587
+ // The polling useEffect above stops when live becomes false, which can miss
588
+ // the last few messages. This effect ensures we capture the complete
589
+ // conversation when the agent finishes.
590
+ const prevLiveRef = useRef(session.live);
591
+ useEffect(() => {
592
+ const wasLive = prevLiveRef.current;
593
+ prevLiveRef.current = session.live;
594
+ if (wasLive && !session.live && isExpanded) {
595
+ void (async () => {
596
+ try {
597
+ const d = await api.teams.getSessionDetail(session.teamName, session.id, historyLimit);
598
+ setDetail(d);
599
+ } catch {
600
+ // silent
601
+ }
602
+ })();
603
+ }
604
+ }, [session.live, isExpanded, session.teamName, session.id, historyLimit]);
605
+
428
606
  const handleLoadMoreHistory = useCallback(() => {
429
607
  if (loadingDetail || loadingMoreHistory || !hasMoreHistory) {
430
608
  return;
@@ -19,7 +19,7 @@ import type { LucideIcon } from 'lucide-react';
19
19
 
20
20
  const statusConfig: Record<TeamTaskStatus, { icon: LucideIcon; color: string; label: string }> = {
21
21
  pending: { icon: Circle, color: 'text-amber-400', label: 'pending' },
22
- in_progress: { icon: Loader2, color: 'text-blue-400', label: 'in progress' },
22
+ in_progress: { icon: Loader2, color: 'text-indigo-400', label: 'in progress' },
23
23
  completed: { icon: CheckCircle2, color: 'text-emerald-400', label: 'completed' },
24
24
  deleted: { icon: Circle, color: 'text-zinc-500', label: 'deleted' },
25
25
  };
@@ -145,7 +145,7 @@ export const SidebarTaskItem = ({
145
145
 
146
146
  const showTeamRow = showTeamName && !hideTeamName;
147
147
  const unreadBackgroundClass =
148
- unreadCount > 0 ? (isLight ? 'bg-blue-500/[0.03]' : 'bg-blue-500/[0.05]') : '';
148
+ unreadCount > 0 ? (isLight ? 'bg-indigo-500/[0.03]' : 'bg-indigo-500/[0.05]') : '';
149
149
 
150
150
  return (
151
151
  <button
@@ -205,9 +205,9 @@ export const SidebarTaskItem = ({
205
205
  <StatusIcon className={`mr-1.5 inline-block size-3 align-[-1px] ${cfg.color}`} />
206
206
  {unreadCount > 0 &&
207
207
  (unreadCount === 1 ? (
208
- <span className="mr-1 inline-block size-1.5 rounded-full bg-blue-400 align-middle" />
208
+ <span className="mr-1 inline-block size-1.5 rounded-full bg-indigo-400 align-middle" />
209
209
  ) : (
210
- <span className="mr-1 inline-flex size-3.5 items-center justify-center rounded-full bg-blue-500 align-middle text-[8px] font-bold leading-none text-white">
210
+ <span className="mr-1 inline-flex size-3.5 items-center justify-center rounded-full bg-indigo-500 align-middle text-[8px] font-bold leading-none text-white">
211
211
  {unreadCount > 9 ? '9+' : unreadCount}
212
212
  </span>
213
213
  ))}
@@ -7,6 +7,7 @@ import { Folder, FolderOpen, ChevronRight, ChevronDown, ArrowUp, HardDrive } fro
7
7
  import { useShallow } from 'zustand/react/shallow';
8
8
 
9
9
  import type { WorkspaceFileEntry, WorkspaceListResponse } from '@shared/types/editor';
10
+ import { SYSTEM_MANAGER_DISPLAY_NAME, SYSTEM_MANAGER_TEAM_NAME } from '@shared/types/team';
10
11
 
11
12
  function getRelativePath(currentDir: string, rootPath: string): string {
12
13
  if (!currentDir || currentDir === rootPath) return '';
@@ -141,8 +142,13 @@ const TeamWorkspace = ({
141
142
  className={`shrink-0 text-[var(--color-text-muted)] transition-transform ${isExpanded ? '' : '-rotate-90'}`}
142
143
  />
143
144
  <HardDrive size={14} className="shrink-0 text-[var(--color-text-muted)]" />
144
- <span className="min-w-0 flex-1 truncate text-sm font-medium text-[var(--color-text)]">
145
- {teamDisplayName}
145
+ <span className="min-w-0 flex-1">
146
+ <span className="block truncate text-sm font-medium text-[var(--color-text)]">
147
+ {teamDisplayName}
148
+ </span>
149
+ <span className="block truncate font-mono text-[10px] text-[var(--color-text-muted)]" title={projectPath}>
150
+ {projectPath}
151
+ </span>
146
152
  </span>
147
153
  <span className="shrink-0 rounded bg-blue-500/20 px-1.5 py-0.5 text-[10px] font-medium text-blue-400">
148
154
  当前
@@ -254,6 +260,7 @@ export const WorkspaceBrowser = (): React.JSX.Element => {
254
260
  }))
255
261
  );
256
262
  const revealFileInEditor = useStore((s) => s.revealFileInEditor);
263
+ const [systemManagerProjectPath, setSystemManagerProjectPath] = useState<string | null>(null);
257
264
 
258
265
  const scopedTeamName = useMemo(() => {
259
266
  if (!activeTabId) {
@@ -268,10 +275,38 @@ export const WorkspaceBrowser = (): React.JSX.Element => {
268
275
  return selectedTeamName;
269
276
  }, [activeTabId, paneLayout.panes, selectedTeamName]);
270
277
 
278
+ useEffect(() => {
279
+ if (scopedTeamName !== SYSTEM_MANAGER_TEAM_NAME) {
280
+ setSystemManagerProjectPath(null);
281
+ return;
282
+ }
283
+
284
+ let cancelled = false;
285
+ void api.systemManager
286
+ .getConfig()
287
+ .then((config) => {
288
+ if (!cancelled) setSystemManagerProjectPath(config.selectedWorkDir);
289
+ })
290
+ .catch(() => {
291
+ if (!cancelled) setSystemManagerProjectPath(null);
292
+ });
293
+
294
+ return () => {
295
+ cancelled = true;
296
+ };
297
+ }, [scopedTeamName]);
298
+
271
299
  const currentTeamWorkspace = useMemo(() => {
272
300
  if (!scopedTeamName) {
273
301
  return null;
274
302
  }
303
+ if (scopedTeamName === SYSTEM_MANAGER_TEAM_NAME) {
304
+ return {
305
+ teamName: SYSTEM_MANAGER_TEAM_NAME,
306
+ teamDisplayName: SYSTEM_MANAGER_DISPLAY_NAME,
307
+ projectPath: systemManagerProjectPath,
308
+ };
309
+ }
275
310
  const team = teams.find((candidate) => candidate.teamName === scopedTeamName);
276
311
  if (!team) {
277
312
  return null;
@@ -289,7 +324,7 @@ export const WorkspaceBrowser = (): React.JSX.Element => {
289
324
  teamDisplayName: team.displayName || team.teamName,
290
325
  projectPath,
291
326
  };
292
- }, [scopedTeamName, teams]);
327
+ }, [scopedTeamName, systemManagerProjectPath, teams]);
293
328
 
294
329
  const [expanded, setExpanded] = useState(true);
295
330
 
@@ -334,7 +369,7 @@ export const WorkspaceBrowser = (): React.JSX.Element => {
334
369
  <div className="flex h-full flex-col overflow-hidden">
335
370
  <div className="flex-1 overflow-y-auto">
336
371
  <TeamWorkspace
337
- key={currentTeamWorkspace.teamName}
372
+ key={`${currentTeamWorkspace.teamName}:${currentTeamWorkspace.projectPath}`}
338
373
  teamDisplayName={currentTeamWorkspace.teamDisplayName}
339
374
  projectPath={currentTeamWorkspace.projectPath}
340
375
  isExpanded={expanded}