@pheem49/mint 1.8.2 → 1.10.0
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/Cargo.lock +55 -3
- package/Cargo.toml +2 -1
- package/Release_Note.md +297 -107
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +1 -0
- package/crates/mint-cli/src/actions.rs +233 -0
- package/crates/mint-cli/src/agent.rs +382 -127
- package/crates/mint-cli/src/gmail.rs +22 -2
- package/crates/mint-cli/src/image.rs +8 -8
- package/crates/mint-cli/src/interactive.rs +2888 -0
- package/crates/mint-cli/src/main.rs +391 -2506
- package/crates/mint-cli/src/markdown.rs +294 -0
- package/crates/mint-cli/src/onboard.rs +152 -109
- package/crates/mint-cli/src/setup.rs +143 -143
- package/crates/mint-cli/src/updater.rs +48 -6
- package/crates/mint-core/Cargo.toml +1 -0
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +431 -65
- package/crates/mint-core/src/browser.rs +630 -102
- package/crates/mint-core/src/channels.rs +105 -6
- package/crates/mint-core/src/chat.rs +174 -11
- package/crates/mint-core/src/code_tools.rs +47 -31
- package/crates/mint-core/src/config.rs +302 -17
- package/crates/mint-core/src/image_gen.rs +299 -38
- package/crates/mint-core/src/lib.rs +10 -7
- package/crates/mint-core/src/mcp.rs +119 -6
- package/crates/mint-core/src/memory.rs +6 -1
- package/crates/mint-core/src/orchestration.rs +237 -96
- package/crates/mint-core/src/pictures.rs +67 -5
- package/crates/mint-core/src/semantic.rs +1 -1
- package/crates/mint-core/src/shell.rs +1 -1
- package/crates/mint-core/src/skills.rs +128 -25
- package/crates/mint-core/src/video_gen.rs +235 -0
- package/package.json +8 -2
- package/shared-modules/linux-audio/fluidsynth2-static.json +9 -3
- package/shared-modules/linux-audio/fluidsynth2.json +8 -2
- package/shared-modules/linux-audio/lilv.json +26 -19
- package/shared-modules/linux-audio/lv2.json +0 -1
- package/shared-modules/luajit/luajit.json +2 -2
- package/skills-lock.json +41 -0
- package/src/renderer/index-web.html +1 -1
- package/src/renderer/index.html +1 -1
- package/src/renderer/shared/components/AgentActivityTable.tsx +25 -6
- package/src/renderer/shared/constants/slashCommands.ts +27 -0
- package/src/renderer/shared/platform.ts +3 -0
- package/src/renderer/shared/types.ts +4 -0
- package/src/renderer/shared/utils/approval.tsx +86 -7
- package/src/renderer/shared/utils/fileIcons.ts +135 -0
- package/src/renderer/shared/utils/markdown.tsx +217 -88
- package/src/renderer/shared/utils/slashCommandProcessor.ts +239 -0
- package/src/renderer/src/components/ChatPanel.tsx +486 -69
- package/src/renderer/src/components/DashboardSidebar.tsx +11 -2
- package/src/renderer/src/components/ImageStudioPanel.tsx +87 -4
- package/src/renderer/src/components/MintDashboard.tsx +195 -7
- package/src/renderer/src/components/PicturesLibrary.tsx +156 -15
- package/src/renderer/src/components/Settings/AgentsTab.tsx +21 -2
- package/src/renderer/src/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src/components/Settings/GeneralTab.tsx +795 -413
- package/src/renderer/src/components/Settings/PluginsTab.tsx +304 -70
- package/src/renderer/src/components/Settings/ThemeTab.tsx +6 -1
- package/src/renderer/src/components/SettingsWindow.tsx +106 -3
- package/src/renderer/src/components/VeoStudioPanel.tsx +549 -0
- package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
- package/src/renderer/src/css/image-studio.css +106 -0
- package/src/renderer/src/css/settings.css +158 -0
- package/src/renderer/src/css/styles.css +368 -1
- package/src/renderer/src/css/veo-studio.css +626 -0
- package/src/renderer/src/index.css +1 -0
- package/src/renderer/src/tauri.ts +144 -17
- package/src/renderer/src-web/components/ChatPanel.tsx +385 -93
- package/src/renderer/src-web/components/DashboardSidebar.tsx +16 -1
- package/src/renderer/src-web/components/ImageStudioPanel.tsx +87 -4
- package/src/renderer/src-web/components/MintDashboard.tsx +156 -5
- package/src/renderer/src-web/components/PicturesLibrary.tsx +155 -15
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +21 -2
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src-web/components/Settings/GeneralTab.tsx +795 -411
- package/src/renderer/src-web/components/Settings/PluginsTab.tsx +304 -70
- package/src/renderer/src-web/components/Settings/ThemeTab.tsx +6 -1
- package/src/renderer/src-web/components/SettingsWindow.tsx +110 -3
- package/src/renderer/src-web/components/VeoStudioPanel.tsx +549 -0
- package/src/renderer/src-web/css/image-studio.css +106 -0
- package/src/renderer/src-web/css/settings.css +158 -0
- package/src/renderer/src-web/css/styles.css +369 -1
- package/src/renderer/src-web/css/veo-studio.css +650 -0
- package/src/renderer/src-web/index.css +1 -0
- package/src/renderer/src-web/tauri.ts +135 -16
- package/src-tauri/src/desktop.rs +18 -16
- package/src-tauri/src/discord_rpc.rs +1 -1
- package/src-tauri/src/lib.rs +155 -25
- package/src-tauri/src/webhooks.rs +45 -31
- package/src-tauri/src/workflows.rs +1 -0
- package/src-tauri/tauri.conf.json +1 -1
- package/temp_gridgeist/AGENTS.md +8 -0
- package/temp_gridgeist/CHANGELOG.md +130 -0
- package/temp_gridgeist/LICENSE +21 -0
- package/temp_gridgeist/README.md +323 -0
- package/temp_gridgeist/README.th.md +325 -0
- package/temp_gridgeist/skills/gridgeist/SKILL.md +88 -0
- package/temp_gridgeist/skills/gridgeist/agents/openai.yaml +9 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist-small.svg +10 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist.png +0 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist.svg +18 -0
- package/temp_gridgeist/skills/gridgeist/references/design-language.md +88 -0
- package/temp_gridgeist/skills/gridgeist/references/review-checklist.md +128 -0
- package/temp_gridgeist/skills/gridgeist/references/system-contract.md +109 -0
|
@@ -13,11 +13,126 @@ interface PluginsTabProps {
|
|
|
13
13
|
setMcpArgs: (val: string) => void
|
|
14
14
|
mcpEnv: string
|
|
15
15
|
setMcpEnv: (val: string) => void
|
|
16
|
+
mcpIcon?: string
|
|
17
|
+
setMcpIcon?: (val: string) => void
|
|
16
18
|
handleAddMcpServer: () => void
|
|
17
19
|
handleRemoveMcpServer: (name: string) => void
|
|
18
20
|
handleConnectPlugin: (plugin: string) => void
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
function renderMcpSvgIcon(name: string, customSvgOrUrl?: string) {
|
|
24
|
+
if (customSvgOrUrl && customSvgOrUrl.trim()) {
|
|
25
|
+
const trimmed = customSvgOrUrl.trim()
|
|
26
|
+
if (trimmed.startsWith('<svg') || trimmed.includes('<svg')) {
|
|
27
|
+
return (
|
|
28
|
+
<span
|
|
29
|
+
style={{ width: '22px', height: '22px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}
|
|
30
|
+
dangerouslySetInnerHTML={{ __html: trimmed }}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
if (trimmed.startsWith('data:image') || trimmed.startsWith('http://') || trimmed.startsWith('https://')) {
|
|
35
|
+
return <img src={trimmed} alt={name} style={{ width: '22px', height: '22px', objectFit: 'contain' }} />
|
|
36
|
+
}
|
|
37
|
+
const cleanCustom = trimmed.toLowerCase()
|
|
38
|
+
if (cleanCustom === 'search') {
|
|
39
|
+
return (
|
|
40
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#3b82f6" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
|
|
41
|
+
<circle cx="11" cy="11" r="8" />
|
|
42
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
43
|
+
</svg>
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
if (cleanCustom === 'database') {
|
|
47
|
+
return (
|
|
48
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#a855f7" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
49
|
+
<ellipse cx="12" cy="5" rx="9" ry="3"/>
|
|
50
|
+
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/>
|
|
51
|
+
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
|
|
52
|
+
</svg>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
if (cleanCustom === 'cloud') {
|
|
56
|
+
return (
|
|
57
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#38bdf8" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
58
|
+
<path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/>
|
|
59
|
+
</svg>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
if (cleanCustom === 'code' || cleanCustom === 'terminal') {
|
|
63
|
+
return (
|
|
64
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#10b981" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
65
|
+
<polyline points="16 18 22 12 16 6" />
|
|
66
|
+
<polyline points="8 6 2 12 8 18" />
|
|
67
|
+
</svg>
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
if (cleanCustom === 'api' || cleanCustom === 'bolt') {
|
|
71
|
+
return (
|
|
72
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#f59e0b" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
73
|
+
<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>
|
|
74
|
+
</svg>
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const cleanName = name.toLowerCase().trim()
|
|
80
|
+
if (cleanName === 'docker') {
|
|
81
|
+
return (
|
|
82
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="#0db7ed">
|
|
83
|
+
<path d="M13 8.5h2v2h-2zm-3 0h2v2h-2zm-3 0h2v2H7zm-3 3h2v2H4zm3 0h2v2H7zm3 0h2v2h-2zm3 0h2v2h-2zm3 0h2v2h-2zm-12 3h2v2H4zm3 0h2v2H7zm3 0h2v2h-2zm3 0h2v2h-2zm3 0h2v2h-2zm-6.2 3.8c-.8.5-2.1.8-3.4.6-2.5-.3-4.5-2.2-4.8-4.7h-1c.4 3.4 3.1 6 6.5 6 3 0 5.6-2 6.4-4.8.6-.2 1.4-.4 2.2-.2.3.1.6.3.8.5.6.6 1.4.9 2.2.9h.4c.5-.7.8-1.5.8-2.4 0-.3 0-.6-.1-.9-.7.1-1.4 0-2.1-.3-.6-.3-1.1-.8-1.5-1.4l-.2-.3h-2.1c-.2.7-.6 1.3-1.2 1.7-.6.4-1.3.6-2 .4z"/>
|
|
84
|
+
</svg>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
if (cleanName === 'git' || cleanName === 'gitkraken') {
|
|
88
|
+
return (
|
|
89
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#f05032" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
|
|
90
|
+
<circle cx="18" cy="18" r="3" />
|
|
91
|
+
<circle cx="6" cy="6" r="3" />
|
|
92
|
+
<circle cx="6" cy="18" r="3" />
|
|
93
|
+
<path d="M6 9v6" />
|
|
94
|
+
<path d="M9 18h6" />
|
|
95
|
+
</svg>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
if (cleanName === 'github') {
|
|
99
|
+
return (
|
|
100
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="#f0f6fc">
|
|
101
|
+
<path fillRule="evenodd" clipRule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.53 1.032 1.53 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/>
|
|
102
|
+
</svg>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
if (cleanName === 'node' || cleanName === 'nodejs') {
|
|
106
|
+
return (
|
|
107
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="#68a063">
|
|
108
|
+
<path d="M12 2L2 7.5v9L12 22l10-5.5v-9L12 2zm0 2.3l7.7 4.2v7L12 19.7 4.3 15.5v-7L12 4.3zm-1 4.2v3.5l-3-1.7V8.5l3 1.7zm2 0l3-1.7v1.8l-3 1.7V8.5z"/>
|
|
109
|
+
</svg>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
if (cleanName === 'spotify') {
|
|
113
|
+
return (
|
|
114
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="#1ed760">
|
|
115
|
+
<path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm4.586 14.424c-.18.295-.563.387-.857.207-2.35-1.434-5.308-1.758-8.793-.963-.335.077-.67-.133-.746-.467-.077-.334.132-.67.467-.746 3.812-.871 7.102-.494 9.722 1.112.294.18.386.563.207.857zm1.233-2.743c-.226.367-.706.482-1.073.257-2.687-1.652-6.785-2.131-9.965-1.166-.413.126-.847-.106-.973-.519-.125-.413.106-.847.519-.973 3.632-1.102 8.147-.568 11.235 1.328.367.226.482.706.257 1.073zm.105-2.835C14.692 8.95 9.375 8.775 6.297 9.71c-.496.15-1.022-.132-1.173-.628-.15-.496.132-1.022.628-1.173 3.535-1.073 9.404-.871 12.984 1.254.446.265.592.844.327 1.29-.265.446-.844.592-1.29.327z"/>
|
|
116
|
+
</svg>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
if (cleanName === 'discord') {
|
|
120
|
+
return (
|
|
121
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="#5865f2">
|
|
122
|
+
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994.021-.041.001-.09-.041-.106a13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.061 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.893.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.028zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z"/>
|
|
123
|
+
</svg>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
return (
|
|
127
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#10b981" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
128
|
+
<rect x="2" y="2" width="20" height="8" rx="2" ry="2"/>
|
|
129
|
+
<rect x="2" y="14" width="20" height="8" rx="2" ry="2"/>
|
|
130
|
+
<line x1="6" y1="6" x2="6.01" y2="6"/>
|
|
131
|
+
<line x1="6" y1="18" x2="6.01" y2="18"/>
|
|
132
|
+
</svg>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
21
136
|
export default function PluginsTab({
|
|
22
137
|
config,
|
|
23
138
|
updateField,
|
|
@@ -29,6 +144,8 @@ export default function PluginsTab({
|
|
|
29
144
|
setMcpArgs,
|
|
30
145
|
mcpEnv,
|
|
31
146
|
setMcpEnv,
|
|
147
|
+
mcpIcon = '',
|
|
148
|
+
setMcpIcon,
|
|
32
149
|
handleAddMcpServer,
|
|
33
150
|
handleRemoveMcpServer,
|
|
34
151
|
handleConnectPlugin
|
|
@@ -123,6 +240,20 @@ export default function PluginsTab({
|
|
|
123
240
|
}
|
|
124
241
|
}
|
|
125
242
|
|
|
243
|
+
const [expandedMcp, setExpandedMcp] = useState<string | null>(null)
|
|
244
|
+
|
|
245
|
+
const handleUpdateMcpServerField = (serverName: string, field: string, value: any) => {
|
|
246
|
+
const currentMcp = config.mcpServers?.[serverName] || { command: 'npx', args: [], env: {} }
|
|
247
|
+
const updatedMcp = {
|
|
248
|
+
...(config.mcpServers || {}),
|
|
249
|
+
[serverName]: {
|
|
250
|
+
...currentMcp,
|
|
251
|
+
[field]: value
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
updateField('mcpServers', updatedMcp)
|
|
255
|
+
}
|
|
256
|
+
|
|
126
257
|
// Local state to toggle expansion of configuration sections
|
|
127
258
|
const [expandedPlugin, setExpandedPlugin] = useState<string | null>(null)
|
|
128
259
|
|
|
@@ -162,6 +293,7 @@ export default function PluginsTab({
|
|
|
162
293
|
command: string
|
|
163
294
|
args: string[]
|
|
164
295
|
icon: string
|
|
296
|
+
customIcon?: string
|
|
165
297
|
isEnabled: boolean
|
|
166
298
|
isConfigured: boolean
|
|
167
299
|
description: string
|
|
@@ -179,6 +311,7 @@ export default function PluginsTab({
|
|
|
179
311
|
command: srv.command,
|
|
180
312
|
args: srv.args || [],
|
|
181
313
|
icon,
|
|
314
|
+
customIcon: srv.icon,
|
|
182
315
|
isEnabled: true,
|
|
183
316
|
isConfigured: true,
|
|
184
317
|
description: `Command: ${srv.command} ${(srv.args || []).join(' ')}`
|
|
@@ -375,80 +508,171 @@ export default function PluginsTab({
|
|
|
375
508
|
No MCP servers configured or discovered.
|
|
376
509
|
</div>
|
|
377
510
|
) : (
|
|
378
|
-
mcpListItems.map((item) =>
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
<div className="plugin-
|
|
397
|
-
{
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
511
|
+
mcpListItems.map((item) => {
|
|
512
|
+
const isExpanded = expandedMcp === item.name;
|
|
513
|
+
const srvConfig = config.mcpServers?.[item.name] || { command: item.command, args: item.args, env: {}, icon: item.customIcon };
|
|
514
|
+
|
|
515
|
+
return (
|
|
516
|
+
<div
|
|
517
|
+
className={`plugin-card-wrapper ${isExpanded ? 'active-plugin-card' : ''}`}
|
|
518
|
+
key={item.name}
|
|
519
|
+
style={{
|
|
520
|
+
border: '1px solid var(--border)',
|
|
521
|
+
borderRadius: '12px',
|
|
522
|
+
background: item.isConfigured ? 'var(--surface-bg)' : 'rgba(16, 185, 129, 0.03)',
|
|
523
|
+
opacity: item.isConfigured ? 1 : 0.65,
|
|
524
|
+
marginBottom: '10px',
|
|
525
|
+
transition: 'all 0.2s ease',
|
|
526
|
+
overflow: 'hidden'
|
|
527
|
+
}}
|
|
528
|
+
>
|
|
529
|
+
<div className="plugin-card" style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '16px 20px' }}>
|
|
530
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
|
531
|
+
<div className="plugin-icon" style={{ fontSize: '1.5rem', width: '40px', height: '40px', display: 'grid', placeItems: 'center', background: 'var(--surface-strong)', borderRadius: '10px' }}>
|
|
532
|
+
{renderMcpSvgIcon(item.name, item.customIcon)}
|
|
533
|
+
</div>
|
|
534
|
+
<div className="plugin-info">
|
|
535
|
+
<div className="plugin-name" style={{ fontWeight: '600', color: 'var(--text-main)' }}>
|
|
536
|
+
{item.name} {!item.isConfigured && <span style={{ fontSize: '0.75rem', padding: '2px 6px', background: 'rgba(16, 185, 129, 0.15)', color: '#10b981', borderRadius: '4px', marginLeft: '6px' }}>Discovered</span>}
|
|
537
|
+
</div>
|
|
538
|
+
<div className="plugin-desc" style={{ fontFamily: 'monospace', fontSize: '0.8rem', color: 'var(--text-muted)' }}>
|
|
539
|
+
{item.description}
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
402
542
|
</div>
|
|
403
|
-
<div className="plugin-
|
|
404
|
-
{item.
|
|
543
|
+
<div className="plugin-actions" style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
544
|
+
{item.isConfigured && (
|
|
545
|
+
<>
|
|
546
|
+
<button
|
|
547
|
+
className="btn-icon-edit"
|
|
548
|
+
onClick={() => setExpandedMcp(isExpanded ? null : item.name)}
|
|
549
|
+
style={{
|
|
550
|
+
background: isExpanded ? 'var(--accent)' : 'transparent',
|
|
551
|
+
border: 'none',
|
|
552
|
+
color: isExpanded ? '#fff' : 'var(--text-soft)',
|
|
553
|
+
cursor: 'pointer',
|
|
554
|
+
padding: '6px',
|
|
555
|
+
display: 'flex',
|
|
556
|
+
alignItems: 'center',
|
|
557
|
+
justifyContent: 'center',
|
|
558
|
+
borderRadius: '6px',
|
|
559
|
+
transition: 'all 0.2s'
|
|
560
|
+
}}
|
|
561
|
+
title="Edit MCP Server Settings"
|
|
562
|
+
>
|
|
563
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
564
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
|
|
565
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
|
|
566
|
+
</svg>
|
|
567
|
+
</button>
|
|
568
|
+
<button
|
|
569
|
+
className="btn-icon-danger"
|
|
570
|
+
onClick={() => handleRemoveMcpServer(item.name)}
|
|
571
|
+
style={{
|
|
572
|
+
background: 'transparent',
|
|
573
|
+
border: 'none',
|
|
574
|
+
color: '#ef4444',
|
|
575
|
+
cursor: 'pointer',
|
|
576
|
+
padding: '6px',
|
|
577
|
+
display: 'flex',
|
|
578
|
+
alignItems: 'center',
|
|
579
|
+
justifyContent: 'center',
|
|
580
|
+
borderRadius: '6px',
|
|
581
|
+
transition: 'background 0.2s'
|
|
582
|
+
}}
|
|
583
|
+
title="Delete MCP Server"
|
|
584
|
+
>
|
|
585
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
586
|
+
<polyline points="3 6 5 6 21 6"></polyline>
|
|
587
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
|
588
|
+
<line x1="10" y1="11" x2="10" y2="17"></line>
|
|
589
|
+
<line x1="14" y1="11" x2="14" y2="17"></line>
|
|
590
|
+
</svg>
|
|
591
|
+
</button>
|
|
592
|
+
</>
|
|
593
|
+
)}
|
|
594
|
+
<label className="settings-toggle-switch">
|
|
595
|
+
<input
|
|
596
|
+
type="checkbox"
|
|
597
|
+
checked={item.isEnabled}
|
|
598
|
+
onChange={(e) => {
|
|
599
|
+
if (e.target.checked) {
|
|
600
|
+
handleEnableTool(item.name, item.command, item.args);
|
|
601
|
+
} else {
|
|
602
|
+
handleRemoveMcpServer(item.name);
|
|
603
|
+
}
|
|
604
|
+
}}
|
|
605
|
+
/>
|
|
606
|
+
<span className="settings-toggle-slider" />
|
|
607
|
+
</label>
|
|
405
608
|
</div>
|
|
406
609
|
</div>
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
<
|
|
432
|
-
|
|
433
|
-
|
|
610
|
+
|
|
611
|
+
{item.isConfigured && isExpanded && (
|
|
612
|
+
<div className="plugin-config-panel" style={{
|
|
613
|
+
padding: '16px 20px',
|
|
614
|
+
borderTop: '1px solid var(--border)',
|
|
615
|
+
background: 'rgba(0, 0, 0, 0.18)',
|
|
616
|
+
display: 'flex',
|
|
617
|
+
flexDirection: 'column',
|
|
618
|
+
gap: '12px'
|
|
619
|
+
}}>
|
|
620
|
+
<h4 style={{ fontSize: '0.85rem', fontWeight: '600', color: 'var(--accent)', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
|
|
621
|
+
Edit Settings for {item.name}
|
|
622
|
+
</h4>
|
|
623
|
+
|
|
624
|
+
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
|
|
625
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
|
626
|
+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Command</label>
|
|
627
|
+
<input
|
|
628
|
+
type="text"
|
|
629
|
+
value={srvConfig.command || ''}
|
|
630
|
+
onChange={(e) => handleUpdateMcpServerField(item.name, 'command', e.target.value)}
|
|
631
|
+
style={{ padding: '8px 12px', borderRadius: '8px', border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text-main)', fontSize: '0.85rem' }}
|
|
632
|
+
/>
|
|
633
|
+
</div>
|
|
634
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
|
635
|
+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Icon (Optional)</label>
|
|
636
|
+
<input
|
|
637
|
+
type="text"
|
|
638
|
+
placeholder="SVG code, URL, or preset: search/database/cloud/code/api"
|
|
639
|
+
value={srvConfig.icon || ''}
|
|
640
|
+
onChange={(e) => handleUpdateMcpServerField(item.name, 'icon', e.target.value)}
|
|
641
|
+
style={{ padding: '8px 12px', borderRadius: '8px', border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text-main)', fontSize: '0.85rem' }}
|
|
642
|
+
/>
|
|
643
|
+
</div>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
|
647
|
+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Arguments (Space separated)</label>
|
|
648
|
+
<input
|
|
649
|
+
type="text"
|
|
650
|
+
value={(srvConfig.args || []).join(' ')}
|
|
651
|
+
onChange={(e) => handleUpdateMcpServerField(item.name, 'args', e.target.value.split(/\s+/).filter(Boolean))}
|
|
652
|
+
style={{ padding: '8px 12px', borderRadius: '8px', border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text-main)', fontSize: '0.85rem', width: '100%' }}
|
|
653
|
+
/>
|
|
654
|
+
</div>
|
|
655
|
+
|
|
656
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
|
|
657
|
+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Environment Variables (JSON format)</label>
|
|
658
|
+
<textarea
|
|
659
|
+
value={typeof srvConfig.env === 'object' ? JSON.stringify(srvConfig.env, null, 2) : (srvConfig.env || '')}
|
|
660
|
+
onChange={(e) => {
|
|
661
|
+
try {
|
|
662
|
+
const parsed = JSON.parse(e.target.value)
|
|
663
|
+
handleUpdateMcpServerField(item.name, 'env', parsed)
|
|
664
|
+
} catch {
|
|
665
|
+
// allow live typing
|
|
666
|
+
}
|
|
667
|
+
}}
|
|
668
|
+
style={{ padding: '8px 12px', borderRadius: '8px', border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text-main)', fontSize: '0.85rem', fontFamily: 'monospace', height: '65px', resize: 'vertical' }}
|
|
669
|
+
/>
|
|
670
|
+
</div>
|
|
671
|
+
</div>
|
|
434
672
|
)}
|
|
435
|
-
<label className="settings-toggle-switch">
|
|
436
|
-
<input
|
|
437
|
-
type="checkbox"
|
|
438
|
-
checked={item.isEnabled}
|
|
439
|
-
onChange={(e) => {
|
|
440
|
-
if (e.target.checked) {
|
|
441
|
-
handleEnableTool(item.name, item.command, item.args);
|
|
442
|
-
} else {
|
|
443
|
-
handleRemoveMcpServer(item.name);
|
|
444
|
-
}
|
|
445
|
-
}}
|
|
446
|
-
/>
|
|
447
|
-
<span className="settings-toggle-slider" />
|
|
448
|
-
</label>
|
|
449
673
|
</div>
|
|
450
|
-
|
|
451
|
-
)
|
|
674
|
+
)
|
|
675
|
+
})
|
|
452
676
|
)}
|
|
453
677
|
</div>
|
|
454
678
|
|
|
@@ -502,6 +726,16 @@ export default function PluginsTab({
|
|
|
502
726
|
style={{ padding: '10px 14px', borderRadius: '8px', border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text-main)', fontSize: '0.9rem', width: '100%' }}
|
|
503
727
|
/>
|
|
504
728
|
</div>
|
|
729
|
+
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px', marginBottom: '12px' }}>
|
|
730
|
+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Icon (Optional)</label>
|
|
731
|
+
<input
|
|
732
|
+
type="text"
|
|
733
|
+
placeholder="SVG code, URL, or preset: search/database/cloud/code/api"
|
|
734
|
+
value={mcpIcon}
|
|
735
|
+
onChange={(e) => setMcpIcon && setMcpIcon(e.target.value)}
|
|
736
|
+
style={{ padding: '10px 14px', borderRadius: '8px', border: '1px solid var(--border)', background: 'var(--input-bg)', color: 'var(--text-main)', fontSize: '0.9rem', width: '100%' }}
|
|
737
|
+
/>
|
|
738
|
+
</div>
|
|
505
739
|
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px', marginBottom: '14px' }}>
|
|
506
740
|
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)' }}>Environment Variables (JSON)</label>
|
|
507
741
|
<textarea
|
|
@@ -546,7 +780,7 @@ export default function PluginsTab({
|
|
|
546
780
|
}}>
|
|
547
781
|
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
|
548
782
|
<div className="plugin-icon" style={{ fontSize: '1.5rem', width: '40px', height: '40px', display: 'grid', placeItems: 'center', background: 'var(--surface-strong)', borderRadius: '10px' }}>
|
|
549
|
-
{p.
|
|
783
|
+
{renderMcpSvgIcon(p.key)}
|
|
550
784
|
</div>
|
|
551
785
|
<div className="plugin-info">
|
|
552
786
|
<div className="plugin-name" style={{ fontWeight: '600', color: 'var(--text-main)' }}>{p.name}</div>
|
|
@@ -107,9 +107,14 @@ export default function ThemeTab({ config, updateField }: ThemeTabProps) {
|
|
|
107
107
|
<label>Font Family</label>
|
|
108
108
|
<select value={config.fontFamily} onChange={(e) => updateField('fontFamily', e.target.value)}>
|
|
109
109
|
<option value="'Outfit', sans-serif">Outfit (Default)</option>
|
|
110
|
-
<option value="'Mali', cursive">Mali (Cute Thai Font)</option>
|
|
111
110
|
<option value="'Prompt', sans-serif">Prompt (Modern Thai)</option>
|
|
112
111
|
<option value="'Sarabun', sans-serif">Sarabun (Formal Thai)</option>
|
|
112
|
+
<option value="'Kanit', sans-serif">Kanit (Trendy Thai)</option>
|
|
113
|
+
<option value="'Mitr', sans-serif">Mitr (Friendly Thai)</option>
|
|
114
|
+
<option value="'Noto Sans Thai', sans-serif">Noto Sans Thai (Clean Thai)</option>
|
|
115
|
+
<option value="'Mali', cursive">Mali (Cute Thai Font)</option>
|
|
116
|
+
<option value="'Inter', sans-serif">Inter (Clean Sans-Serif)</option>
|
|
117
|
+
<option value="'Fira Code', monospace">Fira Code (Developer Code Font)</option>
|
|
113
118
|
</select>
|
|
114
119
|
</div>
|
|
115
120
|
<div className="setting-row">
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
|
-
import { getProfileValue, setProfileValue } from '../tauri'
|
|
2
|
+
import { getProfileValue, setProfileValue, setActiveModel } from '../tauri'
|
|
3
3
|
import GeneralTab from './Settings/GeneralTab'
|
|
4
4
|
import MemoryTab from './Settings/MemoryTab'
|
|
5
5
|
import AudioTab from './Settings/AudioTab'
|
|
@@ -8,6 +8,27 @@ import ThemeTab from './Settings/ThemeTab'
|
|
|
8
8
|
import PluginsTab from './Settings/PluginsTab'
|
|
9
9
|
import AgentsTab from './Settings/AgentsTab'
|
|
10
10
|
|
|
11
|
+
// ─── Custom Provider Types ────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export interface CustomProviderModel {
|
|
14
|
+
modelId: string
|
|
15
|
+
displayName: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface CustomProviderHeader {
|
|
19
|
+
name: string
|
|
20
|
+
value: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface CustomProviderConfig {
|
|
24
|
+
id: string
|
|
25
|
+
displayName: string
|
|
26
|
+
baseUrl: string
|
|
27
|
+
apiKey: string
|
|
28
|
+
models: CustomProviderModel[]
|
|
29
|
+
headers: CustomProviderHeader[]
|
|
30
|
+
}
|
|
31
|
+
|
|
11
32
|
export const DEFAULT_CONFIG = {
|
|
12
33
|
theme: 'dark',
|
|
13
34
|
accentColor: '#10b981',
|
|
@@ -70,11 +91,17 @@ export const DEFAULT_CONFIG = {
|
|
|
70
91
|
lineChannelAccessToken: '',
|
|
71
92
|
lineChannelSecret: '',
|
|
72
93
|
enableLineBridge: false,
|
|
94
|
+
lineWebhookHost: '127.0.0.1',
|
|
95
|
+
lineWebhookPort: 3000,
|
|
73
96
|
whatsappCloudAccessToken: '',
|
|
74
97
|
whatsappPhoneNumberId: '',
|
|
75
98
|
whatsappVerifyToken: '',
|
|
76
99
|
whatsappAppSecret: '',
|
|
77
100
|
enableWhatsappBridge: false,
|
|
101
|
+
whatsappWebhookHost: '127.0.0.1',
|
|
102
|
+
whatsappWebhookPort: 3001,
|
|
103
|
+
enableBridgeAckNotification: true,
|
|
104
|
+
bridgeAckMessage: '[Mint Agent] Remote command received, processing...',
|
|
78
105
|
notionApiKey: '',
|
|
79
106
|
notionDatabaseId: '',
|
|
80
107
|
gmailClientId: '',
|
|
@@ -93,6 +120,9 @@ export const DEFAULT_CONFIG = {
|
|
|
93
120
|
stabilityApiKey: '',
|
|
94
121
|
ideogramApiKey: '',
|
|
95
122
|
replicateApiKey: '',
|
|
123
|
+
// Video Generation
|
|
124
|
+
videoGenProvider: 'veo' as 'veo',
|
|
125
|
+
veoModel: 'veo-2.0-generate-001',
|
|
96
126
|
// Multi-Agent Configuration
|
|
97
127
|
agents: [
|
|
98
128
|
{
|
|
@@ -122,7 +152,11 @@ export const DEFAULT_CONFIG = {
|
|
|
122
152
|
systemInstruction: 'You are the Reviewer agent. Your task is to verify the code modifications made by the Coder. Run the automated tests, check lint errors, and ensure the implementation is correct and complete.',
|
|
123
153
|
enabled: true
|
|
124
154
|
}
|
|
125
|
-
]
|
|
155
|
+
],
|
|
156
|
+
// Custom Providers
|
|
157
|
+
customProviders: [] as CustomProviderConfig[],
|
|
158
|
+
/// Per-provider model selection: { [providerId]: selectedModelId }
|
|
159
|
+
customModelSelections: {} as Record<string, string>,
|
|
126
160
|
}
|
|
127
161
|
|
|
128
162
|
type TabType = 'sect-general' | 'sect-audio' | 'sect-automation' | 'sect-theme' | 'sect-plugins' | 'sect-shortcuts' | 'sect-memory' | 'sect-agents'
|
|
@@ -214,6 +248,7 @@ export default function SettingsWindow() {
|
|
|
214
248
|
const [mcpCmd, setMcpCmd] = useState('')
|
|
215
249
|
const [mcpArgs, setMcpArgs] = useState('')
|
|
216
250
|
const [mcpEnv, setMcpEnv] = useState('')
|
|
251
|
+
const [mcpIcon, setMcpIcon] = useState('')
|
|
217
252
|
const [updateMessage, setUpdateMessage] = useState('')
|
|
218
253
|
const [updateAvailable, setUpdateAvailable] = useState(false)
|
|
219
254
|
|
|
@@ -397,10 +432,73 @@ export default function SettingsWindow() {
|
|
|
397
432
|
if (window.settingsApi) {
|
|
398
433
|
await window.settingsApi.saveSettings(finalConfig)
|
|
399
434
|
applyThemeStyles(finalConfig)
|
|
435
|
+
try {
|
|
436
|
+
const getActiveModelName = (provider: string, cfg: typeof finalConfig) => {
|
|
437
|
+
switch (provider) {
|
|
438
|
+
case 'gemini': return cfg.geminiModel
|
|
439
|
+
case 'openai': return cfg.openaiModel
|
|
440
|
+
case 'openrouter': return cfg.openrouterModel
|
|
441
|
+
case 'deepseek': return cfg.deepseekModel
|
|
442
|
+
case 'anthropic': return cfg.anthropicModel
|
|
443
|
+
case 'huggingface': return cfg.hfModel
|
|
444
|
+
case 'local_openai': return cfg.localModelName
|
|
445
|
+
case 'ollama': return cfg.ollamaModel
|
|
446
|
+
default: return ''
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const oldModel = getActiveModelName(config.aiProvider, config)
|
|
450
|
+
const newModel = getActiveModelName(finalConfig.aiProvider, finalConfig)
|
|
451
|
+
if (config.aiProvider !== finalConfig.aiProvider || oldModel !== newModel) {
|
|
452
|
+
await setActiveModel(finalConfig.aiProvider, newModel)
|
|
453
|
+
}
|
|
454
|
+
} catch (e) {
|
|
455
|
+
console.warn('Failed to sync active model event:', e)
|
|
456
|
+
}
|
|
400
457
|
window.settingsApi.closeSettings()
|
|
401
458
|
}
|
|
402
459
|
}
|
|
403
460
|
|
|
461
|
+
const handleSaveWithoutClosing = async () => {
|
|
462
|
+
const finalConfig = { ...config }
|
|
463
|
+
|
|
464
|
+
if (config.geminiModel === 'custom') {
|
|
465
|
+
finalConfig.geminiModel = customGemini || 'gemini-2.5-flash'
|
|
466
|
+
}
|
|
467
|
+
if (config.openaiModel === 'custom') {
|
|
468
|
+
finalConfig.openaiModel = customOpenAI || 'gpt-4o'
|
|
469
|
+
}
|
|
470
|
+
if (config.openrouterModel === 'custom') {
|
|
471
|
+
finalConfig.openrouterModel = customOpenRouter || 'openai/gpt-4o-mini'
|
|
472
|
+
}
|
|
473
|
+
if (config.deepseekModel === 'custom') {
|
|
474
|
+
finalConfig.deepseekModel = customDeepSeek || 'deepseek-v4-flash'
|
|
475
|
+
}
|
|
476
|
+
if (config.anthropicModel === 'custom') {
|
|
477
|
+
finalConfig.anthropicModel = customAnthropic || 'claude-3-5-sonnet-latest'
|
|
478
|
+
}
|
|
479
|
+
if (config.hfModel === 'custom') {
|
|
480
|
+
finalConfig.hfModel = customHF || 'meta-llama/Meta-Llama-3-8B-Instruct'
|
|
481
|
+
}
|
|
482
|
+
if (config.localModelName === 'custom') {
|
|
483
|
+
finalConfig.localModelName = customLocal || 'local-model'
|
|
484
|
+
}
|
|
485
|
+
if (config.ollamaModel === 'custom') {
|
|
486
|
+
finalConfig.ollamaModel = customOllama || 'llama3:latest'
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
await setProfileValue('name', userName)
|
|
491
|
+
await setProfileValue('preferences', userPreferences)
|
|
492
|
+
} catch (e) {
|
|
493
|
+
console.error("Failed to save user profile memory:", e)
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (window.settingsApi) {
|
|
497
|
+
await window.settingsApi.saveSettings(finalConfig)
|
|
498
|
+
applyThemeStyles(finalConfig)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
404
502
|
const handleReset = async () => {
|
|
405
503
|
if (confirm('Reset all settings to default?')) {
|
|
406
504
|
setConfig(DEFAULT_CONFIG)
|
|
@@ -466,7 +564,8 @@ export default function SettingsWindow() {
|
|
|
466
564
|
[mcpName.trim()]: {
|
|
467
565
|
command: mcpCmd.trim(),
|
|
468
566
|
args: argList,
|
|
469
|
-
env: parsedEnv
|
|
567
|
+
env: parsedEnv,
|
|
568
|
+
icon: mcpIcon.trim() || undefined
|
|
470
569
|
}
|
|
471
570
|
}
|
|
472
571
|
|
|
@@ -479,6 +578,7 @@ export default function SettingsWindow() {
|
|
|
479
578
|
setMcpCmd('')
|
|
480
579
|
setMcpArgs('')
|
|
481
580
|
setMcpEnv('')
|
|
581
|
+
setMcpIcon('')
|
|
482
582
|
}
|
|
483
583
|
|
|
484
584
|
const handleRemoveMcpServer = (name: string) => {
|
|
@@ -656,6 +756,7 @@ export default function SettingsWindow() {
|
|
|
656
756
|
updateMessage={updateMessage}
|
|
657
757
|
handleCheckUpdates={handleCheckUpdates}
|
|
658
758
|
handleInstallUpdate={handleInstallUpdate}
|
|
759
|
+
onSaveWithoutClosing={handleSaveWithoutClosing}
|
|
659
760
|
/>
|
|
660
761
|
)}
|
|
661
762
|
|
|
@@ -703,6 +804,8 @@ export default function SettingsWindow() {
|
|
|
703
804
|
setMcpArgs={setMcpArgs}
|
|
704
805
|
mcpEnv={mcpEnv}
|
|
705
806
|
setMcpEnv={setMcpEnv}
|
|
807
|
+
mcpIcon={mcpIcon}
|
|
808
|
+
setMcpIcon={setMcpIcon}
|
|
706
809
|
handleAddMcpServer={handleAddMcpServer}
|
|
707
810
|
handleRemoveMcpServer={handleRemoveMcpServer}
|
|
708
811
|
handleConnectPlugin={handleConnectPlugin}
|