@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
@@ -0,0 +1,213 @@
1
+ /**
2
+ * TerminalPane - Reusable xterm.js terminal pane.
3
+ *
4
+ * Extracted from SystemManagerView so any team or panel can embed
5
+ * a terminal connected to a PTY process.
6
+ *
7
+ * Lifecycle:
8
+ * - Mount: creates Terminal + FitAddon, registers SSE listeners
9
+ * - `spawn()` call or autoSpawn: starts a CLI process via the terminal API
10
+ * - Unmount: kills PTY, disposes terminal
11
+ */
12
+ import React, { useCallback, useEffect, useImperativeHandle, useRef } from 'react';
13
+ import { FitAddon } from '@xterm/addon-fit';
14
+ import { WebLinksAddon } from '@xterm/addon-web-links';
15
+ import { Terminal } from '@xterm/xterm';
16
+
17
+ import { api } from '@renderer/api';
18
+ import { cn } from '@renderer/lib/utils';
19
+
20
+ // =============================================================================
21
+ // Types
22
+ // =============================================================================
23
+
24
+ export interface TerminalSpawnOptions {
25
+ command: string;
26
+ args: string[];
27
+ cwd: string;
28
+ }
29
+
30
+ interface TerminalPaneProps {
31
+ /** Extra class names for the container */
32
+ className?: string;
33
+ /** Called after a PTY is spawned successfully */
34
+ onSpawned?: (ptyId: string) => void;
35
+ /** Called when the PTY exits */
36
+ onExit?: (ptyId: string, exitCode: number) => void;
37
+ /** Auto-spawn config. When provided, auto-spawns on mount. */
38
+ autoSpawn?: TerminalSpawnOptions;
39
+ }
40
+
41
+ export interface TerminalPaneRef {
42
+ spawn: (options: TerminalSpawnOptions) => Promise<void>;
43
+ }
44
+
45
+ // =============================================================================
46
+ // TerminalPane
47
+ // =============================================================================
48
+
49
+ export const TerminalPane = React.forwardRef<TerminalPaneRef, TerminalPaneProps>(
50
+ function TerminalPane({ className, onSpawned, onExit, autoSpawn }, ref) {
51
+ const hostRef = useRef<HTMLDivElement>(null);
52
+ const terminalRef = useRef<Terminal | null>(null);
53
+ const fitAddonRef = useRef<FitAddon | null>(null);
54
+ const ptyIdRef = useRef<string | null>(null);
55
+ const spawnedRef = useRef(false);
56
+
57
+ const fitTerminal = useCallback(() => {
58
+ try {
59
+ fitAddonRef.current?.fit();
60
+ if (ptyIdRef.current && terminalRef.current) {
61
+ api.terminal.resize(ptyIdRef.current, terminalRef.current.cols, terminalRef.current.rows);
62
+ }
63
+ } catch {
64
+ // xterm fit can throw when the element is not measurable yet
65
+ }
66
+ }, []);
67
+
68
+ // Expose spawn method via ref
69
+ useImperativeHandle(ref, () => ({
70
+ spawn: async (options: TerminalSpawnOptions) => {
71
+ // Kill existing PTY if any
72
+ if (ptyIdRef.current) {
73
+ try { await api.terminal.kill(ptyIdRef.current); } catch {}
74
+ ptyIdRef.current = null;
75
+ }
76
+ // Clear stale terminal content before spawning new process
77
+ terminalRef.current?.clear();
78
+ try {
79
+ const ptyId = await api.terminal.spawn(options);
80
+ ptyIdRef.current = ptyId;
81
+ spawnedRef.current = true;
82
+ fitTerminal();
83
+ onSpawned?.(ptyId);
84
+ } catch (err) {
85
+ terminalRef.current?.writeln(
86
+ `\x1b[31m[Failed to spawn: ${err instanceof Error ? err.message : String(err)}]\x1b[0m`
87
+ );
88
+ }
89
+ },
90
+ }), [fitTerminal, onSpawned]);
91
+
92
+ // Create terminal instance
93
+ useEffect(() => {
94
+ const host = hostRef.current;
95
+ if (!host) return;
96
+
97
+ const term = new Terminal({
98
+ cursorBlink: true,
99
+ convertEol: true,
100
+ fontFamily: 'JetBrains Mono, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
101
+ fontSize: 13,
102
+ lineHeight: 1.28,
103
+ theme: {
104
+ background: 'var(--color-surface)',
105
+ foreground: 'var(--color-text)',
106
+ cursor: 'var(--color-text)',
107
+ selectionBackground: 'var(--color-border-emphasis)',
108
+ black: 'var(--color-surface-sidebar)',
109
+ red: '#f87171',
110
+ green: '#86efac',
111
+ yellow: '#fde68a',
112
+ blue: 'var(--color-accent)',
113
+ magenta: '#d8b4fe',
114
+ cyan: '#67e8f9',
115
+ white: 'var(--color-text)',
116
+ },
117
+ });
118
+
119
+ const fitAddon = new FitAddon();
120
+ term.loadAddon(fitAddon);
121
+ term.loadAddon(new WebLinksAddon());
122
+ term.open(host);
123
+ terminalRef.current = term;
124
+ fitAddonRef.current = fitAddon;
125
+ fitTerminal();
126
+
127
+ // SSE listeners
128
+ const dataDispose = api.terminal.onData((_event, ptyId, data) => {
129
+ if (ptyId === ptyIdRef.current) term.write(data);
130
+ });
131
+ const exitDispose = api.terminal.onExit((_event, ptyId, exitCode) => {
132
+ if (ptyId === ptyIdRef.current) {
133
+ term.writeln(`\r\n\x1b[90m[process exited with code ${exitCode}]\x1b[0m`);
134
+ onExit?.(ptyId, exitCode);
135
+ ptyIdRef.current = null;
136
+ spawnedRef.current = false;
137
+ }
138
+ });
139
+
140
+ // Input forwarding
141
+ const inputDispose = term.onData((data) => {
142
+ if (ptyIdRef.current) api.terminal.write(ptyIdRef.current, data);
143
+ });
144
+
145
+ // Resize observer
146
+ const resizeObserver = new ResizeObserver(() => fitTerminal());
147
+ resizeObserver.observe(host);
148
+
149
+ return () => {
150
+ dataDispose();
151
+ exitDispose();
152
+ inputDispose.dispose();
153
+ resizeObserver.disconnect();
154
+ if (ptyIdRef.current) {
155
+ void api.terminal.kill(ptyIdRef.current).catch(() => {});
156
+ }
157
+ term.dispose();
158
+ terminalRef.current = null;
159
+ fitAddonRef.current = null;
160
+ ptyIdRef.current = null;
161
+ };
162
+ }, [fitTerminal, onExit]);
163
+
164
+ // Auto-spawn
165
+ // Two issues combined to prevent the CLI from ever spawning:
166
+ // 1. React StrictMode mounts → unmounts → remounts. The first mount set
167
+ // spawnedRef = true and started a 200ms timer; cleanup cleared the timer
168
+ // but NOT the ref. The second mount saw spawnedRef === true → skipped.
169
+ // 2. The parent passes an inline object literal as autoSpawn, producing a
170
+ // new reference each render. With the raw object in deps, every render
171
+ // re-ran the effect, whose cleanup cleared the timeout. spawnedRef was
172
+ // already true, so the retry path was blocked.
173
+ // Fix: reset spawnedRef in cleanup so StrictMode remount can retry, and use
174
+ // a stable string key derived from autoSpawn content instead of the object.
175
+ const autoSpawnKey = autoSpawn
176
+ ? `${autoSpawn.command}\0${autoSpawn.args.join(',')}\0${autoSpawn.cwd}`
177
+ : undefined;
178
+
179
+ useEffect(() => {
180
+ if (!autoSpawnKey || spawnedRef.current) return;
181
+ spawnedRef.current = true;
182
+
183
+ const spawnOpts = autoSpawn!;
184
+
185
+ const doSpawn = async () => {
186
+ try {
187
+ const ptyId = await api.terminal.spawn(spawnOpts);
188
+ ptyIdRef.current = ptyId;
189
+ fitTerminal();
190
+ onSpawned?.(ptyId);
191
+ } catch (err) {
192
+ terminalRef.current?.writeln(
193
+ `\x1b[31m[Failed to spawn: ${err instanceof Error ? err.message : String(err)}]\x1b[0m`
194
+ );
195
+ }
196
+ };
197
+
198
+ const timer = setTimeout(doSpawn, 200);
199
+ return () => {
200
+ clearTimeout(timer);
201
+ spawnedRef.current = false;
202
+ };
203
+ // autoSpawnKey is a stable primitive; autoSpawn is captured via closure.
204
+ // eslint-disable-next-line react-hooks/exhaustive-deps
205
+ }, [autoSpawnKey, fitTerminal, onSpawned]);
206
+
207
+ return (
208
+ <div className={cn('size-full overflow-hidden', className)}>
209
+ <div ref={hostRef} className="size-full" />
210
+ </div>
211
+ );
212
+ }
213
+ );
@@ -7,7 +7,7 @@ import React from 'react';
7
7
 
8
8
  import { RecentProjectsSection } from '@features/recent-projects/renderer';
9
9
  import { useStore } from '@renderer/store';
10
- import { PlugZap, Sparkles, Users, Workflow } from 'lucide-react';
10
+ import { Sparkles, Users, Workflow } from 'lucide-react';
11
11
  import { useShallow } from 'zustand/react/shallow';
12
12
 
13
13
  const HIGHLIGHT_HARNESSES = [
@@ -19,16 +19,6 @@ const HIGHLIGHT_HARNESSES = [
19
19
  'DeepSeek / IM',
20
20
  ];
21
21
 
22
- const HIGHLIGHT_CHANNELS = [
23
- 'Feishu',
24
- 'Slack',
25
- 'Discord',
26
- 'DingTalk',
27
- 'WeCom',
28
- 'Telegram',
29
- 'Webhook / API',
30
- ];
31
-
32
22
  export const DashboardView = (): React.JSX.Element => {
33
23
  const { openTeamsTab, openSettingsTab, teams, teamsLoading } = useStore(
34
24
  useShallow((state) => ({
@@ -58,8 +48,7 @@ export const DashboardView = (): React.JSX.Element => {
58
48
  Hermit:一人公司的 AI 团队控制台
59
49
  </h1>
60
50
  <p className="mt-2 text-sm text-text-secondary">
61
- 几乎覆盖所有主流
62
- Harness,支持全渠道接入,把团队编排、消息协作、任务推进和运行状态放在同一个工作台。
51
+ 几乎覆盖所有主流 Harness,把团队编排、消息协作、任务推进和运行状态放在同一个工作台。
63
52
  </p>
64
53
  </div>
65
54
  <div className="grid gap-4 px-6 py-5 md:grid-cols-3">
@@ -82,21 +71,14 @@ export const DashboardView = (): React.JSX.Element => {
82
71
  </div>
83
72
  <div className="rounded-lg border border-border bg-surface px-4 py-3">
84
73
  <div className="mb-2 inline-flex items-center gap-1.5 text-xs font-medium text-text-secondary">
85
- <PlugZap className="size-3.5" />
86
- 渠道接入
74
+ <Sparkles className="size-3.5" />
75
+ 会话洞察
87
76
  </div>
88
77
  <p className="text-xs text-text-muted">
89
- 统一托管企业 IM、社区渠道和 Webhook/API,消息流和任务流自动对齐。
78
+ 汇总本地会话、任务、消息和 Token 使用情况,帮助你判断团队执行状态。
90
79
  </p>
91
- <div className="mt-3 flex flex-wrap gap-1.5">
92
- {HIGHLIGHT_CHANNELS.map((channel) => (
93
- <span
94
- key={channel}
95
- className="rounded-md border border-border bg-surface-overlay px-2 py-1 text-[11px] text-text-secondary"
96
- >
97
- {channel}
98
- </span>
99
- ))}
80
+ <div className="mt-3 rounded-md border border-border bg-surface-overlay px-2.5 py-2 text-[11px] text-text-muted">
81
+ 会话记录 使用统计 → 身份识别 → 导出复盘
100
82
  </div>
101
83
  </div>
102
84
  <div className="rounded-lg border border-border bg-surface px-4 py-3">
@@ -130,7 +112,7 @@ export const DashboardView = (): React.JSX.Element => {
130
112
  <p className="mt-1 text-xs text-text-muted">
131
113
  首次使用会看到空白首页。按下面步骤配置后,就会出现团队和项目内容。
132
114
  </p>
133
- <div className="mt-4 grid gap-3 md:grid-cols-3">
115
+ <div className="mt-4 grid gap-3 md:grid-cols-2">
134
116
  <button
135
117
  type="button"
136
118
  onClick={() => openSettingsTab('harness')}
@@ -140,21 +122,12 @@ export const DashboardView = (): React.JSX.Element => {
140
122
  <p className="mt-1 text-sm font-medium text-text">配置 Harness</p>
141
123
  <p className="mt-1 text-xs text-text-muted">连接 Claude/Codex/Gemini 等运行时</p>
142
124
  </button>
143
- <button
144
- type="button"
145
- onClick={() => openSettingsTab('channels')}
146
- className="rounded-lg border border-border bg-surface px-3 py-3 text-left transition-colors hover:bg-surface-overlay"
147
- >
148
- <p className="text-[11px] font-medium text-text-muted">第 2 步</p>
149
- <p className="mt-1 text-sm font-medium text-text">配置渠道</p>
150
- <p className="mt-1 text-xs text-text-muted">接入飞书/Slack/Telegram/Webhook</p>
151
- </button>
152
125
  <button
153
126
  type="button"
154
127
  onClick={openTeamsTab}
155
128
  className="rounded-lg border border-border bg-surface px-3 py-3 text-left transition-colors hover:bg-surface-overlay"
156
129
  >
157
- <p className="text-[11px] font-medium text-text-muted">第 3 步</p>
130
+ <p className="text-[11px] font-medium text-text-muted">第 2 步</p>
158
131
  <p className="mt-1 text-sm font-medium text-text">创建团队并启动</p>
159
132
  <p className="mt-1 text-xs text-text-muted">设置工作目录后即可开始分发任务</p>
160
133
  </button>
@@ -31,25 +31,15 @@ import { useStore } from '@renderer/store';
31
31
  import { createLoadingMultimodelCliStatus } from '@renderer/store/slices/cliInstallerSlice';
32
32
  import {
33
33
  filterExtensionStoreProviders,
34
- formatCliExtensionCapabilityStatus,
35
34
  getVisibleMultimodelProviders,
36
35
  isMultimodelRuntimeStatus,
37
36
  } from '@renderer/utils/multimodelProviderVisibility';
38
37
  import { resolveProjectPathById } from '@renderer/utils/projectLookup';
39
38
  import { refreshCliStatusForCurrentMode } from '@renderer/utils/refreshCliStatus';
40
39
  import { getRuntimeDisplayName } from '@renderer/utils/runtimeDisplayName';
41
- import { getCliProviderExtensionCapabilities } from '@shared/utils/providerExtensionCapabilities';
42
- import {
43
- AlertTriangle,
44
- Info,
45
- Loader2,
46
- Puzzle,
47
- RefreshCw,
48
- Sliders,
49
- } from 'lucide-react';
40
+ import { AlertTriangle, Info, Loader2, Puzzle, RefreshCw } from 'lucide-react';
50
41
  import { useShallow } from 'zustand/react/shallow';
51
42
 
52
- import { EnvVarPanel } from './env/EnvVarPanel';
53
43
  import { PluginsPanel } from './plugins/PluginsPanel';
54
44
  import { StoreExtensionToast } from './common/ExtensionToast';
55
45
  import { ExtensionsSubTabTrigger } from './ExtensionsSubTabTrigger';
@@ -81,7 +71,7 @@ const ProviderCapabilityCardSkeleton = ({
81
71
  </Badge>
82
72
  </div>
83
73
  <div className="mt-2 flex flex-wrap gap-1.5">
84
- {Array.from({ length: 3 }, (_, index) => (
74
+ {Array.from({ length: 4 }, (_, index) => (
85
75
  <span
86
76
  key={index}
87
77
  className="h-7 w-28 animate-pulse rounded-md border border-border bg-surface"
@@ -118,12 +108,6 @@ const EXTENSION_SUB_TABS = [
118
108
  icon: Puzzle,
119
109
  description: 'Claude Code 私有扩展,增强运行时的能力与集成。',
120
110
  },
121
- {
122
- value: 'env-vars' as const,
123
- label: '环境变量',
124
- icon: Sliders,
125
- description: '管理运行时环境变量,启动 agent 时自动注入。',
126
- },
127
111
  ] as const;
128
112
 
129
113
  export const ExtensionStoreView = (): React.JSX.Element => {
@@ -215,7 +199,6 @@ export const ExtensionStoreView = (): React.JSX.Element => {
215
199
  [extensionsTabProjectId, projects, repositoryGroups]
216
200
  );
217
201
  const projectPath = resolvedProject?.path ?? null;
218
- const projectLabel = resolvedProject?.name ?? null;
219
202
  const subTabs = EXTENSION_SUB_TABS;
220
203
 
221
204
  useEffect(() => {
@@ -238,11 +221,7 @@ export const ExtensionStoreView = (): React.JSX.Element => {
238
221
  bootstrapCliStatus,
239
222
  fetchCliStatus,
240
223
  });
241
- }, [
242
- bootstrapCliStatus,
243
- fetchCliStatus,
244
- multimodelEnabled,
245
- ]);
224
+ }, [bootstrapCliStatus, fetchCliStatus, multimodelEnabled]);
246
225
 
247
226
  const isRefreshing = effectiveCliStatusLoading;
248
227
  const cliStatusBanner = useMemo(() => {
@@ -264,7 +243,7 @@ export const ExtensionStoreView = (): React.JSX.Element => {
264
243
  <div>
265
244
  <p className="text-sm font-medium text-text">正在检查扩展运行时可用性</p>
266
245
  <p className="mt-0.5 text-xs text-text-muted">
267
- 扩展需要配置好的运行时来管理 MCP 服务器、技能和提供商连接。
246
+ 扩展需要配置好的运行时来管理插件和提供商连接。
268
247
  </p>
269
248
  </div>
270
249
  </div>
@@ -321,101 +300,7 @@ export const ExtensionStoreView = (): React.JSX.Element => {
321
300
  );
322
301
  }
323
302
 
324
- if (isMultimodel) {
325
- return (
326
- <div className="bg-surface/70 mx-4 mt-3 rounded-md border border-border px-4 py-3">
327
- <div className="flex items-start gap-3">
328
- <Info className="mt-0.5 size-4 shrink-0 text-text-secondary" />
329
- <div className="min-w-0 flex-1">
330
- <p className="text-sm font-medium text-text">多模型运行时能力</p>
331
- <p className="mt-0.5 text-xs text-text-muted">
332
- 不同区域支持的提供商可能不同。只有运行时明确声明支持时,MCP 与技能能力才会显示。
333
- </p>
334
- </div>
335
- </div>
336
- {visibleProviders.length > 0 && (
337
- <div className="mt-3 grid gap-2 md:grid-cols-2">
338
- {visibleProviders.map((provider) => {
339
- const providerLoading = cliProviderStatusLoading[provider.providerId] === true;
340
- if (
341
- isProviderCapabilityCardLoading(provider, providerLoading) ||
342
- isCodexSnapshotPending(provider, codexSnapshotPending)
343
- ) {
344
- return (
345
- <ProviderCapabilityCardSkeleton
346
- key={provider.providerId}
347
- providerId={provider.providerId}
348
- displayName={provider.displayName}
349
- />
350
- );
351
- }
352
-
353
- const statusTone = provider.authenticated
354
- ? 'border-emerald-500/30 bg-emerald-500/5 text-emerald-300'
355
- : provider.supported
356
- ? 'border-amber-500/30 bg-amber-500/5 text-amber-300'
357
- : 'border-border bg-surface-raised text-text-muted';
358
- const statusLabel = provider.authenticated
359
- ? '已连接'
360
- : provider.supported
361
- ? '需要设置'
362
- : '不支持';
363
- const extensionCapabilities = getCliProviderExtensionCapabilities(provider);
364
-
365
- return (
366
- <div
367
- key={provider.providerId}
368
- className={`rounded-md border px-3 py-2 ${statusTone}`}
369
- >
370
- <div className="flex items-center justify-between gap-2">
371
- <div className="min-w-0">
372
- <p className="inline-flex items-center gap-2 text-sm font-medium">
373
- <ProviderBrandLogo
374
- providerId={provider.providerId}
375
- className="size-4 shrink-0"
376
- />
377
- <span>{provider.displayName}</span>
378
- </p>
379
- <p className="truncate text-[11px] text-text-muted">
380
- {provider.statusMessage ?? provider.backend?.label ?? '可配置'}
381
- </p>
382
- </div>
383
- <Badge variant="outline" className="shrink-0">
384
- {statusLabel}
385
- </Badge>
386
- </div>
387
- <div className="mt-2 flex flex-wrap gap-1.5 text-[11px]">
388
- <Badge variant="secondary">
389
- MCP: {formatCliExtensionCapabilityStatus(extensionCapabilities.mcp.status)}
390
- </Badge>
391
- <Badge variant="secondary">
392
- 技能:{extensionCapabilities.skills.ownership}
393
- </Badge>
394
- </div>
395
- </div>
396
- );
397
- })}
398
- </div>
399
- )}
400
- </div>
401
- );
402
- }
403
-
404
- return (
405
- <div className="mx-4 mt-3 flex items-start gap-3 rounded-md border border-emerald-500/30 bg-emerald-500/5 px-4 py-3">
406
- <Info className="mt-0.5 size-4 shrink-0 text-emerald-300" />
407
- <div>
408
- <p className="text-sm font-medium text-emerald-300">{runtimeDisplayName} 已就绪</p>
409
- <p className="mt-0.5 text-xs text-text-muted">
410
- 可以从此页面管理 MCP 服务器与技能
411
- {effectiveCliStatus.installedVersion
412
- ? `,使用 ${runtimeDisplayName} ${effectiveCliStatus.installedVersion}`
413
- : ''}
414
- .
415
- </p>
416
- </div>
417
- </div>
418
- );
303
+ return null;
419
304
  }, [
420
305
  cliProviderStatusLoading,
421
306
  codexSnapshotPending,
@@ -425,7 +310,7 @@ export const ExtensionStoreView = (): React.JSX.Element => {
425
310
  ]);
426
311
 
427
312
  // Browser mode guard
428
- if (!api.plugins && !api.mcpRegistry && !api.skills) {
313
+ if (!api.plugins) {
429
314
  return (
430
315
  <div className="flex flex-1 items-center justify-center">
431
316
  <div className="text-center">
@@ -510,10 +395,6 @@ export const ExtensionStoreView = (): React.JSX.Element => {
510
395
  cliStatusLoading={effectiveCliStatusLoading}
511
396
  />
512
397
  </TabsContent>
513
-
514
- <TabsContent value="env-vars" className="mt-0 pt-4">
515
- <EnvVarPanel projectPath={projectPath} />
516
- </TabsContent>
517
398
  </Tabs>
518
399
  </div>
519
400
  </div>
@@ -5,7 +5,7 @@ import { Info } from 'lucide-react';
5
5
  import type { LucideIcon } from 'lucide-react';
6
6
 
7
7
  interface ExtensionsSubTabTriggerProps {
8
- value: 'plugins' | 'mcp-servers' | 'skills' | 'env-vars';
8
+ value: 'plugins';
9
9
  label: string;
10
10
  description: string;
11
11
  icon: LucideIcon;