@pheem49/mint 1.8.0 → 1.8.2
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/.github/workflows/release.yml +1 -1
- package/Cargo.lock +34 -3
- package/Cargo.toml +2 -2
- package/README.md +20 -6
- package/Release_Note.md +129 -0
- package/assets/Mint_CLI.png +0 -0
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +1 -0
- package/crates/mint-cli/src/agent.rs +242 -54
- package/crates/mint-cli/src/main.rs +397 -74
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +64 -2
- package/crates/mint-core/src/browser.rs +456 -0
- package/crates/mint-core/src/channels.rs +1 -0
- package/crates/mint-core/src/chat.rs +3 -0
- package/crates/mint-core/src/config.rs +130 -1
- package/crates/mint-core/src/lib.rs +19 -0
- package/crates/mint-core/src/orchestration.rs +317 -12
- package/crates/mint-core/src/skills.rs +113 -4
- package/crates/mint-core/src/tts.rs +3 -1
- package/crates/mint-core/src/workflows.rs +1 -22
- package/flatpak/com.pheem49.mint.desktop +9 -0
- package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
- package/flatpak/com.pheem49.mint.yaml +52 -0
- package/package.json +1 -1
- package/shared-modules/.github/workflows/ci.yml +120 -0
- package/shared-modules/.github/workflows/update.yaml +28 -0
- package/shared-modules/CODEOWNERS +23 -0
- package/shared-modules/README.md +79 -0
- package/shared-modules/SDL/README.md +3 -0
- package/shared-modules/SDL/SDL-1.2.15.json +51 -0
- package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
- package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
- package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
- package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
- package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
- package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
- package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
- package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
- package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
- package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
- package/shared-modules/SDL/sdl12-compat.json +22 -0
- package/shared-modules/SDL2/SDL2_image.json +27 -0
- package/shared-modules/SDL2/SDL2_ttf.json +29 -0
- package/shared-modules/cld2/CMakeLists.txt +157 -0
- package/shared-modules/cld2/cld2.json +24 -0
- package/shared-modules/clutter/clutter.json +72 -0
- package/shared-modules/dbus-glib/dbus-glib.json +29 -0
- package/shared-modules/glew/glew.json +36 -0
- package/shared-modules/glu/glu-9.json +12 -0
- package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
- package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
- package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
- package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
- package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
- package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
- package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
- package/shared-modules/gtk2/gtk2.json +120 -0
- package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
- package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
- package/shared-modules/gtk2/readme.md +10 -0
- package/shared-modules/intltool/intltool-0.51.json +20 -0
- package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
- package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
- package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
- package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
- package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
- package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
- package/shared-modules/lame/lame-3.99.5.json +32 -0
- package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
- package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
- package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
- package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
- package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
- package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
- package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
- package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
- package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
- package/shared-modules/libcanberra/libcanberra.json +44 -0
- package/shared-modules/libmad/libmad.json +19 -0
- package/shared-modules/libsecret/libsecret.json +23 -0
- package/shared-modules/libsoup/libsoup-2.4.json +14 -0
- package/shared-modules/libusb/libusb.json +27 -0
- package/shared-modules/linux-audio/dssi.json +31 -0
- package/shared-modules/linux-audio/fftw3f-static.json +44 -0
- package/shared-modules/linux-audio/fftw3f.json +42 -0
- package/shared-modules/linux-audio/fluidsynth2-static.json +30 -0
- package/shared-modules/linux-audio/fluidsynth2.json +19 -0
- package/shared-modules/linux-audio/ladspa.json +26 -0
- package/shared-modules/linux-audio/lash.json +35 -0
- package/shared-modules/linux-audio/libinstpatch.json +16 -0
- package/shared-modules/linux-audio/liblo-static.json +22 -0
- package/shared-modules/linux-audio/liblo.json +17 -0
- package/shared-modules/linux-audio/lilv-static.json +94 -0
- package/shared-modules/linux-audio/lilv.json +82 -0
- package/shared-modules/linux-audio/lrdf.json +57 -0
- package/shared-modules/linux-audio/lv2.json +21 -0
- package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
- package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
- package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
- package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
- package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
- package/shared-modules/linux-audio/stk.json +28 -0
- package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
- package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
- package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
- package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
- package/shared-modules/lua5.3/lua.pc.in +8 -0
- package/shared-modules/lua5.3/luaconf.patch +47 -0
- package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
- package/shared-modules/lua5.4/lua-5.4.json +41 -0
- package/shared-modules/lua5.4/lua.pc.in +8 -0
- package/shared-modules/lua5.4/luaconf.patch +34 -0
- package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
- package/shared-modules/luajit/luajit.json +30 -0
- package/shared-modules/lzo/lzo.json +27 -0
- package/shared-modules/mac/mac.json +18 -0
- package/shared-modules/physfs/physfs.json +26 -0
- package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
- package/shared-modules/pygame/cython-fixes.patch +34 -0
- package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
- package/shared-modules/pygame/glib.patch +25 -0
- package/shared-modules/pygame/pygame1-python2.json +157 -0
- package/shared-modules/pygtk/pygtk-c99.patch +15 -0
- package/shared-modules/pygtk/pygtk.json +117 -0
- package/shared-modules/pygtk/pygtk.patch +39 -0
- package/shared-modules/python2.7/python-2.7.json +48 -0
- package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
- package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
- package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
- package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
- package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
- package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
- package/shared-modules/update-checker.sh +50 -0
- package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
- package/shared-modules/vorbisgain/0002-errno.patch +33 -0
- package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
- package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
- package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
- package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
- package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
- package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
- package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
- package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
- package/shared-modules/vorbisgain/README.md +23 -0
- package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
- package/src/renderer/shared/agentProgress.ts +145 -0
- package/src/renderer/shared/calculator.ts +52 -0
- package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
- package/src/renderer/shared/components/AgentActivityTable.tsx +66 -0
- package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
- package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
- package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
- package/src/renderer/shared/constants/models.ts +91 -0
- package/src/renderer/shared/platform.ts +82 -0
- package/src/renderer/shared/types.ts +140 -0
- package/src/renderer/shared/utils/agentActivity.ts +187 -0
- package/src/renderer/shared/utils/approval.ts +1 -0
- package/src/renderer/shared/utils/approval.tsx +64 -0
- package/src/renderer/shared/utils/markdown.tsx +347 -0
- package/src/renderer/shared/utils/providers.ts +36 -0
- package/src/renderer/shared/utils/speech.ts +216 -0
- package/src/renderer/shared/utils/ui.ts +147 -0
- package/src/renderer/src/agentProgress.ts +11 -39
- package/src/renderer/src/calculator.ts +3 -46
- package/src/renderer/src/components/ChatPanel.tsx +230 -1202
- package/src/renderer/src/components/ImageStudioPanel.tsx +11 -1
- package/src/renderer/src/components/MintDashboard.tsx +63 -171
- package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
- package/src/renderer/src/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src/components/Settings/PluginsTab.tsx +221 -41
- package/src/renderer/src/components/SettingsWindow.tsx +54 -12
- package/src/renderer/src/components/WorkspacePanel.tsx +66 -9
- package/src/renderer/src/css/image-studio.css +6 -0
- package/src/renderer/src/css/styles.css +148 -11
- package/src/renderer/src/index.css +12 -1
- package/src/renderer/src/tauri.ts +169 -143
- package/src/renderer/src-web/agentProgress.ts +11 -39
- package/src/renderer/src-web/calculator.ts +3 -46
- package/src/renderer/src-web/components/ChatPanel.tsx +223 -1199
- package/src/renderer/src-web/components/ImageStudioPanel.tsx +11 -1
- package/src/renderer/src-web/components/MintDashboard.tsx +31 -172
- package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src-web/components/Settings/PluginsTab.tsx +221 -41
- package/src/renderer/src-web/components/SettingsWindow.tsx +54 -12
- package/src/renderer/src-web/css/image-studio.css +6 -0
- package/src/renderer/src-web/css/styles.css +184 -12
- package/src/renderer/src-web/index.css +12 -1
- package/src/renderer/src-web/tauri.ts +204 -104
- package/src-tauri/src/browser.rs +1 -141
- package/src-tauri/src/headless.rs +3 -2
- package/src-tauri/src/lib.rs +254 -59
- package/src-tauri/src/webhooks.rs +1 -0
- package/src-tauri/src/workflows.rs +57 -4
- package/src-tauri/tauri.conf.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useEffect } from 'react'
|
|
2
2
|
import { DEFAULT_CONFIG } from '../SettingsWindow'
|
|
3
|
-
import { listLearnedSkills, addLearnedSkill, deleteLearnedSkill, LearnedSkill } from '../../tauri'
|
|
3
|
+
import { listLearnedSkills, addLearnedSkill, deleteLearnedSkill, LearnedSkill, detectSystemTools, DetectedTools } from '../../tauri'
|
|
4
4
|
|
|
5
5
|
interface PluginsTabProps {
|
|
6
6
|
config: typeof DEFAULT_CONFIG
|
|
@@ -40,14 +40,49 @@ export default function PluginsTab({
|
|
|
40
40
|
const [skillsLoading, setSkillsLoading] = useState(false)
|
|
41
41
|
const [skillsError, setSkillsError] = useState('')
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// Local state for auto-detected tools
|
|
44
|
+
const [detectedTools, setDetectedTools] = useState<DetectedTools>({
|
|
45
|
+
docker: false,
|
|
46
|
+
git: false,
|
|
47
|
+
gh: false,
|
|
48
|
+
node: false
|
|
49
|
+
})
|
|
50
|
+
const [detecting, setDetecting] = useState(false)
|
|
51
|
+
|
|
52
|
+
// Load skills and detect tools on mount
|
|
44
53
|
useEffect(() => {
|
|
45
54
|
fetchSkills()
|
|
55
|
+
detectTools()
|
|
46
56
|
}, [])
|
|
47
57
|
|
|
58
|
+
const detectTools = async () => {
|
|
59
|
+
setDetecting(true)
|
|
60
|
+
try {
|
|
61
|
+
const tools = await detectSystemTools()
|
|
62
|
+
setDetectedTools(tools)
|
|
63
|
+
} catch (e) {
|
|
64
|
+
console.error("Failed to detect tools:", e)
|
|
65
|
+
} finally {
|
|
66
|
+
setDetecting(false)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const handleEnableTool = (name: string, command: string, args: string[]) => {
|
|
71
|
+
const updatedMcp = {
|
|
72
|
+
...(config.mcpServers || {}),
|
|
73
|
+
[name]: {
|
|
74
|
+
command,
|
|
75
|
+
args,
|
|
76
|
+
env: {}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
updateField('mcpServers', updatedMcp)
|
|
80
|
+
}
|
|
81
|
+
|
|
48
82
|
const fetchSkills = async () => {
|
|
49
83
|
try {
|
|
50
|
-
const
|
|
84
|
+
const activeWorkspace = window.localStorage.getItem('mint:last-workspace-path') || undefined
|
|
85
|
+
const list = await listLearnedSkills(activeWorkspace)
|
|
51
86
|
setSkills(list)
|
|
52
87
|
} catch (e) {
|
|
53
88
|
console.error("Failed to load skills:", e)
|
|
@@ -122,6 +157,79 @@ export default function PluginsTab({
|
|
|
122
157
|
}
|
|
123
158
|
]
|
|
124
159
|
|
|
160
|
+
const mcpListItems: Array<{
|
|
161
|
+
name: string
|
|
162
|
+
command: string
|
|
163
|
+
args: string[]
|
|
164
|
+
icon: string
|
|
165
|
+
isEnabled: boolean
|
|
166
|
+
isConfigured: boolean
|
|
167
|
+
description: string
|
|
168
|
+
}> = []
|
|
169
|
+
|
|
170
|
+
Object.entries(config.mcpServers || {}).forEach(([name, srv]: [string, any]) => {
|
|
171
|
+
let icon = '⚙';
|
|
172
|
+
if (name === 'docker') icon = '🐳';
|
|
173
|
+
else if (name === 'git' || name === 'gitkraken') icon = '🐙';
|
|
174
|
+
else if (name === 'github') icon = '🐱';
|
|
175
|
+
else if (name === 'node') icon = '🟢';
|
|
176
|
+
|
|
177
|
+
mcpListItems.push({
|
|
178
|
+
name,
|
|
179
|
+
command: srv.command,
|
|
180
|
+
args: srv.args || [],
|
|
181
|
+
icon,
|
|
182
|
+
isEnabled: true,
|
|
183
|
+
isConfigured: true,
|
|
184
|
+
description: `Command: ${srv.command} ${(srv.args || []).join(' ')}`
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (detectedTools.docker && !config.mcpServers?.docker) {
|
|
189
|
+
mcpListItems.push({
|
|
190
|
+
name: 'docker',
|
|
191
|
+
command: 'npx',
|
|
192
|
+
args: ['-y', '@proxeus/mcp-docker-server'],
|
|
193
|
+
icon: '🐳',
|
|
194
|
+
isEnabled: false,
|
|
195
|
+
isConfigured: false,
|
|
196
|
+
description: 'Docker MCP Server (Discovered)'
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (detectedTools.git && !config.mcpServers?.git) {
|
|
200
|
+
mcpListItems.push({
|
|
201
|
+
name: 'git',
|
|
202
|
+
command: 'npx',
|
|
203
|
+
args: ['-y', '@modelcontextprotocol/server-git'],
|
|
204
|
+
icon: '🐙',
|
|
205
|
+
isEnabled: false,
|
|
206
|
+
isConfigured: false,
|
|
207
|
+
description: 'Git MCP Server (Discovered)'
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
if (detectedTools.gh && !config.mcpServers?.github) {
|
|
211
|
+
mcpListItems.push({
|
|
212
|
+
name: 'github',
|
|
213
|
+
command: 'npx',
|
|
214
|
+
args: ['-y', '@modelcontextprotocol/server-github'],
|
|
215
|
+
icon: '🐱',
|
|
216
|
+
isEnabled: false,
|
|
217
|
+
isConfigured: false,
|
|
218
|
+
description: 'GitHub MCP Server (Discovered)'
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
if (detectedTools.node && !config.mcpServers?.node) {
|
|
222
|
+
mcpListItems.push({
|
|
223
|
+
name: 'node',
|
|
224
|
+
command: 'npx',
|
|
225
|
+
args: ['-y', '@modelcontextprotocol/server-node'],
|
|
226
|
+
icon: '🟢',
|
|
227
|
+
isEnabled: false,
|
|
228
|
+
isConfigured: false,
|
|
229
|
+
description: 'NodeJS Runtime MCP Server (Discovered)'
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
125
233
|
return (
|
|
126
234
|
<div className="tab-pane active" style={{ display: 'flex', flexDirection: 'column', gap: '24px' }}>
|
|
127
235
|
{/* ── Learned AI Skills ── */}
|
|
@@ -154,7 +262,7 @@ export default function PluginsTab({
|
|
|
154
262
|
{skills.map((s) => (
|
|
155
263
|
<div className="skill-card" key={s.id} style={{
|
|
156
264
|
display: 'flex',
|
|
157
|
-
alignItems: '
|
|
265
|
+
alignItems: 'center',
|
|
158
266
|
justifyContent: 'space-between',
|
|
159
267
|
padding: '16px 20px',
|
|
160
268
|
border: '1px solid var(--border)',
|
|
@@ -163,7 +271,7 @@ export default function PluginsTab({
|
|
|
163
271
|
gap: '16px'
|
|
164
272
|
}}>
|
|
165
273
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
166
|
-
<div style={{ display: 'flex', alignItems: 'center', gap: '8px'
|
|
274
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
167
275
|
<span className="badge" style={{
|
|
168
276
|
background: 'var(--accent)',
|
|
169
277
|
color: '#fff',
|
|
@@ -172,24 +280,31 @@ export default function PluginsTab({
|
|
|
172
280
|
padding: '2px 8px',
|
|
173
281
|
borderRadius: '4px'
|
|
174
282
|
}}>{s.name}</span>
|
|
283
|
+
{s.location && (
|
|
284
|
+
<span className="location-badge" style={{
|
|
285
|
+
background: s.location === 'workspace'
|
|
286
|
+
? 'rgba(16, 185, 129, 0.15)'
|
|
287
|
+
: s.location === 'global'
|
|
288
|
+
? 'rgba(59, 130, 246, 0.15)'
|
|
289
|
+
: 'rgba(139, 92, 246, 0.15)',
|
|
290
|
+
color: s.location === 'workspace'
|
|
291
|
+
? '#10b981'
|
|
292
|
+
: s.location === 'global'
|
|
293
|
+
? '#3b82f6'
|
|
294
|
+
: '#8b5cf6',
|
|
295
|
+
fontSize: '0.7rem',
|
|
296
|
+
fontWeight: '600',
|
|
297
|
+
padding: '2px 6px',
|
|
298
|
+
borderRadius: '4px',
|
|
299
|
+
textTransform: 'capitalize'
|
|
300
|
+
}}>
|
|
301
|
+
{s.location === 'database' ? 'Taught' : s.location}
|
|
302
|
+
</span>
|
|
303
|
+
)}
|
|
175
304
|
<span style={{ fontSize: '0.8rem', color: 'var(--text-muted)', textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'nowrap' }}>
|
|
176
305
|
Source: {s.sourcePath}
|
|
177
306
|
</span>
|
|
178
307
|
</div>
|
|
179
|
-
<div style={{
|
|
180
|
-
fontSize: '0.85rem',
|
|
181
|
-
color: 'var(--text-main)',
|
|
182
|
-
whiteSpace: 'pre-wrap',
|
|
183
|
-
maxHeight: '120px',
|
|
184
|
-
overflowY: 'auto',
|
|
185
|
-
background: 'rgba(0,0,0,0.12)',
|
|
186
|
-
padding: '10px 14px',
|
|
187
|
-
borderRadius: '8px',
|
|
188
|
-
fontFamily: 'monospace',
|
|
189
|
-
lineHeight: '1.4'
|
|
190
|
-
}}>
|
|
191
|
-
{s.content}
|
|
192
|
-
</div>
|
|
193
308
|
</div>
|
|
194
309
|
<button
|
|
195
310
|
className="btn btn-danger"
|
|
@@ -255,33 +370,98 @@ export default function PluginsTab({
|
|
|
255
370
|
</div>
|
|
256
371
|
|
|
257
372
|
<div className="mcp-list">
|
|
258
|
-
{
|
|
259
|
-
<div
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
373
|
+
{mcpListItems.length === 0 ? (
|
|
374
|
+
<div style={{ padding: '20px', textAlign: 'center', color: 'var(--text-muted)' }}>
|
|
375
|
+
No MCP servers configured or discovered.
|
|
376
|
+
</div>
|
|
377
|
+
) : (
|
|
378
|
+
mcpListItems.map((item) => (
|
|
379
|
+
<div
|
|
380
|
+
className="plugin-card"
|
|
381
|
+
key={item.name}
|
|
382
|
+
style={{
|
|
383
|
+
display: 'flex',
|
|
384
|
+
alignItems: 'center',
|
|
385
|
+
justifyContent: 'space-between',
|
|
386
|
+
padding: '16px 20px',
|
|
387
|
+
border: '1px solid var(--border)',
|
|
388
|
+
borderRadius: '12px',
|
|
389
|
+
background: item.isConfigured ? 'var(--surface-bg)' : 'rgba(16, 185, 129, 0.03)',
|
|
390
|
+
opacity: item.isConfigured ? 1 : 0.65,
|
|
391
|
+
marginBottom: '10px',
|
|
392
|
+
transition: 'all 0.2s'
|
|
393
|
+
}}
|
|
394
|
+
>
|
|
395
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
|
396
|
+
<div className="plugin-icon" style={{ fontSize: '1.5rem', width: '40px', height: '40px', display: 'grid', placeItems: 'center', background: 'var(--surface-strong)', borderRadius: '10px' }}>
|
|
397
|
+
{item.icon}
|
|
398
|
+
</div>
|
|
399
|
+
<div className="plugin-info">
|
|
400
|
+
<div className="plugin-name" style={{ fontWeight: '600', color: 'var(--text-main)' }}>
|
|
401
|
+
{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>}
|
|
402
|
+
</div>
|
|
403
|
+
<div className="plugin-desc" style={{ fontFamily: 'monospace', fontSize: '0.8rem', color: 'var(--text-muted)' }}>
|
|
404
|
+
{item.description}
|
|
405
|
+
</div>
|
|
275
406
|
</div>
|
|
276
407
|
</div>
|
|
408
|
+
<div className="plugin-actions" style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
|
409
|
+
{item.isConfigured && (
|
|
410
|
+
<button
|
|
411
|
+
className="btn-icon-danger"
|
|
412
|
+
onClick={() => handleRemoveMcpServer(item.name)}
|
|
413
|
+
style={{
|
|
414
|
+
background: 'transparent',
|
|
415
|
+
border: 'none',
|
|
416
|
+
color: '#ef4444',
|
|
417
|
+
cursor: 'pointer',
|
|
418
|
+
padding: '6px',
|
|
419
|
+
display: 'flex',
|
|
420
|
+
alignItems: 'center',
|
|
421
|
+
justifyContent: 'center',
|
|
422
|
+
borderRadius: '6px',
|
|
423
|
+
transition: 'background 0.2s'
|
|
424
|
+
}}
|
|
425
|
+
title="Delete MCP Server"
|
|
426
|
+
>
|
|
427
|
+
<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">
|
|
428
|
+
<polyline points="3 6 5 6 21 6"></polyline>
|
|
429
|
+
<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>
|
|
430
|
+
<line x1="10" y1="11" x2="10" y2="17"></line>
|
|
431
|
+
<line x1="14" y1="11" x2="14" y2="17"></line>
|
|
432
|
+
</svg>
|
|
433
|
+
</button>
|
|
434
|
+
)}
|
|
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
|
+
</div>
|
|
277
450
|
</div>
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
</div>
|
|
281
|
-
</div>
|
|
282
|
-
))}
|
|
451
|
+
))
|
|
452
|
+
)}
|
|
283
453
|
</div>
|
|
284
454
|
|
|
455
|
+
{/* Save settings alert */}
|
|
456
|
+
{((detectedTools.docker && !config.mcpServers?.docker) ||
|
|
457
|
+
(detectedTools.git && !config.mcpServers?.git) ||
|
|
458
|
+
(detectedTools.gh && !config.mcpServers?.github) ||
|
|
459
|
+
(detectedTools.node && !config.mcpServers?.node)) && (
|
|
460
|
+
<div style={{ marginTop: '12px', padding: '12px 16px', background: 'rgba(255,193,7,0.1)', border: '1px solid rgba(255,193,7,0.3)', borderRadius: '8px', fontSize: '0.8rem', color: '#ffb300', fontWeight: '500', display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
461
|
+
<span>⚠️ After toggling a plugin, please click the "Save Settings" button at the bottom of the window to persist changes.</span>
|
|
462
|
+
</div>
|
|
463
|
+
)}
|
|
464
|
+
|
|
285
465
|
<div className="add-mcp-box" style={{
|
|
286
466
|
marginTop: '20px',
|
|
287
467
|
padding: '20px',
|
|
@@ -6,6 +6,7 @@ import AudioTab from './Settings/AudioTab'
|
|
|
6
6
|
import AutomationTab from './Settings/AutomationTab'
|
|
7
7
|
import ThemeTab from './Settings/ThemeTab'
|
|
8
8
|
import PluginsTab from './Settings/PluginsTab'
|
|
9
|
+
import AgentsTab from './Settings/AgentsTab'
|
|
9
10
|
|
|
10
11
|
export const DEFAULT_CONFIG = {
|
|
11
12
|
theme: 'dark',
|
|
@@ -30,7 +31,7 @@ export const DEFAULT_CONFIG = {
|
|
|
30
31
|
proactiveCooldown: 120,
|
|
31
32
|
enableVoiceReply: true,
|
|
32
33
|
enableCustomWorkflows: true,
|
|
33
|
-
enableAgentCollaboration:
|
|
34
|
+
enableAgentCollaboration: false,
|
|
34
35
|
ttsProvider: 'google',
|
|
35
36
|
ttsVolume: 1.0,
|
|
36
37
|
ttsSpeed: 1.0,
|
|
@@ -91,10 +92,40 @@ export const DEFAULT_CONFIG = {
|
|
|
91
92
|
imageGenProvider: 'gemini' as 'gemini' | 'dalle' | 'stability' | 'ideogram' | 'replicate',
|
|
92
93
|
stabilityApiKey: '',
|
|
93
94
|
ideogramApiKey: '',
|
|
94
|
-
replicateApiKey: ''
|
|
95
|
+
replicateApiKey: '',
|
|
96
|
+
// Multi-Agent Configuration
|
|
97
|
+
agents: [
|
|
98
|
+
{
|
|
99
|
+
id: 'planner',
|
|
100
|
+
name: 'Planner',
|
|
101
|
+
provider: 'gemini',
|
|
102
|
+
model: 'gemini-2.5-flash',
|
|
103
|
+
apiKey: '',
|
|
104
|
+
systemInstruction: 'You are the Planner agent. Your task is to analyze the user request, inspect the workspace structure, and design a step-by-step implementation plan. Create or update the implementation_plan.md file to document your proposal.',
|
|
105
|
+
enabled: true
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: 'coder',
|
|
109
|
+
name: 'Coder',
|
|
110
|
+
provider: 'gemini',
|
|
111
|
+
model: 'gemini-2.5-flash',
|
|
112
|
+
apiKey: '',
|
|
113
|
+
systemInstruction: 'You are the Coder agent. Your task is to implement the changes specified in the approved implementation plan. Read relevant files, write clean and efficient code, and run terminal commands to build or verify. Stay focused on execution.',
|
|
114
|
+
enabled: true
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: 'reviewer',
|
|
118
|
+
name: 'Reviewer',
|
|
119
|
+
provider: 'gemini',
|
|
120
|
+
model: 'gemini-2.5-flash',
|
|
121
|
+
apiKey: '',
|
|
122
|
+
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
|
+
enabled: true
|
|
124
|
+
}
|
|
125
|
+
]
|
|
95
126
|
}
|
|
96
127
|
|
|
97
|
-
type TabType = 'sect-general' | 'sect-audio' | 'sect-automation' | 'sect-theme' | 'sect-plugins' | 'sect-shortcuts' | 'sect-memory'
|
|
128
|
+
type TabType = 'sect-general' | 'sect-audio' | 'sect-automation' | 'sect-theme' | 'sect-plugins' | 'sect-shortcuts' | 'sect-memory' | 'sect-agents'
|
|
98
129
|
|
|
99
130
|
export const GEMINI_MODELS = [
|
|
100
131
|
'gemini-2.5-flash',
|
|
@@ -157,15 +188,7 @@ export const LOCAL_MODELS = [
|
|
|
157
188
|
'lmstudio-community/gemma-2-9b-it-GGUF'
|
|
158
189
|
]
|
|
159
190
|
|
|
160
|
-
export const OLLAMA_MODELS = [
|
|
161
|
-
'llama3:latest',
|
|
162
|
-
'llama3.1:latest',
|
|
163
|
-
'llama3.2:latest',
|
|
164
|
-
'gemma2:latest',
|
|
165
|
-
'mistral:latest',
|
|
166
|
-
'phi3:latest',
|
|
167
|
-
'qwen2.5:latest'
|
|
168
|
-
]
|
|
191
|
+
export const OLLAMA_MODELS: string[] = []
|
|
169
192
|
|
|
170
193
|
export default function SettingsWindow() {
|
|
171
194
|
const [activeTab, setActiveTab] = useState<TabType>('sect-general')
|
|
@@ -594,6 +617,17 @@ export default function SettingsWindow() {
|
|
|
594
617
|
</span>
|
|
595
618
|
<strong>Plugins</strong>
|
|
596
619
|
</button>
|
|
620
|
+
<button className={`tab-btn ${activeTab === 'sect-agents' ? 'active' : ''}`} onClick={() => setActiveTab('sect-agents')}>
|
|
621
|
+
<span style={{ display: 'inline-flex', alignItems: 'center' }}>
|
|
622
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
623
|
+
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
|
624
|
+
<circle cx="9" cy="7" r="4"></circle>
|
|
625
|
+
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
|
|
626
|
+
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
|
|
627
|
+
</svg>
|
|
628
|
+
</span>
|
|
629
|
+
<strong>Multi-Agent (Beta)</strong>
|
|
630
|
+
</button>
|
|
597
631
|
</nav>
|
|
598
632
|
|
|
599
633
|
<div className="settings-content">
|
|
@@ -674,6 +708,14 @@ export default function SettingsWindow() {
|
|
|
674
708
|
handleConnectPlugin={handleConnectPlugin}
|
|
675
709
|
/>
|
|
676
710
|
)}
|
|
711
|
+
|
|
712
|
+
{activeTab === 'sect-agents' && (
|
|
713
|
+
<AgentsTab
|
|
714
|
+
config={config}
|
|
715
|
+
updateField={updateField}
|
|
716
|
+
dynamicOllamaModels={dynamicOllamaModels}
|
|
717
|
+
/>
|
|
718
|
+
)}
|
|
677
719
|
</div>
|
|
678
720
|
</main>
|
|
679
721
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
import { getWorkspaceTree, type WorkspaceTreeEntry } from '../tauri'
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import { getWorkspaceTree, type WorkspaceTreeEntry, createWorkspaceFile, createWorkspaceFolder, deleteWorkspaceItem } from '../tauri'
|
|
3
3
|
import folderIcon from 'material-icon-theme/icons/folder.svg?url'
|
|
4
4
|
import folderOpenIcon from 'material-icon-theme/icons/folder-open.svg?url'
|
|
5
5
|
import folderComponentsIcon from 'material-icon-theme/icons/folder-components.svg?url'
|
|
@@ -147,7 +147,7 @@ function materialFileIcon(name: string, fileExtension: string) {
|
|
|
147
147
|
return FILE_ICONS_BY_NAME[name.toLowerCase()] || FILE_ICONS_BY_EXTENSION[fileExtension] || documentIcon
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
-
function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number; key?: string }) {
|
|
150
|
+
function TreeNode({ entry, level, onRefresh, workspacePath }: { entry: WorkspaceTreeEntry; level: number; onRefresh: () => void; workspacePath: string; key?: string }) {
|
|
151
151
|
const [open, setOpen] = useState(level < 1)
|
|
152
152
|
const isDirectory = entry.kind === 'directory'
|
|
153
153
|
const hasChildren = entry.children.length > 0
|
|
@@ -156,6 +156,20 @@ function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number;
|
|
|
156
156
|
const materialIcon = isDirectory ? materialFolderIcon(entry.name, open) : materialFileIcon(entry.name, fileExtension)
|
|
157
157
|
const dragText = `@${entry.path}`
|
|
158
158
|
|
|
159
|
+
const handleContextMenu = async (event: React.MouseEvent) => {
|
|
160
|
+
event.preventDefault()
|
|
161
|
+
const confirmed = confirm(`Are you sure you want to delete "${entry.name}"?`)
|
|
162
|
+
if (!confirmed) return
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
const absolutePath = `${workspacePath}/${entry.path}`
|
|
166
|
+
await deleteWorkspaceItem(absolutePath)
|
|
167
|
+
onRefresh()
|
|
168
|
+
} catch (err) {
|
|
169
|
+
alert(`Failed to delete item: ${err instanceof Error ? err.message : String(err)}`)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
159
173
|
return (
|
|
160
174
|
<div className="workspace-tree-node">
|
|
161
175
|
<button
|
|
@@ -163,6 +177,7 @@ function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number;
|
|
|
163
177
|
className={`workspace-tree-row ${isDirectory ? 'is-directory' : 'is-file'}`}
|
|
164
178
|
style={{ paddingLeft: `${level * 16 + 8}px` }}
|
|
165
179
|
onClick={() => isDirectory && hasChildren && setOpen((current) => !current)}
|
|
180
|
+
onContextMenu={handleContextMenu}
|
|
166
181
|
title={entry.path}
|
|
167
182
|
draggable
|
|
168
183
|
onDragStart={(event) => {
|
|
@@ -186,7 +201,7 @@ function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number;
|
|
|
186
201
|
{isDirectory && open && hasChildren && (
|
|
187
202
|
<div className="workspace-tree-children">
|
|
188
203
|
{entry.children.map((child) => (
|
|
189
|
-
<TreeNode key={child.path} entry={child} level={level + 1} />
|
|
204
|
+
<TreeNode key={child.path} entry={child} level={level + 1} onRefresh={onRefresh} workspacePath={workspacePath} />
|
|
190
205
|
))}
|
|
191
206
|
</div>
|
|
192
207
|
)}
|
|
@@ -217,11 +232,52 @@ export default function WorkspacePanel({ agentMode, sending, workspacePath, onEn
|
|
|
217
232
|
|
|
218
233
|
useEffect(() => {
|
|
219
234
|
refresh()
|
|
235
|
+
|
|
236
|
+
// Refresh when the window gains focus (e.g., switching back from VS Code)
|
|
237
|
+
const handleFocus = () => {
|
|
238
|
+
refresh()
|
|
239
|
+
}
|
|
240
|
+
window.addEventListener('focus', handleFocus)
|
|
241
|
+
|
|
242
|
+
// Poll every 15 seconds to catch edits/updates in real-time
|
|
243
|
+
const interval = setInterval(() => {
|
|
244
|
+
refresh()
|
|
245
|
+
}, 15000)
|
|
246
|
+
|
|
247
|
+
return () => {
|
|
248
|
+
window.removeEventListener('focus', handleFocus)
|
|
249
|
+
clearInterval(interval)
|
|
250
|
+
}
|
|
220
251
|
}, [workspacePath])
|
|
221
252
|
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
253
|
+
const handleCreateFile = async () => {
|
|
254
|
+
if (!workspacePath.trim()) return
|
|
255
|
+
const name = prompt('Enter name of new file:')
|
|
256
|
+
if (!name || !name.trim()) return
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
setError('')
|
|
260
|
+
const fullPath = `${workspacePath}/${name.trim()}`
|
|
261
|
+
await createWorkspaceFile(fullPath)
|
|
262
|
+
await refresh()
|
|
263
|
+
} catch (err) {
|
|
264
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const handleCreateFolder = async () => {
|
|
269
|
+
if (!workspacePath.trim()) return
|
|
270
|
+
const name = prompt('Enter name of new folder:')
|
|
271
|
+
if (!name || !name.trim()) return
|
|
272
|
+
|
|
273
|
+
try {
|
|
274
|
+
setError('')
|
|
275
|
+
const fullPath = `${workspacePath}/${name.trim()}`
|
|
276
|
+
await createWorkspaceFolder(fullPath)
|
|
277
|
+
await refresh()
|
|
278
|
+
} catch (err) {
|
|
279
|
+
setError(err instanceof Error ? err.message : String(err))
|
|
280
|
+
}
|
|
225
281
|
}
|
|
226
282
|
|
|
227
283
|
return (
|
|
@@ -237,7 +293,8 @@ export default function WorkspacePanel({ agentMode, sending, workspacePath, onEn
|
|
|
237
293
|
</header>
|
|
238
294
|
|
|
239
295
|
<div className="workspace-panel-actions">
|
|
240
|
-
<button type="button" onClick={
|
|
296
|
+
<button type="button" onClick={handleCreateFile} disabled={!workspacePath.trim()}>New File</button>
|
|
297
|
+
<button type="button" onClick={handleCreateFolder} disabled={!workspacePath.trim()}>New Folder</button>
|
|
241
298
|
<button type="button" onClick={refresh} disabled={!workspacePath.trim()}>Refresh</button>
|
|
242
299
|
</div>
|
|
243
300
|
|
|
@@ -255,7 +312,7 @@ export default function WorkspacePanel({ agentMode, sending, workspacePath, onEn
|
|
|
255
312
|
</div>
|
|
256
313
|
<div className="workspace-tree">
|
|
257
314
|
{tree.children.map((entry) => (
|
|
258
|
-
<TreeNode key={entry.path} entry={entry} level={0} />
|
|
315
|
+
<TreeNode key={entry.path} entry={entry} level={0} onRefresh={refresh} workspacePath={workspacePath} />
|
|
259
316
|
))}
|
|
260
317
|
</div>
|
|
261
318
|
</>
|