@pheem49/mint 1.2.3 → 1.3.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/README.md +28 -0
- package/docs/assets/Agent_Mint.png +0 -0
- package/docs/assets/Settings.png +0 -0
- package/docs/assets/icon.png +0 -0
- package/docs/index.html +53 -5
- package/docs/style.css +295 -6
- package/index.html +16 -0
- package/main.js +36 -83
- package/mint-cli-logic.js +19 -0
- package/mint-cli.js +121 -17
- package/package.json +8 -2
- package/src/AI_Brain/Gemini_API.js +175 -9
- package/src/AI_Brain/knowledge_base.js +199 -125
- package/src/Automation_Layer/file_operations.js +74 -10
- package/src/CLI/chat_router.js +166 -0
- package/src/CLI/chat_ui.js +239 -110
- package/src/CLI/code_agent.js +443 -0
- package/src/CLI/code_session_memory.js +62 -0
- package/src/CLI/list_features.js +1 -0
- package/src/Plugins/mcp_manager.js +95 -0
- package/src/Plugins/plugin_manager.js +2 -2
- package/src/System/config_manager.js +27 -7
- package/src/System/granular_automation.js +88 -0
- package/src/UI/settings.html +24 -0
- package/src/UI/settings.js +98 -1
- package/docs/assets/hero-bg.png +0 -0
- package/docs/assets/logo.png +0 -0
package/main.js
CHANGED
|
@@ -13,21 +13,22 @@ const { parseCommand } = require('./src/Command_Parser/parser');
|
|
|
13
13
|
const pluginManager = require('./src/Plugins/plugin_manager');
|
|
14
14
|
const { analyzeAndSuggest } = require('./src/AI_Brain/proactive_engine');
|
|
15
15
|
const { recordBehavior, getBehaviorSummary } = require('./src/AI_Brain/behavior_memory');
|
|
16
|
-
const { indexFile } = require('./src/AI_Brain/knowledge_base');
|
|
16
|
+
const { indexFile, indexFolder } = require('./src/AI_Brain/knowledge_base');
|
|
17
|
+
|
|
17
18
|
const SystemAutomation = require('./src/System/system_automation');
|
|
18
19
|
const systemEvents = require('./src/System/system_events');
|
|
19
20
|
const customWorkflows = require('./src/System/custom_workflows');
|
|
21
|
+
const mcpManager = require('./src/Plugins/mcp_manager');
|
|
22
|
+
const granularAutomation = require('./src/System/granular_automation');
|
|
20
23
|
const googleTTS = require('google-tts-api');
|
|
21
24
|
|
|
22
25
|
let mainWindow;
|
|
23
26
|
let settingsWindow = null;
|
|
24
27
|
let screenPickerWindow = null;
|
|
25
28
|
let spotlightWindow = null;
|
|
26
|
-
let floatingWindow = null;
|
|
27
29
|
let widgetWindow = null;
|
|
28
30
|
let proactiveGlowWindow = null;
|
|
29
31
|
let tray = null;
|
|
30
|
-
let floatingUnreadCount = 0;
|
|
31
32
|
|
|
32
33
|
// =====================
|
|
33
34
|
// Proactive Loop
|
|
@@ -192,7 +193,7 @@ function createWindow() {
|
|
|
192
193
|
});
|
|
193
194
|
|
|
194
195
|
mainWindow.on('focus', () => {
|
|
195
|
-
clearFloatingUnread();
|
|
196
|
+
// clearFloatingUnread(); // Disabled
|
|
196
197
|
});
|
|
197
198
|
}
|
|
198
199
|
|
|
@@ -291,41 +292,7 @@ function createSpotlightWindow() {
|
|
|
291
292
|
});
|
|
292
293
|
}
|
|
293
294
|
|
|
294
|
-
|
|
295
|
-
if (floatingWindow) return;
|
|
296
|
-
const display = screen.getPrimaryDisplay();
|
|
297
|
-
const { x, y, width, height } = display.workArea;
|
|
298
|
-
const size = 72;
|
|
299
|
-
const margin = 20;
|
|
300
|
-
const posX = x + width - size - margin;
|
|
301
|
-
const posY = y + height - size - margin - 40;
|
|
302
|
-
|
|
303
|
-
floatingWindow = new BrowserWindow({
|
|
304
|
-
width: size,
|
|
305
|
-
height: size,
|
|
306
|
-
x: posX,
|
|
307
|
-
y: posY,
|
|
308
|
-
frame: false,
|
|
309
|
-
transparent: true,
|
|
310
|
-
resizable: false,
|
|
311
|
-
alwaysOnTop: true,
|
|
312
|
-
skipTaskbar: true,
|
|
313
|
-
show: true,
|
|
314
|
-
webPreferences: {
|
|
315
|
-
preload: path.join(__dirname, 'src/UI/preload-floating.js'),
|
|
316
|
-
nodeIntegration: false,
|
|
317
|
-
contextIsolation: true
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
floatingWindow.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
|
|
322
|
-
floatingWindow.setAlwaysOnTop(true, 'floating');
|
|
323
|
-
floatingWindow.loadFile('src/UI/floating.html');
|
|
324
|
-
|
|
325
|
-
floatingWindow.on('closed', () => {
|
|
326
|
-
floatingWindow = null;
|
|
327
|
-
});
|
|
328
|
-
}
|
|
295
|
+
// Floating window logic removed
|
|
329
296
|
|
|
330
297
|
function createWidgetWindow() {
|
|
331
298
|
if (widgetWindow) return;
|
|
@@ -363,28 +330,21 @@ function createWidgetWindow() {
|
|
|
363
330
|
});
|
|
364
331
|
}
|
|
365
332
|
|
|
366
|
-
|
|
367
|
-
if (floatingWindow && !floatingWindow.isDestroyed()) {
|
|
368
|
-
floatingWindow.webContents.send('floating-notify', floatingUnreadCount);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
function clearFloatingUnread() {
|
|
373
|
-
if (floatingUnreadCount === 0) return;
|
|
374
|
-
floatingUnreadCount = 0;
|
|
375
|
-
updateFloatingUnread();
|
|
376
|
-
}
|
|
333
|
+
// Floating unread logic removed
|
|
377
334
|
|
|
378
335
|
app.whenReady().then(() => {
|
|
379
336
|
const config = readConfig();
|
|
380
337
|
createWindow();
|
|
381
338
|
createTray();
|
|
382
|
-
createFloatingWindow();
|
|
339
|
+
// createFloatingWindow(); // Removed
|
|
383
340
|
|
|
384
341
|
// Only show AI widget if enabled in settings
|
|
385
342
|
if (config.showDesktopWidget !== false) {
|
|
386
343
|
createWidgetWindow();
|
|
387
344
|
}
|
|
345
|
+
|
|
346
|
+
// Initialize MCP Servers
|
|
347
|
+
mcpManager.init().catch(err => console.error('[MCP] Init Error:', err));
|
|
388
348
|
|
|
389
349
|
// Start monitoring system events (battery, wifi, etc.)
|
|
390
350
|
systemEvents.startMonitoring();
|
|
@@ -395,7 +355,7 @@ app.whenReady().then(() => {
|
|
|
395
355
|
systemEvents.on('low-battery', (level) => {
|
|
396
356
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
397
357
|
mainWindow.webContents.send('proactive-notification', {
|
|
398
|
-
message: `⚠️
|
|
358
|
+
message: `⚠️ Battery is low (${level}%). Please plug in your charger. ✨`,
|
|
399
359
|
type: 'warning'
|
|
400
360
|
});
|
|
401
361
|
}
|
|
@@ -403,7 +363,7 @@ app.whenReady().then(() => {
|
|
|
403
363
|
|
|
404
364
|
systemEvents.on('connection-change', (isOnline) => {
|
|
405
365
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
406
|
-
const msg = isOnline ? '✅
|
|
366
|
+
const msg = isOnline ? '✅ Internet connection restored. ✨' : '❌ Internet connection lost.';
|
|
407
367
|
mainWindow.webContents.send('proactive-notification', { message: msg, type: 'info' });
|
|
408
368
|
}
|
|
409
369
|
});
|
|
@@ -438,6 +398,7 @@ app.on('window-all-closed', (e) => {
|
|
|
438
398
|
|
|
439
399
|
app.on('will-quit', () => {
|
|
440
400
|
globalShortcut.unregisterAll();
|
|
401
|
+
mcpManager.shutdown();
|
|
441
402
|
});
|
|
442
403
|
|
|
443
404
|
// =====================
|
|
@@ -473,7 +434,7 @@ ipcMain.on('close-window', (event) => {
|
|
|
473
434
|
});
|
|
474
435
|
|
|
475
436
|
ipcMain.on('minimize-window', (event) => {
|
|
476
|
-
if (mainWindow) mainWindow.
|
|
437
|
+
if (mainWindow) mainWindow.minimize();
|
|
477
438
|
});
|
|
478
439
|
|
|
479
440
|
ipcMain.on('quit-app', (event) => {
|
|
@@ -512,6 +473,7 @@ ipcMain.handle('get-settings', () => {
|
|
|
512
473
|
});
|
|
513
474
|
|
|
514
475
|
ipcMain.handle('save-settings', (event, config) => {
|
|
476
|
+
console.log('[Settings] Saving new config. MCP Servers count:', Object.keys(config.mcpServers || {}).length);
|
|
515
477
|
const result = writeConfig(config);
|
|
516
478
|
// Refresh API key if user updated it in settings
|
|
517
479
|
refreshApiKeyFromConfig();
|
|
@@ -597,33 +559,7 @@ ipcMain.on('spotlight-resize', (event, width, height) => {
|
|
|
597
559
|
}
|
|
598
560
|
});
|
|
599
561
|
|
|
600
|
-
//
|
|
601
|
-
// IPC — Floating Icon
|
|
602
|
-
// =====================
|
|
603
|
-
ipcMain.on('floating-click', () => {
|
|
604
|
-
if (mainWindow) {
|
|
605
|
-
mainWindow.show();
|
|
606
|
-
mainWindow.focus();
|
|
607
|
-
}
|
|
608
|
-
clearFloatingUnread();
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
ipcMain.on('ai-notify', () => {
|
|
612
|
-
floatingUnreadCount += 1;
|
|
613
|
-
updateFloatingUnread();
|
|
614
|
-
});
|
|
615
|
-
|
|
616
|
-
ipcMain.on('ai-notify-clear', () => {
|
|
617
|
-
clearFloatingUnread();
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
ipcMain.on('floating-drag-move', (_event, x, y) => {
|
|
621
|
-
if (!floatingWindow || floatingWindow.isDestroyed()) return;
|
|
622
|
-
const [width, height] = floatingWindow.getSize();
|
|
623
|
-
const posX = Math.round(x - width / 2);
|
|
624
|
-
const posY = Math.round(y - height / 2);
|
|
625
|
-
floatingWindow.setBounds({ x: posX, y: posY, width, height });
|
|
626
|
-
});
|
|
562
|
+
// Floating IPC removed
|
|
627
563
|
|
|
628
564
|
ipcMain.handle('open-external', (event, url) => {
|
|
629
565
|
shell.openExternal(url);
|
|
@@ -924,8 +860,11 @@ async function executeAction(action) {
|
|
|
924
860
|
createFolder(action.target);
|
|
925
861
|
break;
|
|
926
862
|
case 'open_file':
|
|
927
|
-
await openFile(action.target);
|
|
928
|
-
|
|
863
|
+
const fileRes = await openFile(action.target);
|
|
864
|
+
return fileRes || `Successfully opened file: ${action.target} ✅`;
|
|
865
|
+
case 'open_folder':
|
|
866
|
+
const folderRes = await openFile(action.target);
|
|
867
|
+
return folderRes || `Successfully opened folder: ${action.target} ✅`;
|
|
929
868
|
case 'delete_file':
|
|
930
869
|
await deleteFile(action.target);
|
|
931
870
|
break;
|
|
@@ -934,6 +873,20 @@ async function executeAction(action) {
|
|
|
934
873
|
break;
|
|
935
874
|
case 'learn_file':
|
|
936
875
|
return await indexFile(action.target);
|
|
876
|
+
case 'learn_folder':
|
|
877
|
+
const { indexFolder } = require('./src/AI_Brain/knowledge_base');
|
|
878
|
+
return await indexFolder(action.target);
|
|
879
|
+
case 'mcp_tool':
|
|
880
|
+
const mcpResult = await mcpManager.callTool(action.server, action.target, action.args);
|
|
881
|
+
return JSON.stringify(mcpResult.content);
|
|
882
|
+
case 'mouse_move':
|
|
883
|
+
return await granularAutomation.mouseMove(action.x, action.y);
|
|
884
|
+
case 'mouse_click':
|
|
885
|
+
return await granularAutomation.mouseClick(action.x, action.y, action.button || 1);
|
|
886
|
+
case 'type_text':
|
|
887
|
+
return await granularAutomation.typeText(action.target);
|
|
888
|
+
case 'key_tap':
|
|
889
|
+
return await granularAutomation.keyTap(action.target);
|
|
937
890
|
case 'plugin':
|
|
938
891
|
return await pluginManager.executePlugin(action.pluginName, action.target);
|
|
939
892
|
case 'system_automation':
|
package/mint-cli-logic.js
CHANGED
|
@@ -26,11 +26,30 @@ async function executeAction(action) {
|
|
|
26
26
|
case 'open_file':
|
|
27
27
|
await openFile(action.target);
|
|
28
28
|
return `Opening: ${action.target}`;
|
|
29
|
+
case 'open_folder':
|
|
30
|
+
await openFile(action.target);
|
|
31
|
+
return `Opening folder: ${action.target}`;
|
|
29
32
|
case 'delete_file':
|
|
30
33
|
await deleteFile(action.target);
|
|
31
34
|
return `Deleted: ${action.target}`;
|
|
32
35
|
case 'learn_file':
|
|
33
36
|
return await indexFile(action.target);
|
|
37
|
+
case 'mcp_tool':
|
|
38
|
+
const mcpManager = require('./src/Plugins/mcp_manager');
|
|
39
|
+
const mcpResult = await mcpManager.callTool(action.server, action.target, action.args);
|
|
40
|
+
return JSON.stringify(mcpResult.content);
|
|
41
|
+
case 'mouse_move':
|
|
42
|
+
const granularAutomation = require('./src/System/granular_automation');
|
|
43
|
+
return await granularAutomation.mouseMove(action.x, action.y);
|
|
44
|
+
case 'mouse_click':
|
|
45
|
+
const granularAutomationClick = require('./src/System/granular_automation');
|
|
46
|
+
return await granularAutomationClick.mouseClick(action.x, action.y, action.button || 1);
|
|
47
|
+
case 'type_text':
|
|
48
|
+
const granularAutomationType = require('./src/System/granular_automation');
|
|
49
|
+
return await granularAutomationType.typeText(action.target);
|
|
50
|
+
case 'key_tap':
|
|
51
|
+
const granularAutomationKey = require('./src/System/granular_automation');
|
|
52
|
+
return await granularAutomationKey.keyTap(action.target);
|
|
34
53
|
case 'plugin':
|
|
35
54
|
return await pluginManager.executePlugin(action.pluginName, action.target);
|
|
36
55
|
case 'system_automation':
|
package/mint-cli.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
require('dotenv').config({ quiet: true });
|
|
3
3
|
const { Command } = require('commander');
|
|
4
4
|
const { handleChat, resetChat } = require('./src/AI_Brain/Gemini_API');
|
|
5
|
+
const pkg = require('./package.json');
|
|
5
6
|
const { runOnboarding } = require('./src/CLI/onboarding');
|
|
6
7
|
const { startAgent } = require('./src/AI_Brain/headless_agent');
|
|
7
8
|
const { displayFeatures } = require('./src/CLI/list_features');
|
|
8
9
|
const { readConfig, writeConfig } = require('./src/System/config_manager');
|
|
10
|
+
const { executeCodeTask } = require('./src/CLI/code_agent');
|
|
11
|
+
const { detectCodeIntent, runChatRoutedTask } = require('./src/CLI/chat_router');
|
|
9
12
|
const readline = require('readline');
|
|
10
13
|
const { createChatUI } = require('./src/CLI/chat_ui');
|
|
11
14
|
|
|
@@ -17,7 +20,7 @@ const startupTime = startupNow.toLocaleString('th-TH', {
|
|
|
17
20
|
day: '2-digit', month: '2-digit', year: 'numeric',
|
|
18
21
|
hour: '2-digit', minute: '2-digit', hour12: false
|
|
19
22
|
}).replace(',', '');
|
|
20
|
-
console.log(`\x1b[38;5;121m[Mint] ${startupTime} | Active Model: ${startupModel}\x1b[0m`);
|
|
23
|
+
console.log(`\x1b[38;5;121m[Mint] v${pkg.version} | ${startupTime} | Active Model: ${startupModel}\x1b[0m`);
|
|
21
24
|
|
|
22
25
|
// ANSI Colors
|
|
23
26
|
const colors = {
|
|
@@ -35,7 +38,7 @@ const program = new Command();
|
|
|
35
38
|
program
|
|
36
39
|
.name('mint-ai')
|
|
37
40
|
.description('Mint - Your Personal AI Assistant CLI')
|
|
38
|
-
.version(
|
|
41
|
+
.version(pkg.version);
|
|
39
42
|
|
|
40
43
|
// Chat Command (Interactive Mode)
|
|
41
44
|
program
|
|
@@ -92,23 +95,64 @@ program
|
|
|
92
95
|
console.log(`${colors.gray}You will receive a notification when it's done.${colors.reset}\n`);
|
|
93
96
|
});
|
|
94
97
|
|
|
98
|
+
program
|
|
99
|
+
.command('code')
|
|
100
|
+
.description('Run Mint in workspace-aware coding mode for the current project')
|
|
101
|
+
.argument('<task>', 'Coding task to execute in the current working directory')
|
|
102
|
+
.action(async (task) => {
|
|
103
|
+
console.log(`\n${colors.mint}${colors.bright}[Mint Code]${colors.reset} Workspace: ${process.cwd()}`);
|
|
104
|
+
console.log(`${colors.gray}[Mint Code] Task: ${task}${colors.reset}\n`);
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
const result = await executeCodeTask(task, {
|
|
108
|
+
cwd: process.cwd(),
|
|
109
|
+
onProgress: (message) => {
|
|
110
|
+
console.log(`${colors.gray}[Mint Code] ${message}${colors.reset}`);
|
|
111
|
+
},
|
|
112
|
+
requestApproval: requestCodeApproval
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
console.log(`\n${colors.mint}${colors.bright}Summary${colors.reset}`);
|
|
116
|
+
console.log(result.summary);
|
|
117
|
+
console.log(`\n${colors.cyan}Verification:${colors.reset} ${result.verification}`);
|
|
118
|
+
console.log(`${colors.gray}Completed in ${result.steps} step(s).${colors.reset}\n`);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error(`\n${colors.pink}[Mint Code Error]${colors.reset} ${error.message}\n`);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
95
125
|
program.parse(process.argv);
|
|
96
126
|
|
|
97
127
|
/**
|
|
98
128
|
* The Interactive Chat Loop — Gemini-style TUI
|
|
99
129
|
*/
|
|
100
130
|
async function startInteractiveChat(initialMessage = null) {
|
|
101
|
-
const { screen, appendMessage, setThinking, updateStatusModel, copyLastResponse } = createChatUI({
|
|
131
|
+
const { screen, appendMessage, setThinking, updateStatusModel, copyLastResponse, requestApproval, setMode } = createChatUI({
|
|
102
132
|
onSubmit: async (text) => {
|
|
103
133
|
if (text.startsWith('/')) {
|
|
104
134
|
// Slash commands via fake rl-compatible object
|
|
105
135
|
const fakeRl = { close: () => { } };
|
|
106
136
|
appendMessage('user', text);
|
|
107
|
-
await handleSlashCommandUI(text, appendMessage, updateStatusModel, copyLastResponse);
|
|
137
|
+
await handleSlashCommandUI(text, appendMessage, updateStatusModel, copyLastResponse, setThinking, requestApproval, setMode);
|
|
108
138
|
return;
|
|
109
139
|
}
|
|
110
140
|
appendMessage('user', text);
|
|
111
141
|
|
|
142
|
+
const routeDecision = await detectCodeIntent(text, process.cwd());
|
|
143
|
+
if (routeDecision.route === 'code') {
|
|
144
|
+
appendMessage('system', `Router: entering Code Mode. ${routeDecision.reason}`);
|
|
145
|
+
await runChatRoutedTask(text, {
|
|
146
|
+
appendMessage,
|
|
147
|
+
setThinking,
|
|
148
|
+
requestApproval,
|
|
149
|
+
setMode
|
|
150
|
+
});
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
setMode('Chat');
|
|
155
|
+
|
|
112
156
|
// Start thinking timer
|
|
113
157
|
let seconds = 0;
|
|
114
158
|
setThinking(true, seconds);
|
|
@@ -148,18 +192,30 @@ async function startInteractiveChat(initialMessage = null) {
|
|
|
148
192
|
// Handle initial message if passed via CLI arg
|
|
149
193
|
if (initialMessage) {
|
|
150
194
|
appendMessage('user', initialMessage);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
195
|
+
const routeDecision = await detectCodeIntent(initialMessage, process.cwd());
|
|
196
|
+
if (routeDecision.route === 'code') {
|
|
197
|
+
appendMessage('system', `Router: entering Code Mode. ${routeDecision.reason}`);
|
|
198
|
+
await runChatRoutedTask(initialMessage, {
|
|
199
|
+
appendMessage,
|
|
200
|
+
setThinking,
|
|
201
|
+
requestApproval,
|
|
202
|
+
setMode
|
|
203
|
+
});
|
|
204
|
+
} else {
|
|
205
|
+
setMode('Chat');
|
|
206
|
+
let seconds = 0;
|
|
207
|
+
setThinking(true, seconds);
|
|
208
|
+
const timer = setInterval(() => { seconds++; setThinking(true, seconds); }, 1000);
|
|
209
|
+
try {
|
|
210
|
+
const response = await handleChat(initialMessage);
|
|
211
|
+
clearInterval(timer);
|
|
212
|
+
setThinking(false);
|
|
213
|
+
appendMessage('assistant', response.response, response.timestamp);
|
|
214
|
+
} catch (err) {
|
|
215
|
+
clearInterval(timer);
|
|
216
|
+
setThinking(false);
|
|
217
|
+
appendMessage('error', err.message);
|
|
218
|
+
}
|
|
163
219
|
}
|
|
164
220
|
}
|
|
165
221
|
}
|
|
@@ -167,7 +223,7 @@ async function startInteractiveChat(initialMessage = null) {
|
|
|
167
223
|
/**
|
|
168
224
|
* Handles slash commands within the TUI context
|
|
169
225
|
*/
|
|
170
|
-
async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse) {
|
|
226
|
+
async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse, setThinking, requestApproval, setMode) {
|
|
171
227
|
const parts = input.split(' ');
|
|
172
228
|
const command = parts[0].toLowerCase();
|
|
173
229
|
const args = parts.slice(1);
|
|
@@ -177,6 +233,7 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
|
|
|
177
233
|
case '/?':
|
|
178
234
|
appendMessage('system', [
|
|
179
235
|
'Mint Slash Commands:',
|
|
236
|
+
' /code <task> — Force workspace Code Mode',
|
|
180
237
|
' /models [name] — List or switch Gemini models',
|
|
181
238
|
' /config — Show current configuration',
|
|
182
239
|
' /copy — Copy last response to clipboard',
|
|
@@ -214,10 +271,24 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
|
|
|
214
271
|
}
|
|
215
272
|
break;
|
|
216
273
|
|
|
274
|
+
case '/code':
|
|
275
|
+
if (args.length === 0) {
|
|
276
|
+
appendMessage('system', 'Usage: /code <task>');
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
await runChatRoutedTask(`/code ${args.join(' ')}`, {
|
|
280
|
+
appendMessage,
|
|
281
|
+
setThinking,
|
|
282
|
+
requestApproval,
|
|
283
|
+
setMode
|
|
284
|
+
});
|
|
285
|
+
break;
|
|
286
|
+
|
|
217
287
|
case '/config':
|
|
218
288
|
const currentCfg = readConfig();
|
|
219
289
|
appendMessage('system', [
|
|
220
290
|
'Current Configuration:',
|
|
291
|
+
` Version : v${pkg.version}`,
|
|
221
292
|
` Provider : ${currentCfg.aiProvider}`,
|
|
222
293
|
` Model : ${currentCfg.geminiModel}`,
|
|
223
294
|
` Ollama : ${currentCfg.ollamaModel}`,
|
|
@@ -251,3 +322,36 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
|
|
|
251
322
|
}
|
|
252
323
|
}
|
|
253
324
|
|
|
325
|
+
async function requestCodeApproval(request) {
|
|
326
|
+
const typeLabel = request.type === 'shell'
|
|
327
|
+
? 'Shell Command'
|
|
328
|
+
: request.type === 'patch'
|
|
329
|
+
? 'Patch Edit'
|
|
330
|
+
: 'File Write';
|
|
331
|
+
|
|
332
|
+
console.log(`\n${colors.yellow}${colors.bright}[Approval Required]${colors.reset} ${typeLabel}`);
|
|
333
|
+
if (request.label) {
|
|
334
|
+
console.log(`${colors.gray}${request.label}${colors.reset}`);
|
|
335
|
+
}
|
|
336
|
+
if (request.preview) {
|
|
337
|
+
console.log(`${colors.gray}${request.preview}${colors.reset}\n`);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const rl = readline.createInterface({
|
|
341
|
+
input: process.stdin,
|
|
342
|
+
output: process.stdout
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const answer = await new Promise((resolve) => {
|
|
346
|
+
rl.question('Approve this action? [y/N]: ', (value) => {
|
|
347
|
+
rl.close();
|
|
348
|
+
resolve((value || '').trim().toLowerCase());
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
const approved = answer === 'y' || answer === 'yes';
|
|
353
|
+
console.log(approved
|
|
354
|
+
? `${colors.mint}[Mint Code] Approved.${colors.reset}\n`
|
|
355
|
+
: `${colors.pink}[Mint Code] Denied.${colors.reset}\n`);
|
|
356
|
+
return approved;
|
|
357
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pheem49/mint",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A powerful Electron-based AI desktop assistant powered by Google Gemini, featuring screen vision, web automation, and proactive suggestions.",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"scripts": {
|
|
@@ -22,24 +22,30 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@google/genai": "^1.44.0",
|
|
24
24
|
"@inkjs/ui": "^2.0.0",
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
25
26
|
"axios": "^1.13.6",
|
|
26
27
|
"blessed": "^0.1.81",
|
|
27
28
|
"cheerio": "^1.2.0",
|
|
28
29
|
"commander": "^14.0.3",
|
|
29
30
|
"dotenv": "^17.3.1",
|
|
31
|
+
"framer-motion": "^12.38.0",
|
|
30
32
|
"google-tts-api": "^2.0.2",
|
|
31
33
|
"ink": "^7.0.1",
|
|
32
34
|
"ink-text-input": "^6.0.0",
|
|
33
35
|
"inquirer": "^13.4.1",
|
|
36
|
+
"lucide-react": "^1.9.0",
|
|
34
37
|
"mammoth": "^1.12.0",
|
|
35
38
|
"pdf-parse": "^2.4.5",
|
|
36
39
|
"puppeteer": "^24.38.0",
|
|
37
40
|
"react": "^19.2.5",
|
|
41
|
+
"react-dom": "^19.2.5",
|
|
38
42
|
"xlsx": "^0.18.5"
|
|
39
43
|
},
|
|
40
44
|
"devDependencies": {
|
|
45
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
41
46
|
"electron": "^40.7.0",
|
|
42
|
-
"electron-builder": "^26.8.1"
|
|
47
|
+
"electron-builder": "^26.8.1",
|
|
48
|
+
"vite": "^8.0.10"
|
|
43
49
|
},
|
|
44
50
|
"build": {
|
|
45
51
|
"appId": "com.pheem49.mint",
|