@yancyyu/openhermit 1.6.38 → 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 (188) hide show
  1. package/dist-renderer/assets/ProjectEditorOverlay-krO5vQxX.js +58 -0
  2. package/dist-renderer/assets/{TeamGraphOverlay-ZEDfZyHb.js → TeamGraphOverlay-DqhQzcTr.js} +1 -1
  3. package/dist-renderer/assets/{_basePickBy-CIhniz70.js → _basePickBy-B7kSYPxr.js} +1 -1
  4. package/dist-renderer/assets/{_baseUniq-cKAW4Q8I.js → _baseUniq-CnjxqwAk.js} +1 -1
  5. package/dist-renderer/assets/{arc-YmNsoDXW.js → arc-CLeZuINP.js} +1 -1
  6. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DHEls2sX.js → architectureDiagram-VXUJARFQ-QKtqaqdY.js} +1 -1
  7. package/dist-renderer/assets/{blockDiagram-VD42YOAC-Bpwf1Sbg.js → blockDiagram-VD42YOAC-BqdrzO_f.js} +1 -1
  8. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-B0IaQ4w5.js → c4Diagram-YG6GDRKO-gwPlCxDC.js} +1 -1
  9. package/dist-renderer/assets/channel-DpMHF50r.js +1 -0
  10. package/dist-renderer/assets/{chunk-4BX2VUAB-DLk-hcFc.js → chunk-4BX2VUAB-C6XLurL4.js} +1 -1
  11. package/dist-renderer/assets/{chunk-55IACEB6-1XRmX_Zm.js → chunk-55IACEB6-Ds6quhEP.js} +1 -1
  12. package/dist-renderer/assets/{chunk-B4BG7PRW-1waH1DAD.js → chunk-B4BG7PRW-5UlA1_e9.js} +1 -1
  13. package/dist-renderer/assets/{chunk-DI55MBZ5-BqpZBtrN.js → chunk-DI55MBZ5-ywFrqIsY.js} +1 -1
  14. package/dist-renderer/assets/{chunk-FMBD7UC4-Bly7vVym.js → chunk-FMBD7UC4-C7ifUA17.js} +1 -1
  15. package/dist-renderer/assets/{chunk-QN33PNHL-Ci2QWBAs.js → chunk-QN33PNHL-BxGCo80U.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QZHKN3VN-YCqFW7d-.js → chunk-QZHKN3VN-B2CuaZs6.js} +1 -1
  17. package/dist-renderer/assets/{chunk-TZMSLE5B-B0xGXInl.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-DxcFNQKT.js → cose-bilkent-S5V4N54A-Cz1GVtLp.js} +1 -1
  22. package/dist-renderer/assets/{dagre-6UL2VRFP-DPo_RfZY.js → dagre-6UL2VRFP-BrmR-P4h.js} +1 -1
  23. package/dist-renderer/assets/{diagram-PSM6KHXK-U3hQsFe4.js → diagram-PSM6KHXK-DbNjC5Rg.js} +1 -1
  24. package/dist-renderer/assets/{diagram-QEK2KX5R-OrwrAy0V.js → diagram-QEK2KX5R-qkRX5_Mq.js} +1 -1
  25. package/dist-renderer/assets/{diagram-S2PKOQOG-CXATPWVw.js → diagram-S2PKOQOG-CyL5rCv2.js} +1 -1
  26. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-B0e8AfMF.js → erDiagram-Q2GNP2WA-Dox3-bA5.js} +1 -1
  27. package/dist-renderer/assets/{flowDiagram-NV44I4VS-CXfzA4jJ.js → flowDiagram-NV44I4VS-BtkaxlDL.js} +1 -1
  28. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-CMr08qVl.js → ganttDiagram-JELNMOA3-Dhy_d9GK.js} +1 -1
  29. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-vYFHpPmy.js → gitGraphDiagram-V2S2FVAM-B5XRhIQA.js} +1 -1
  30. package/dist-renderer/assets/{graph-DOe5j8dH.js → graph-CsoEwUhS.js} +1 -1
  31. package/dist-renderer/assets/{index-BySQS7AB.js → index-BWPWmJNo.js} +1 -1
  32. package/dist-renderer/assets/{index-V7dAKPqd.js → index-Bu2R-Se7.js} +587 -705
  33. package/dist-renderer/assets/index-CnWV3BhG.css +32 -0
  34. package/dist-renderer/assets/{index-CzWxVCRL.js → index-D-3KgskL.js} +1 -1
  35. package/dist-renderer/assets/{index-VJ-MM9xa.js → index-DGEBzLNT.js} +1 -1
  36. package/dist-renderer/assets/{index-B2Dy7M2G.js → index-NhHNs2Oo.js} +1 -1
  37. package/dist-renderer/assets/{index-C_okzZXP.js → index-h17WuEyf.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D_WubR0B.js → infoDiagram-HS3SLOUP-hMGmNojH.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-w9ca-1TI.js → journeyDiagram-XKPGCS4Q-DXV2rBDl.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-Jg9p6_pN.js → kanban-definition-3W4ZIXB7-Bf99WLRy.js} +1 -1
  41. package/dist-renderer/assets/{layout-B-z3y17c.js → layout-C3XWrpwo.js} +1 -1
  42. package/dist-renderer/assets/{linear-D-RTX5UW.js → linear-OEEcn8KN.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-CDQmHOYP.js → mindmap-definition-VGOIOE7T-Dpi3S2x4.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-D_odsQL7.js → pieDiagram-ADFJNKIX-xTPPhtNx.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-BRsmYWSA.js → quadrantDiagram-AYHSOK5B-euniyDlz.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-ChNE_BOV.js → requirementDiagram-UZGBJVZJ-D9Uiw4kF.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-C8FtpwKc.js → sankeyDiagram-TZEHDZUN-CySU4nED.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-DmLCzNcc.js → sequenceDiagram-WL72ISMW-JVGpET6V.js} +1 -1
  49. package/dist-renderer/assets/splashScene-D0YB9uxm.js +17 -0
  50. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-WJBm4bhu.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-BXs_hOJs.js → timeline-definition-IT6M3QCI-DmycNUUe.js} +1 -1
  53. package/dist-renderer/assets/{treemap-GDKQZRPO-o04MA0G9.js → treemap-GDKQZRPO-DPq4gZuB.js} +1 -1
  54. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-Czj69XRd.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 +2 -1
  58. package/src/main/server.ts +873 -221
  59. package/src/main/services/extensions/ExtensionFacadeService.ts +2 -5
  60. package/src/main/services/extensions/catalog/PluginCatalogService.ts +4 -2
  61. package/src/main/services/session-intelligence/ConversationTelemetryService.ts +1101 -0
  62. package/src/main/services/session-intelligence/LocalSessionScanner.ts +512 -0
  63. package/src/main/services/session-intelligence/SessionUsageParser.ts +4 -4
  64. package/src/main/services/system-manager/SystemManagerConfigService.ts +122 -0
  65. package/src/main/services/system-manager/SystemManagerPtyService.ts +233 -0
  66. package/src/main/services/system-manager/WorkflowPromptService.ts +75 -0
  67. package/src/main/services/teams-mvp/TaskDispatchService.ts +5 -6
  68. package/src/main/services/teams-mvp/TeamProvisioningService.ts +39 -2
  69. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +22 -4
  70. package/src/main/utils/teamProjectResolution.ts +15 -0
  71. package/src/renderer/App.tsx +8 -4
  72. package/src/renderer/api/httpClient.ts +68 -18
  73. package/src/renderer/api/providers.ts +23 -2
  74. package/src/renderer/assets/participant-avatars/01.svg +3 -0
  75. package/src/renderer/assets/participant-avatars/02.svg +3 -0
  76. package/src/renderer/assets/participant-avatars/03.svg +3 -0
  77. package/src/renderer/assets/participant-avatars/04.svg +3 -0
  78. package/src/renderer/assets/participant-avatars/05.svg +3 -0
  79. package/src/renderer/assets/participant-avatars/06.svg +3 -0
  80. package/src/renderer/assets/participant-avatars/07.svg +3 -0
  81. package/src/renderer/assets/participant-avatars/08.svg +3 -0
  82. package/src/renderer/assets/participant-avatars/09.svg +3 -0
  83. package/src/renderer/assets/participant-avatars/10.svg +3 -0
  84. package/src/renderer/assets/participant-avatars/11.svg +3 -0
  85. package/src/renderer/assets/participant-avatars/12.svg +3 -0
  86. package/src/renderer/assets/participant-avatars/13.svg +3 -0
  87. package/src/renderer/components/common/TerminalPane.tsx +213 -0
  88. package/src/renderer/components/dashboard/DashboardView.tsx +9 -36
  89. package/src/renderer/components/extensions/ExtensionStoreView.tsx +6 -125
  90. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
  91. package/src/renderer/components/extensions/mcp/McpLibraryEnableDialog.tsx +305 -0
  92. package/src/renderer/components/extensions/mcp/McpLibraryEntryDialog.tsx +418 -0
  93. package/src/renderer/components/extensions/mcp/McpLibraryPanel.tsx +404 -0
  94. package/src/renderer/components/extensions/plugins/PluginCard.tsx +6 -6
  95. package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +34 -21
  96. package/src/renderer/components/extensions/skills/SkillsLibraryPanel.tsx +335 -0
  97. package/src/renderer/components/layout/PaneContent.tsx +8 -1
  98. package/src/renderer/components/layout/Sidebar.tsx +11 -54
  99. package/src/renderer/components/layout/SortableTab.tsx +20 -31
  100. package/src/renderer/components/layout/TabBar.tsx +1 -1
  101. package/src/renderer/components/layout/TabContextMenu.tsx +1 -1
  102. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +768 -157
  103. package/src/renderer/components/schedules/SchedulesView.tsx +51 -462
  104. package/src/renderer/components/schedules/calendar/CalendarDayView.tsx +173 -0
  105. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +113 -0
  106. package/src/renderer/components/schedules/calendar/CalendarHeader.tsx +148 -0
  107. package/src/renderer/components/schedules/calendar/CalendarMonthView.tsx +142 -0
  108. package/src/renderer/components/schedules/calendar/CalendarWeekView.tsx +219 -0
  109. package/src/renderer/components/schedules/calendar/ScheduleCalendarBoard.tsx +41 -0
  110. package/src/renderer/components/schedules/calendar/TeamGanttView.tsx +405 -0
  111. package/src/renderer/components/schedules/calendar/computeOccurrences.ts +234 -0
  112. package/src/renderer/components/schedules/calendar/index.ts +2 -0
  113. package/src/renderer/components/schedules/calendar/types.ts +44 -0
  114. package/src/renderer/components/settings/SettingsTabs.tsx +50 -55
  115. package/src/renderer/components/settings/SettingsView.tsx +30 -35
  116. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +5 -1
  117. package/src/renderer/components/settings/components/SettingsSelect.tsx +5 -3
  118. package/src/renderer/components/settings/components/SettingsToggle.tsx +2 -2
  119. package/src/renderer/components/settings/sections/AdvancedSection.tsx +11 -42
  120. package/src/renderer/components/settings/sections/CliStatusSection.tsx +71 -112
  121. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  122. package/src/renderer/components/settings/sections/GeneralSection.tsx +11 -3
  123. package/src/renderer/components/settings/sections/HarnessSection.tsx +18 -14
  124. package/src/renderer/components/settings/sections/PlatformsSection.tsx +3 -3
  125. package/src/renderer/components/settings/sections/TaskBusSection.tsx +33 -40
  126. package/src/renderer/components/settings/sections/index.ts +0 -1
  127. package/src/renderer/components/sidebar/SidebarSessions.tsx +182 -4
  128. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +4 -4
  129. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +39 -4
  130. package/src/renderer/components/splash/splashScene.ts +121 -929
  131. package/src/renderer/components/system-manager/FolderBrowser.tsx +163 -0
  132. package/src/renderer/components/system-manager/SystemManagerView.tsx +351 -0
  133. package/src/renderer/components/tasks/TasksView.tsx +112 -134
  134. package/src/renderer/components/team/CcSessionsSection.tsx +431 -89
  135. package/src/renderer/components/team/CollapsibleTeamSection.tsx +17 -32
  136. package/src/renderer/components/team/TeamDetailView.tsx +319 -123
  137. package/src/renderer/components/team/TeamListView.tsx +108 -123
  138. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +2 -2
  139. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +84 -306
  140. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +259 -342
  141. package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +1 -1
  142. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +17 -15
  143. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +221 -0
  144. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +7 -0
  145. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +1 -1
  146. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +361 -0
  147. package/src/renderer/components/team/dialogs/platformMeta.ts +122 -11
  148. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +17 -5
  149. package/src/renderer/components/team/kanban/KanbanBoard.tsx +9 -9
  150. package/src/renderer/components/team/members/MemberCard.tsx +14 -47
  151. package/src/renderer/components/team/members/MemberDetailDialog.tsx +3 -95
  152. package/src/renderer/components/team/members/MemberDetailStats.tsx +50 -65
  153. package/src/renderer/components/team/messages/MessageComposer.tsx +8 -110
  154. package/src/renderer/components/team/messages/MessagesPanel.tsx +131 -114
  155. package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +2 -2
  156. package/src/renderer/components/team/tools/AddMcpInline.tsx +27 -17
  157. package/src/renderer/components/team/tools/McpChip.tsx +6 -3
  158. package/src/renderer/components/team/tools/SkillChip.tsx +2 -2
  159. package/src/renderer/components/team/tools/ToolsSection.tsx +418 -70
  160. package/src/renderer/hooks/useExtensionsTabState.ts +3 -114
  161. package/src/renderer/index.css +39 -22
  162. package/src/renderer/index.html +17 -50
  163. package/src/renderer/store/index.ts +2 -1
  164. package/src/renderer/store/slices/scheduleSlice.ts +1 -1
  165. package/src/renderer/store/slices/teamSlice.ts +45 -168
  166. package/src/renderer/utils/claudeCodeOnlyProviders.ts +3 -10
  167. package/src/renderer/utils/memberHelpers.ts +5 -17
  168. package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +4 -2
  169. package/src/renderer/utils/providerSlashCommands.ts +0 -5
  170. package/src/renderer/utils/scheduleFormatters.ts +3 -1
  171. package/src/renderer/utils/teamMessageFiltering.ts +14 -1
  172. package/src/renderer/utils/teamModelAvailability.ts +18 -2
  173. package/src/shared/types/api.ts +121 -2
  174. package/src/shared/types/ccConnect.ts +2 -0
  175. package/src/shared/types/index.ts +3 -0
  176. package/src/shared/types/systemManager.ts +49 -0
  177. package/src/shared/types/team.ts +29 -0
  178. package/src/shared/types/terminal.ts +4 -2
  179. package/src/shared/utils/extensionNormalizers.ts +15 -8
  180. package/src/shared/utils/providerExtensionCapabilities.ts +2 -2
  181. package/dist-renderer/assets/ProjectEditorOverlay-lJZi-9Hp.js +0 -52
  182. package/dist-renderer/assets/channel-yIlSKy0e.js +0 -1
  183. package/dist-renderer/assets/classDiagram-2ON5EDUG-24fHez0s.js +0 -1
  184. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-24fHez0s.js +0 -1
  185. package/dist-renderer/assets/clone-BTNuUva-.js +0 -1
  186. package/dist-renderer/assets/index-Bi6nrZ4z.css +0 -1
  187. package/dist-renderer/assets/splashScene-C8lWNnm4.js +0 -1
  188. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-_m6iPPUR.js +0 -1
@@ -607,55 +607,22 @@ export const MemberCard = ({
607
607
  className="shrink-0"
608
608
  title={totalTasks > 0 ? `${completed}/${totalTasks} completed` : undefined}
609
609
  >
610
- <Badge
611
- variant="secondary"
612
- className="shrink-0 px-1.5 py-0.5 text-[10px] font-normal leading-none"
613
- >
614
- {member.taskCount} {member.taskCount === 1 ? 'task' : 'tasks'}
615
- </Badge>
616
610
  {totalTasks > 0 && (
617
- <div className="mx-0.5 mt-0.5 h-[2px] rounded-full bg-[var(--color-border)]">
618
- <div
619
- className="h-full rounded-full bg-emerald-500 transition-all duration-500"
620
- style={{ width: `${progressPercent}%` }}
621
- />
622
- </div>
623
- )}
624
- {/* NOTE: lead context bar disabled — usage formula is inaccurate */}
625
- </div>
626
- )}
627
- {!isRemoved && (
628
- <div className="flex shrink-0 items-center gap-0.5">
629
- <Tooltip>
630
- <TooltipTrigger asChild>
631
- <button
632
- type="button"
633
- className="rounded p-1 text-[var(--color-text-muted)] transition-colors hover:bg-[var(--color-surface)] hover:text-[var(--color-text)]"
634
- onClick={(e) => {
635
- e.stopPropagation();
636
- onSendMessage?.();
637
- }}
638
- >
639
- <MessageSquare size={13} />
640
- </button>
641
- </TooltipTrigger>
642
- <TooltipContent side="bottom">发送消息</TooltipContent>
643
- </Tooltip>
644
- <Tooltip>
645
- <TooltipTrigger asChild>
646
- <button
647
- type="button"
648
- className="rounded p-1 text-[var(--color-text-muted)] transition-colors hover:bg-[var(--color-surface)] hover:text-[var(--color-text)]"
649
- onClick={(e) => {
650
- e.stopPropagation();
651
- onAssignTask?.();
652
- }}
611
+ <>
612
+ <Badge
613
+ variant="secondary"
614
+ className="shrink-0 px-1.5 py-0.5 text-[10px] font-normal leading-none"
653
615
  >
654
- <Plus size={13} />
655
- </button>
656
- </TooltipTrigger>
657
- <TooltipContent side="bottom">分配任务</TooltipContent>
658
- </Tooltip>
616
+ {completed}/{totalTasks}
617
+ </Badge>
618
+ <div className="mx-0.5 mt-0.5 h-[2px] rounded-full bg-[var(--color-border)]">
619
+ <div
620
+ className="h-full rounded-full bg-emerald-500 transition-all duration-500"
621
+ style={{ width: `${progressPercent}%` }}
622
+ />
623
+ </div>
624
+ </>
625
+ )}
659
626
  </div>
660
627
  )}
661
628
  </div>
@@ -1,11 +1,7 @@
1
1
  import { useEffect, useMemo, useState } from 'react';
2
2
 
3
- import { Button } from '@renderer/components/ui/button';
4
3
  import { Dialog, DialogContent, DialogFooter, DialogHeader } from '@renderer/components/ui/dialog';
5
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '@renderer/components/ui/tabs';
6
4
  import { useMemberStats } from '@renderer/hooks/useMemberStats';
7
- import { useStore } from '@renderer/store';
8
- import { selectMemberMessagesForTeamMember } from '@renderer/store/slices/teamSlice';
9
5
  import {
10
6
  buildMemberLaunchDiagnosticsPayload,
11
7
  getMemberLaunchDiagnosticsErrorMessage,
@@ -17,16 +13,10 @@ import {
17
13
  resolveMemberRuntimeSummary,
18
14
  } from '@renderer/utils/memberRuntimeSummary';
19
15
  import { isLeadMember } from '@shared/utils/leadDetection';
20
- import { BarChart3, FolderOpen, Loader2 } from 'lucide-react';
21
16
 
22
- import { buildMemberActivityEntries } from './memberActivityEntries';
23
17
  import { MemberDetailHeader } from './MemberDetailHeader';
24
18
  import { MemberDetailStats } from './MemberDetailStats';
25
- import { type MemberActivityFilter, type MemberDetailTab } from './memberDetailTypes';
26
19
  import { MemberLaunchDiagnosticsButton } from './MemberLaunchDiagnosticsButton';
27
- import { MemberMessagesTab } from './MemberMessagesTab';
28
- import { MemberStatsTab } from './MemberStatsTab';
29
- import { MemberWorkspaceTab } from './MemberWorkspaceTab';
30
20
 
31
21
  import type { TeamLaunchParams } from '@renderer/store/slices/teamSlice';
32
22
  import type {
@@ -43,8 +33,6 @@ interface MemberDetailDialogProps {
43
33
  teamName: string;
44
34
  members: ResolvedTeamMember[];
45
35
  tasks: TeamTaskWithKanban[];
46
- initialTab?: MemberDetailTab;
47
- initialActivityFilter?: MemberActivityFilter;
48
36
  isTeamAlive?: boolean;
49
37
  isTeamProvisioning?: boolean;
50
38
  isLaunchSettling?: boolean;
@@ -72,8 +60,6 @@ export const MemberDetailDialog = ({
72
60
  teamName,
73
61
  members,
74
62
  tasks,
75
- initialTab = 'tasks',
76
- initialActivityFilter = 'all',
77
63
  isTeamAlive,
78
64
  isTeamProvisioning,
79
65
  isLaunchSettling,
@@ -90,25 +76,6 @@ export const MemberDetailDialog = ({
90
76
  updatingRole,
91
77
  onViewMemberChanges,
92
78
  }: MemberDetailDialogProps): React.JSX.Element | null => {
93
- const memberMessages = useStore((state) =>
94
- selectMemberMessagesForTeamMember(state, teamName, member?.name ?? null)
95
- );
96
- const memberActivityCount = useMemo(() => {
97
- if (!member) {
98
- return 0;
99
- }
100
- return buildMemberActivityEntries({
101
- teamName,
102
- memberName: member.name,
103
- members,
104
- tasks,
105
- messages: memberMessages,
106
- }).length;
107
- }, [member, memberMessages, members, tasks, teamName]);
108
-
109
- const [activeTab, setActiveTab] = useState<MemberDetailTab>(
110
- initialTab === 'tasks' ? 'workspace' : initialTab
111
- );
112
79
  const [restarting, setRestarting] = useState(false);
113
80
  const [restartError, setRestartError] = useState<string | null>(null);
114
81
 
@@ -149,10 +116,9 @@ export const MemberDetailDialog = ({
149
116
  if (!open || !member) {
150
117
  return;
151
118
  }
152
- setActiveTab(initialTab);
153
119
  setRestartError(null);
154
120
  setRestarting(false);
155
- }, [initialTab, member, open]);
121
+ }, [member, open]);
156
122
 
157
123
  const {
158
124
  stats: memberStats,
@@ -160,8 +126,6 @@ export const MemberDetailDialog = ({
160
126
  error: statsError,
161
127
  } = useMemberStats(teamName, member?.name ?? null);
162
128
 
163
- const totalTokens = memberStats ? memberStats.inputTokens + memberStats.outputTokens : null;
164
-
165
129
  if (!member) return null;
166
130
 
167
131
  return (
@@ -189,68 +153,12 @@ export const MemberDetailDialog = ({
189
153
  </DialogHeader>
190
154
 
191
155
  <MemberDetailStats
192
- totalTasks={0}
193
- inProgressTasks={0}
194
- totalTokens={totalTokens}
156
+ stats={memberStats}
195
157
  statsLoading={statsLoading}
196
- statsComputedAt={memberStats?.computedAt}
197
- onTabChange={setActiveTab}
158
+ statsError={statsError}
198
159
  />
199
160
  </div>
200
161
 
201
- <Tabs
202
- value={activeTab}
203
- onValueChange={(v) => setActiveTab(v as MemberDetailTab)}
204
- className="min-w-0 overflow-hidden"
205
- >
206
- <TabsList className="w-full">
207
- <TabsTrigger value="workspace" className="flex-1 gap-1.5">
208
- <FolderOpen size={12} />
209
- Workspace
210
- </TabsTrigger>
211
- <TabsTrigger value="activity" className="flex-1 gap-1.5">
212
- Activity
213
- {memberActivityCount > 0 && (
214
- <span className="rounded-full bg-[var(--color-surface)] px-1.5 text-[10px]">
215
- {memberActivityCount}
216
- </span>
217
- )}
218
- </TabsTrigger>
219
- <TabsTrigger value="stats" className="flex-1 gap-1.5">
220
- <BarChart3 size={12} />
221
- Stats
222
- </TabsTrigger>
223
- </TabsList>
224
- <TabsContent value="workspace">
225
- <MemberWorkspaceTab
226
- teamName={teamName}
227
- memberName={member.name}
228
- onFileClick={(filePath) => onViewMemberChanges?.(member.name, filePath)}
229
- onViewAllChanges={() => onViewMemberChanges?.(member.name)}
230
- />
231
- </TabsContent>
232
- <TabsContent value="activity">
233
- <MemberMessagesTab
234
- teamName={teamName}
235
- memberName={member.name}
236
- members={members}
237
- tasks={tasks}
238
- initialFilter={initialActivityFilter}
239
- />
240
- </TabsContent>
241
- <TabsContent value="stats">
242
- <MemberStatsTab
243
- teamName={teamName}
244
- memberName={member.name}
245
- prefetchedStats={memberStats}
246
- prefetchedLoading={statsLoading}
247
- prefetchedError={statsError}
248
- onFileClick={(filePath) => onViewMemberChanges?.(member.name, filePath)}
249
- onShowAllFiles={() => onViewMemberChanges?.(member.name)}
250
- />
251
- </TabsContent>
252
- </Tabs>
253
-
254
162
  <DialogFooter>
255
163
  {restartError ? (
256
164
  <div className="text-xs text-red-400">{restartError}</div>
@@ -1,80 +1,65 @@
1
- import { formatRelativeTime, formatTokensCompact } from '@renderer/utils/formatters';
1
+ import { formatDuration, formatTokensCompact } from '@renderer/utils/formatters';
2
2
 
3
- import type { MemberDetailTab } from './memberDetailTypes';
3
+ import type { MemberFullStats } from '@shared/types';
4
4
 
5
5
  interface MemberDetailStatsProps {
6
- totalTasks: number;
7
- inProgressTasks: number;
8
- totalTokens: number | null;
6
+ stats: MemberFullStats | null;
9
7
  statsLoading?: boolean;
10
- statsComputedAt?: string;
11
- onTabChange?: (tab: MemberDetailTab) => void;
8
+ statsError?: string | null;
12
9
  }
13
10
 
14
- const baseClasses =
15
- 'rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] px-2.5 py-1.5';
16
- const clickableClasses =
17
- 'cursor-pointer transition-colors hover:border-[var(--color-border-emphasis)] hover:bg-[var(--color-surface-overlay)]';
18
-
19
- const StatBlock = ({
20
- label,
21
- value,
22
- sub,
23
- onClick,
24
- }: {
25
- label: string;
26
- value: string | number;
27
- sub?: string;
28
- onClick?: () => void;
29
- }): React.JSX.Element => {
30
- const classes = onClick ? `${baseClasses} ${clickableClasses}` : baseClasses;
31
- const content = (
32
- <>
33
- <p className="text-base font-semibold leading-tight text-[var(--color-text)]">{value}</p>
34
- <p className="text-[10px] text-[var(--color-text-muted)]">{label}</p>
35
- {sub && <p className="mt-0.5 text-[9px] text-[var(--color-text-muted)]">{sub}</p>}
36
- </>
37
- );
38
- if (onClick) {
39
- return (
40
- <button type="button" className={classes} onClick={onClick}>
41
- {content}
42
- </button>
43
- );
44
- }
45
- return <div className={classes}>{content}</div>;
46
- };
11
+ function formatDurationShort(ms: number): string {
12
+ if (ms < 60_000) return `${Math.round(ms / 1000)}s`;
13
+ const minutes = Math.floor(ms / 60_000);
14
+ if (minutes < 60) return `${minutes}m`;
15
+ const hours = Math.floor(minutes / 60);
16
+ const remainMin = minutes % 60;
17
+ if (hours < 24) return `${hours}h ${remainMin}m`;
18
+ const days = Math.floor(hours / 24);
19
+ return `${days}d ${hours % 24}h`;
20
+ }
47
21
 
48
22
  export const MemberDetailStats = ({
49
- totalTasks,
50
- inProgressTasks,
51
- totalTokens,
23
+ stats,
52
24
  statsLoading,
53
- statsComputedAt,
54
- onTabChange,
55
25
  }: MemberDetailStatsProps): React.JSX.Element => {
56
- const tokensValue = statsLoading
57
- ? '...'
58
- : totalTokens != null
59
- ? formatTokensCompact(totalTokens)
60
- : '';
61
- const tokensSub =
62
- !statsLoading && statsComputedAt ? `updated ${formatRelativeTime(statsComputedAt)}` : undefined;
26
+ const totalTokens = stats ? stats.inputTokens + stats.outputTokens : 0;
27
+
28
+ const items = [
29
+ {
30
+ label: 'Sessions',
31
+ value: statsLoading ? '...' : String(stats?.sessionCount ?? 0),
32
+ sub: !statsLoading && stats ? `${stats.messageCount} messages` : undefined,
33
+ },
34
+ {
35
+ label: 'Tokens',
36
+ value: statsLoading ? '...' : formatTokensCompact(totalTokens),
37
+ },
38
+ {
39
+ label: 'Duration',
40
+ value: statsLoading ? '...' : stats?.totalDurationMs ? formatDurationShort(stats.totalDurationMs) : '—',
41
+ sub: !statsLoading && stats?.tasksCompleted ? `${stats.tasksCompleted} completed` : undefined,
42
+ },
43
+ ];
63
44
 
64
45
  return (
65
- <div className="grid min-w-0 flex-1 grid-cols-2 gap-1.5">
66
- <StatBlock
67
- label="Tasks"
68
- value={totalTasks}
69
- sub={inProgressTasks > 0 ? `进行中: ${inProgressTasks}` : undefined}
70
- onClick={onTabChange ? () => onTabChange('tasks') : undefined}
71
- />
72
- <StatBlock
73
- label="Tokens"
74
- value={tokensValue}
75
- sub={tokensSub}
76
- onClick={onTabChange ? () => onTabChange('stats') : undefined}
77
- />
46
+ <div className="grid min-w-0 flex-1 grid-cols-3 gap-1.5">
47
+ {items.map((item) => (
48
+ <div
49
+ key={item.label}
50
+ className="rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] px-2.5 py-1.5"
51
+ >
52
+ <div className="flex items-baseline gap-1.5">
53
+ <span className="text-sm font-semibold tabular-nums text-[var(--color-text)]">
54
+ {item.value}
55
+ </span>
56
+ <span className="text-[10px] text-[var(--color-text-muted)]">{item.label}</span>
57
+ </div>
58
+ {item.sub && (
59
+ <span className="block text-[9px] text-[var(--color-text-muted)]">{item.sub}</span>
60
+ )}
61
+ </div>
62
+ ))}
78
63
  </div>
79
64
  );
80
65
  };
@@ -33,14 +33,12 @@ import {
33
33
  normalizeOptionalTeamProviderId,
34
34
  } from '@shared/utils/teamProvider';
35
35
  import { AlertCircle, Check, ChevronDown, Mic, Paperclip, Search, Send } from 'lucide-react';
36
- import { useShallow } from 'zustand/react/shallow';
37
36
 
38
37
  import type { MentionSuggestion } from '@renderer/types/mention';
39
38
  import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
40
39
  import type {
41
40
  AgentActionMode,
42
41
  AttachmentPayload,
43
- CcSession,
44
42
  ResolvedTeamMember,
45
43
  SendMessageResult,
46
44
  TaskRef,
@@ -56,9 +54,6 @@ interface MessageComposerProps {
56
54
  sendWarning?: string | null;
57
55
  sendDebugDetails?: OpenCodeRuntimeDeliveryDebugDetails | null;
58
56
  lastResult?: SendMessageResult | null;
59
- sessions?: CcSession[];
60
- selectedSessionKey?: string | null;
61
- onSessionChange?: (sessionKey: string | null) => void;
62
57
  /** Ref to the underlying textarea element for external focus management. */
63
58
  textareaRef?: React.Ref<HTMLTextAreaElement>;
64
59
  onSend: (
@@ -86,9 +81,6 @@ export const MessageComposer = ({
86
81
  sendWarning,
87
82
  sendDebugDetails,
88
83
  lastResult,
89
- sessions = [],
90
- selectedSessionKey = null,
91
- onSessionChange,
92
84
  textareaRef: externalTextareaRef,
93
85
  onSend,
94
86
  onDispatchTask,
@@ -118,7 +110,6 @@ export const MessageComposer = ({
118
110
  const [fileRestrictionError, setFileRestrictionError] = useState<string | null>(null);
119
111
  const fileRestrictionTimerRef = useRef(0);
120
112
  const dismissMentionsRef = useRef<(() => void) | null>(null);
121
- const [teamSelectorOpen, setTeamSelectorOpen] = useState(false);
122
113
 
123
114
  // Members load async with team data; keep recipient stable if valid, otherwise default to lead/first.
124
115
  useEffect(() => {
@@ -135,6 +126,9 @@ export const MessageComposer = ({
135
126
  const projectPath = useStore((s) =>
136
127
  s.selectedTeamName === teamName ? (s.selectedTeamData?.config.projectPath ?? null) : null
137
128
  );
129
+ const skillsUserCatalog = useStore((s) => s.skillsUserCatalog);
130
+ const skillsProjectCatalogByProjectPath = useStore((s) => s.skillsProjectCatalogByProjectPath);
131
+ const fetchSkillsCatalog = useStore((s) => s.fetchSkillsCatalog);
138
132
  const currentTeamColor = useStore((s) => {
139
133
  if (s.selectedTeamName !== teamName) {
140
134
  return nameColorSet(teamName).border;
@@ -146,17 +140,6 @@ export const MessageComposer = ({
146
140
  });
147
141
  const isProvisioning = useStore((s) => isTeamProvisioningActive(s, teamName));
148
142
  const draft = useComposerDraft(teamName);
149
- const selectedSession = useMemo(
150
- () => sessions.find((session) => session.sessionKey === selectedSessionKey) ?? null,
151
- [selectedSessionKey, sessions]
152
- );
153
- const selectedSessionLabel =
154
- selectedSession?.chatName ||
155
- selectedSession?.title ||
156
- selectedSession?.userName ||
157
- selectedSession?.sessionKey ||
158
- '选择会话';
159
-
160
143
  const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
161
144
 
162
145
  const mentionSuggestions = useMemo<MentionSuggestion[]>(
@@ -176,29 +159,22 @@ export const MessageComposer = ({
176
159
  );
177
160
  }, [members]);
178
161
 
179
- const { suggestions: teamMentionSuggestions } = useTeamSuggestions(teamName);
180
- const { suggestions: taskSuggestions } = useTaskSuggestions(teamName);
181
- // Project skills as slash command suggestions
182
- const projectSkills = useStore(
183
- useShallow((s) => (projectPath ? (s.skillsProjectCatalogByProjectPath[projectPath] ?? []) : []))
184
- );
185
- const userSkills = useStore(useShallow((s) => s.skillsUserCatalog));
186
- const fetchSkillsCatalog = useStore((s) => s.fetchSkillsCatalog);
187
-
188
- // Fetch skills catalog for the team's project on mount / project change
189
162
  useEffect(() => {
190
163
  void fetchSkillsCatalog(projectPath ?? undefined);
191
164
  }, [fetchSkillsCatalog, projectPath]);
192
165
 
166
+ const { suggestions: teamMentionSuggestions } = useTeamSuggestions(teamName);
167
+ const { suggestions: taskSuggestions } = useTaskSuggestions(teamName);
168
+ const projectSkills = projectPath ? (skillsProjectCatalogByProjectPath[projectPath] ?? []) : [];
193
169
  const slashCommandSuggestions = useMemo<MentionSuggestion[]>(
194
170
  () =>
195
171
  buildSlashCommandSuggestions(
196
172
  getSuggestedSlashCommandsForProvider(leadProviderId),
197
173
  projectSkills,
198
- userSkills,
174
+ skillsUserCatalog,
199
175
  leadProviderId
200
176
  ),
201
- [leadProviderId, projectSkills, userSkills]
177
+ [leadProviderId, projectSkills, skillsUserCatalog]
202
178
  );
203
179
 
204
180
  const trimmed = stripEncodedTaskReferenceMetadata(draft.text).trim();
@@ -473,84 +449,6 @@ export const MessageComposer = ({
473
449
  'border-[var(--color-border)]'
474
450
  )}
475
451
  >
476
- <Popover open={teamSelectorOpen} onOpenChange={setTeamSelectorOpen}>
477
- <PopoverTrigger asChild>
478
- <button
479
- type="button"
480
- className={cn(
481
- 'inline-flex items-center gap-1.5 border-r border-r-[var(--color-border)] px-2.5 py-1 text-xs transition-colors',
482
- shouldDockRecipientSelector
483
- ? 'rounded-bl-none rounded-tl-[1.35rem]'
484
- : 'rounded-l-full',
485
- 'hover:bg-[var(--color-surface-raised)]'
486
- )}
487
- >
488
- {currentTeamColor ? (
489
- <span
490
- className="inline-block size-2 shrink-0 rounded-full"
491
- style={{ backgroundColor: currentTeamColor }}
492
- />
493
- ) : null}
494
- <span className="max-w-[120px] truncate text-[var(--color-text-secondary)]">
495
- {selectedSessionLabel}
496
- </span>
497
- <ChevronDown size={12} className="shrink-0 text-[var(--color-text-muted)]" />
498
- </button>
499
- </PopoverTrigger>
500
- <PopoverContent align="end" className="w-56 p-1.5">
501
- <div className="max-h-48 space-y-0.5 overflow-y-auto">
502
- {sessions.length > 0 && (
503
- <>
504
- <div className="px-2 py-1 text-[10px] font-medium uppercase tracking-wide text-[var(--color-text-muted)]">
505
- 会话
506
- </div>
507
- {sessions.map((session) => {
508
- const isSelected = selectedSessionKey === session.sessionKey;
509
- const label =
510
- session.chatName ||
511
- session.title ||
512
- session.userName ||
513
- session.sessionKey;
514
- return (
515
- <button
516
- key={session.sessionKey}
517
- type="button"
518
- className={cn(
519
- 'flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-left text-xs transition-colors hover:bg-[var(--color-surface-raised)]',
520
- isSelected && 'bg-[var(--color-surface-raised)]'
521
- )}
522
- onClick={() => {
523
- onSessionChange?.(session.sessionKey);
524
- setTeamSelectorOpen(false);
525
- }}
526
- >
527
- <span
528
- className={cn(
529
- 'inline-block size-2 shrink-0 rounded-full',
530
- session.live && 'animate-pulse'
531
- )}
532
- style={{
533
- backgroundColor: session.live ? '#22c55e' : currentTeamColor,
534
- }}
535
- />
536
- <span className="min-w-0 flex-1 truncate text-[var(--color-text)]">
537
- {label}
538
- </span>
539
- <span className="shrink-0 text-[10px] text-[var(--color-text-muted)]">
540
- {session.platform}
541
- </span>
542
- {isSelected ? (
543
- <Check size={12} className="ml-auto shrink-0 text-blue-400" />
544
- ) : null}
545
- </button>
546
- );
547
- })}
548
- </>
549
- )}
550
- </div>
551
- </PopoverContent>
552
- </Popover>
553
-
554
452
  <Popover open={recipientOpen} onOpenChange={setRecipientOpen}>
555
453
  <PopoverTrigger asChild>
556
454
  <button