@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.
- package/dist-renderer/assets/ProjectEditorOverlay-krO5vQxX.js +58 -0
- package/dist-renderer/assets/{TeamGraphOverlay-ZEDfZyHb.js → TeamGraphOverlay-DqhQzcTr.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-CIhniz70.js → _basePickBy-B7kSYPxr.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-cKAW4Q8I.js → _baseUniq-CnjxqwAk.js} +1 -1
- package/dist-renderer/assets/{arc-YmNsoDXW.js → arc-CLeZuINP.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DHEls2sX.js → architectureDiagram-VXUJARFQ-QKtqaqdY.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-Bpwf1Sbg.js → blockDiagram-VD42YOAC-BqdrzO_f.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-B0IaQ4w5.js → c4Diagram-YG6GDRKO-gwPlCxDC.js} +1 -1
- package/dist-renderer/assets/channel-DpMHF50r.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-DLk-hcFc.js → chunk-4BX2VUAB-C6XLurL4.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-1XRmX_Zm.js → chunk-55IACEB6-Ds6quhEP.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-1waH1DAD.js → chunk-B4BG7PRW-5UlA1_e9.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-BqpZBtrN.js → chunk-DI55MBZ5-ywFrqIsY.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-Bly7vVym.js → chunk-FMBD7UC4-C7ifUA17.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-Ci2QWBAs.js → chunk-QN33PNHL-BxGCo80U.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-YCqFW7d-.js → chunk-QZHKN3VN-B2CuaZs6.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-B0xGXInl.js → chunk-TZMSLE5B-Ds1hInvp.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-CBYCBVRl.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CBYCBVRl.js +1 -0
- package/dist-renderer/assets/clone-DcMF6Psb.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-DxcFNQKT.js → cose-bilkent-S5V4N54A-Cz1GVtLp.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-DPo_RfZY.js → dagre-6UL2VRFP-BrmR-P4h.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-U3hQsFe4.js → diagram-PSM6KHXK-DbNjC5Rg.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-OrwrAy0V.js → diagram-QEK2KX5R-qkRX5_Mq.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-CXATPWVw.js → diagram-S2PKOQOG-CyL5rCv2.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-B0e8AfMF.js → erDiagram-Q2GNP2WA-Dox3-bA5.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-CXfzA4jJ.js → flowDiagram-NV44I4VS-BtkaxlDL.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-CMr08qVl.js → ganttDiagram-JELNMOA3-Dhy_d9GK.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-vYFHpPmy.js → gitGraphDiagram-V2S2FVAM-B5XRhIQA.js} +1 -1
- package/dist-renderer/assets/{graph-DOe5j8dH.js → graph-CsoEwUhS.js} +1 -1
- package/dist-renderer/assets/{index-BySQS7AB.js → index-BWPWmJNo.js} +1 -1
- package/dist-renderer/assets/{index-V7dAKPqd.js → index-Bu2R-Se7.js} +587 -705
- package/dist-renderer/assets/index-CnWV3BhG.css +32 -0
- package/dist-renderer/assets/{index-CzWxVCRL.js → index-D-3KgskL.js} +1 -1
- package/dist-renderer/assets/{index-VJ-MM9xa.js → index-DGEBzLNT.js} +1 -1
- package/dist-renderer/assets/{index-B2Dy7M2G.js → index-NhHNs2Oo.js} +1 -1
- package/dist-renderer/assets/{index-C_okzZXP.js → index-h17WuEyf.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D_WubR0B.js → infoDiagram-HS3SLOUP-hMGmNojH.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-w9ca-1TI.js → journeyDiagram-XKPGCS4Q-DXV2rBDl.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-Jg9p6_pN.js → kanban-definition-3W4ZIXB7-Bf99WLRy.js} +1 -1
- package/dist-renderer/assets/{layout-B-z3y17c.js → layout-C3XWrpwo.js} +1 -1
- package/dist-renderer/assets/{linear-D-RTX5UW.js → linear-OEEcn8KN.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-CDQmHOYP.js → mindmap-definition-VGOIOE7T-Dpi3S2x4.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-D_odsQL7.js → pieDiagram-ADFJNKIX-xTPPhtNx.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-BRsmYWSA.js → quadrantDiagram-AYHSOK5B-euniyDlz.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-ChNE_BOV.js → requirementDiagram-UZGBJVZJ-D9Uiw4kF.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-C8FtpwKc.js → sankeyDiagram-TZEHDZUN-CySU4nED.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-DmLCzNcc.js → sequenceDiagram-WL72ISMW-JVGpET6V.js} +1 -1
- package/dist-renderer/assets/splashScene-D0YB9uxm.js +17 -0
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-WJBm4bhu.js → stateDiagram-FKZM4ZOC-B2FY5qqi.js} +1 -1
- package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DcoMiR8H.js +1 -0
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BXs_hOJs.js → timeline-definition-IT6M3QCI-DmycNUUe.js} +1 -1
- package/dist-renderer/assets/{treemap-GDKQZRPO-o04MA0G9.js → treemap-GDKQZRPO-DPq4gZuB.js} +1 -1
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-Czj69XRd.js → xychartDiagram-PRI3JC2R-J6VVJzRq.js} +1 -1
- package/dist-renderer/index.html +20 -53
- package/package.json +25 -18
- package/src/main/ipc/extensions.ts +2 -1
- package/src/main/server.ts +873 -221
- package/src/main/services/extensions/ExtensionFacadeService.ts +2 -5
- package/src/main/services/extensions/catalog/PluginCatalogService.ts +4 -2
- package/src/main/services/session-intelligence/ConversationTelemetryService.ts +1101 -0
- package/src/main/services/session-intelligence/LocalSessionScanner.ts +512 -0
- package/src/main/services/session-intelligence/SessionUsageParser.ts +4 -4
- package/src/main/services/system-manager/SystemManagerConfigService.ts +122 -0
- package/src/main/services/system-manager/SystemManagerPtyService.ts +233 -0
- package/src/main/services/system-manager/WorkflowPromptService.ts +75 -0
- package/src/main/services/teams-mvp/TaskDispatchService.ts +5 -6
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +39 -2
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +22 -4
- package/src/main/utils/teamProjectResolution.ts +15 -0
- package/src/renderer/App.tsx +8 -4
- package/src/renderer/api/httpClient.ts +68 -18
- package/src/renderer/api/providers.ts +23 -2
- package/src/renderer/assets/participant-avatars/01.svg +3 -0
- package/src/renderer/assets/participant-avatars/02.svg +3 -0
- package/src/renderer/assets/participant-avatars/03.svg +3 -0
- package/src/renderer/assets/participant-avatars/04.svg +3 -0
- package/src/renderer/assets/participant-avatars/05.svg +3 -0
- package/src/renderer/assets/participant-avatars/06.svg +3 -0
- package/src/renderer/assets/participant-avatars/07.svg +3 -0
- package/src/renderer/assets/participant-avatars/08.svg +3 -0
- package/src/renderer/assets/participant-avatars/09.svg +3 -0
- package/src/renderer/assets/participant-avatars/10.svg +3 -0
- package/src/renderer/assets/participant-avatars/11.svg +3 -0
- package/src/renderer/assets/participant-avatars/12.svg +3 -0
- package/src/renderer/assets/participant-avatars/13.svg +3 -0
- package/src/renderer/components/common/TerminalPane.tsx +213 -0
- package/src/renderer/components/dashboard/DashboardView.tsx +9 -36
- package/src/renderer/components/extensions/ExtensionStoreView.tsx +6 -125
- package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
- package/src/renderer/components/extensions/mcp/McpLibraryEnableDialog.tsx +305 -0
- package/src/renderer/components/extensions/mcp/McpLibraryEntryDialog.tsx +418 -0
- package/src/renderer/components/extensions/mcp/McpLibraryPanel.tsx +404 -0
- package/src/renderer/components/extensions/plugins/PluginCard.tsx +6 -6
- package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +34 -21
- package/src/renderer/components/extensions/skills/SkillsLibraryPanel.tsx +335 -0
- package/src/renderer/components/layout/PaneContent.tsx +8 -1
- package/src/renderer/components/layout/Sidebar.tsx +11 -54
- package/src/renderer/components/layout/SortableTab.tsx +20 -31
- package/src/renderer/components/layout/TabBar.tsx +1 -1
- package/src/renderer/components/layout/TabContextMenu.tsx +1 -1
- package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +768 -157
- package/src/renderer/components/schedules/SchedulesView.tsx +51 -462
- package/src/renderer/components/schedules/calendar/CalendarDayView.tsx +173 -0
- package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +113 -0
- package/src/renderer/components/schedules/calendar/CalendarHeader.tsx +148 -0
- package/src/renderer/components/schedules/calendar/CalendarMonthView.tsx +142 -0
- package/src/renderer/components/schedules/calendar/CalendarWeekView.tsx +219 -0
- package/src/renderer/components/schedules/calendar/ScheduleCalendarBoard.tsx +41 -0
- package/src/renderer/components/schedules/calendar/TeamGanttView.tsx +405 -0
- package/src/renderer/components/schedules/calendar/computeOccurrences.ts +234 -0
- package/src/renderer/components/schedules/calendar/index.ts +2 -0
- package/src/renderer/components/schedules/calendar/types.ts +44 -0
- package/src/renderer/components/settings/SettingsTabs.tsx +50 -55
- package/src/renderer/components/settings/SettingsView.tsx +30 -35
- package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +5 -1
- package/src/renderer/components/settings/components/SettingsSelect.tsx +5 -3
- package/src/renderer/components/settings/components/SettingsToggle.tsx +2 -2
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +11 -42
- package/src/renderer/components/settings/sections/CliStatusSection.tsx +71 -112
- package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
- package/src/renderer/components/settings/sections/GeneralSection.tsx +11 -3
- package/src/renderer/components/settings/sections/HarnessSection.tsx +18 -14
- package/src/renderer/components/settings/sections/PlatformsSection.tsx +3 -3
- package/src/renderer/components/settings/sections/TaskBusSection.tsx +33 -40
- package/src/renderer/components/settings/sections/index.ts +0 -1
- package/src/renderer/components/sidebar/SidebarSessions.tsx +182 -4
- package/src/renderer/components/sidebar/SidebarTaskItem.tsx +4 -4
- package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +39 -4
- package/src/renderer/components/splash/splashScene.ts +121 -929
- package/src/renderer/components/system-manager/FolderBrowser.tsx +163 -0
- package/src/renderer/components/system-manager/SystemManagerView.tsx +351 -0
- package/src/renderer/components/tasks/TasksView.tsx +112 -134
- package/src/renderer/components/team/CcSessionsSection.tsx +431 -89
- package/src/renderer/components/team/CollapsibleTeamSection.tsx +17 -32
- package/src/renderer/components/team/TeamDetailView.tsx +319 -123
- package/src/renderer/components/team/TeamListView.tsx +108 -123
- package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +2 -2
- package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +84 -306
- package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +259 -342
- package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +1 -1
- package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +17 -15
- package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +221 -0
- package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +7 -0
- package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +1 -1
- package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +361 -0
- package/src/renderer/components/team/dialogs/platformMeta.ts +122 -11
- package/src/renderer/components/team/dialogs/useTeamEditForm.ts +17 -5
- package/src/renderer/components/team/kanban/KanbanBoard.tsx +9 -9
- package/src/renderer/components/team/members/MemberCard.tsx +14 -47
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +3 -95
- package/src/renderer/components/team/members/MemberDetailStats.tsx +50 -65
- package/src/renderer/components/team/messages/MessageComposer.tsx +8 -110
- package/src/renderer/components/team/messages/MessagesPanel.tsx +131 -114
- package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +2 -2
- package/src/renderer/components/team/tools/AddMcpInline.tsx +27 -17
- package/src/renderer/components/team/tools/McpChip.tsx +6 -3
- package/src/renderer/components/team/tools/SkillChip.tsx +2 -2
- package/src/renderer/components/team/tools/ToolsSection.tsx +418 -70
- package/src/renderer/hooks/useExtensionsTabState.ts +3 -114
- package/src/renderer/index.css +39 -22
- package/src/renderer/index.html +17 -50
- package/src/renderer/store/index.ts +2 -1
- package/src/renderer/store/slices/scheduleSlice.ts +1 -1
- package/src/renderer/store/slices/teamSlice.ts +45 -168
- package/src/renderer/utils/claudeCodeOnlyProviders.ts +3 -10
- package/src/renderer/utils/memberHelpers.ts +5 -17
- package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +4 -2
- package/src/renderer/utils/providerSlashCommands.ts +0 -5
- package/src/renderer/utils/scheduleFormatters.ts +3 -1
- package/src/renderer/utils/teamMessageFiltering.ts +14 -1
- package/src/renderer/utils/teamModelAvailability.ts +18 -2
- package/src/shared/types/api.ts +121 -2
- package/src/shared/types/ccConnect.ts +2 -0
- package/src/shared/types/index.ts +3 -0
- package/src/shared/types/systemManager.ts +49 -0
- package/src/shared/types/team.ts +29 -0
- package/src/shared/types/terminal.ts +4 -2
- package/src/shared/utils/extensionNormalizers.ts +15 -8
- package/src/shared/utils/providerExtensionCapabilities.ts +2 -2
- package/dist-renderer/assets/ProjectEditorOverlay-lJZi-9Hp.js +0 -52
- package/dist-renderer/assets/channel-yIlSKy0e.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-24fHez0s.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-24fHez0s.js +0 -1
- package/dist-renderer/assets/clone-BTNuUva-.js +0 -1
- package/dist-renderer/assets/index-Bi6nrZ4z.css +0 -1
- package/dist-renderer/assets/splashScene-C8lWNnm4.js +0 -1
- 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 {
|
|
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
|
-
<
|
|
86
|
-
|
|
74
|
+
<Sparkles className="size-3.5" />
|
|
75
|
+
会话洞察
|
|
87
76
|
</div>
|
|
88
77
|
<p className="text-xs text-text-muted">
|
|
89
|
-
|
|
78
|
+
汇总本地会话、任务、消息和 Token 使用情况,帮助你判断团队执行状态。
|
|
90
79
|
</p>
|
|
91
|
-
<div className="mt-3
|
|
92
|
-
|
|
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-
|
|
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">第
|
|
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 {
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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'
|
|
8
|
+
value: 'plugins';
|
|
9
9
|
label: string;
|
|
10
10
|
description: string;
|
|
11
11
|
icon: LucideIcon;
|