@pheem49/mint 1.2.4 → 1.4.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 +55 -23
- package/index.html +16 -0
- package/main.js +36 -83
- package/mint-cli-logic.js +19 -0
- package/mint-cli.js +316 -39
- package/package.json +20 -3
- package/src/AI_Brain/Gemini_API.js +439 -20
- package/src/AI_Brain/agent_orchestrator.js +73 -0
- package/src/AI_Brain/autonomous_brain.js +2 -0
- package/src/AI_Brain/knowledge_base.js +199 -125
- package/src/AI_Brain/memory_store.js +318 -0
- package/src/Automation_Layer/file_operations.js +41 -19
- package/src/CLI/chat_router.js +181 -0
- package/src/CLI/chat_ui.js +321 -110
- package/src/CLI/code_agent.js +556 -0
- package/src/CLI/code_session_memory.js +62 -0
- package/src/CLI/list_features.js +1 -0
- package/src/CLI/onboarding.js +53 -6
- package/src/CLI/workspace_manager.js +81 -0
- package/src/Plugins/mcp_manager.js +95 -0
- package/src/Plugins/plugin_manager.js +2 -2
- package/src/Plugins/spotify.js +168 -40
- package/src/Plugins/system_monitor.js +72 -0
- package/src/System/config_manager.js +61 -8
- package/src/System/granular_automation.js +88 -0
- package/src/System/notifications.js +23 -0
- package/src/UI/settings.html +167 -65
- package/src/UI/settings.js +253 -42
- package/tests/agent_orchestrator.test.js +41 -0
- package/tests/config_manager.test.js +141 -0
- package/tests/memory_store.test.js +185 -0
- package/tests/spotify.test.js +201 -0
- package/tests/system_monitor.test.js +37 -0
- package/tests/workspace_manager.test.js +41 -0
package/mint-cli.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
require('dotenv').config({ quiet: true });
|
|
3
3
|
const { Command } = require('commander');
|
|
4
|
-
const { handleChat, resetChat } = require('./src/AI_Brain/Gemini_API');
|
|
4
|
+
const { handleChat, handleGeminiChatStream, resetChat, refreshApiKeyFromConfig } = require('./src/AI_Brain/Gemini_API');
|
|
5
|
+
const agentOrchestrator = require('./src/AI_Brain/agent_orchestrator');
|
|
6
|
+
const workspaceManager = require('./src/CLI/workspace_manager');
|
|
7
|
+
const systemMonitor = require('./src/Plugins/system_monitor');
|
|
8
|
+
const { sendNotification } = require('./src/System/notifications');
|
|
5
9
|
const pkg = require('./package.json');
|
|
6
10
|
const { runOnboarding } = require('./src/CLI/onboarding');
|
|
7
11
|
const { startAgent } = require('./src/AI_Brain/headless_agent');
|
|
8
12
|
const { displayFeatures } = require('./src/CLI/list_features');
|
|
9
13
|
const { readConfig, writeConfig } = require('./src/System/config_manager');
|
|
14
|
+
const { executeCodeTask } = require('./src/CLI/code_agent');
|
|
15
|
+
const { detectCodeIntent, runChatRoutedTask } = require('./src/CLI/chat_router');
|
|
10
16
|
const readline = require('readline');
|
|
11
17
|
const { createChatUI } = require('./src/CLI/chat_ui');
|
|
12
18
|
|
|
@@ -93,23 +99,138 @@ program
|
|
|
93
99
|
console.log(`${colors.gray}You will receive a notification when it's done.${colors.reset}\n`);
|
|
94
100
|
});
|
|
95
101
|
|
|
102
|
+
program
|
|
103
|
+
.command('code')
|
|
104
|
+
.description('Run Mint in workspace-aware coding mode for the current project')
|
|
105
|
+
.argument('<task>', 'Coding task to execute in the current working directory')
|
|
106
|
+
.action(async (task) => {
|
|
107
|
+
console.log(`\n${colors.mint}${colors.bright}[Mint Code]${colors.reset} Workspace: ${process.cwd()}`);
|
|
108
|
+
console.log(`${colors.gray}[Mint Code] Task: ${task}${colors.reset}\n`);
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const result = await executeCodeTask(task, {
|
|
112
|
+
cwd: process.cwd(),
|
|
113
|
+
onProgress: (message) => {
|
|
114
|
+
console.log(`${colors.gray}[Mint Code] ${message}${colors.reset}`);
|
|
115
|
+
},
|
|
116
|
+
requestApproval: requestCodeApproval
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
console.log(`\n${colors.mint}${colors.bright}Summary${colors.reset}`);
|
|
120
|
+
console.log(result.summary);
|
|
121
|
+
console.log(`\n${colors.cyan}Verification:${colors.reset} ${result.verification}`);
|
|
122
|
+
console.log(`${colors.gray}Completed in ${result.steps} step(s).${colors.reset}\n`);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(`\n${colors.pink}[Mint Code Error]${colors.reset} ${error.message}\n`);
|
|
125
|
+
process.exitCode = 1;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
96
129
|
program.parse(process.argv);
|
|
97
130
|
|
|
98
131
|
/**
|
|
99
132
|
* The Interactive Chat Loop — Gemini-style TUI
|
|
100
133
|
*/
|
|
101
134
|
async function startInteractiveChat(initialMessage = null) {
|
|
102
|
-
|
|
135
|
+
let lastResponseText = "";
|
|
136
|
+
const { screen, appendMessage, streamMessage, setThinking, updateStatusModel, copyLastResponse, requestApproval, setMode } = createChatUI({
|
|
103
137
|
onSubmit: async (text) => {
|
|
104
138
|
if (text.startsWith('/')) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
139
|
+
if (text.startsWith('/agent')) {
|
|
140
|
+
const args = text.split(' ');
|
|
141
|
+
if (args[1] === 'list') {
|
|
142
|
+
appendMessage('system', `Available Agents: ${agentOrchestrator.listAgents().join(', ')}`);
|
|
143
|
+
} else if (args[1]) {
|
|
144
|
+
const success = agentOrchestrator.setAgent(args[1]);
|
|
145
|
+
if (success) {
|
|
146
|
+
const agent = agentOrchestrator.getCurrentAgent();
|
|
147
|
+
appendMessage('system', `Switched to Agent: ${agent.icon} ${agent.name}`);
|
|
148
|
+
updateStatusModel(null, agent.name); // Pass name to status bar
|
|
149
|
+
resetChat(); // Reset to apply new system prompt
|
|
150
|
+
} else {
|
|
151
|
+
appendMessage('error', `Agent "${args[1]}" not found. Try /agent list`);
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
const agent = agentOrchestrator.getCurrentAgent();
|
|
155
|
+
appendMessage('system', `Current Agent: ${agent.icon} ${agent.name}\nUsage: /agent <type> or /agent list`);
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (text.startsWith('/stats')) {
|
|
161
|
+
appendMessage('system', '📊 Fetching system statistics...');
|
|
162
|
+
const stats = await systemMonitor.execute('stats');
|
|
163
|
+
appendMessage('system', stats);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (text.startsWith('/workspace')) {
|
|
168
|
+
const args = text.split(' ');
|
|
169
|
+
const subCmd = args[1];
|
|
170
|
+
|
|
171
|
+
if (subCmd === 'add') {
|
|
172
|
+
const name = args[2];
|
|
173
|
+
const wsPath = args[3] || '.';
|
|
174
|
+
const instructions = args.slice(4).join(' ');
|
|
175
|
+
if (!name) {
|
|
176
|
+
appendMessage('error', 'Usage: /workspace add <name> [path] [instructions]');
|
|
177
|
+
} else {
|
|
178
|
+
workspaceManager.addWorkspace(name, wsPath, instructions);
|
|
179
|
+
appendMessage('system', `Workspace "${name}" registered at ${path.resolve(wsPath)}`);
|
|
180
|
+
resetChat();
|
|
181
|
+
}
|
|
182
|
+
} else if (subCmd === 'list') {
|
|
183
|
+
const all = workspaceManager.listWorkspaces();
|
|
184
|
+
let listMsg = "Registered Workspaces:\n";
|
|
185
|
+
for (const n in all) listMsg += `- ${n}: ${all[n].path}\n`;
|
|
186
|
+
appendMessage('system', Object.keys(all).length ? listMsg : "No workspaces registered.");
|
|
187
|
+
} else if (subCmd === 'remove') {
|
|
188
|
+
const name = args[2];
|
|
189
|
+
if (workspaceManager.removeWorkspace(name)) {
|
|
190
|
+
appendMessage('system', `Removed workspace "${name}"`);
|
|
191
|
+
resetChat();
|
|
192
|
+
} else {
|
|
193
|
+
appendMessage('error', `Workspace "${name}" not found.`);
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
const ws = workspaceManager.getWorkspaceByPath(process.cwd());
|
|
197
|
+
appendMessage('system', ws ? `Current Workspace: ${ws.name}\nPath: ${ws.path}` : "Not currently in a registered workspace.\nUsage: /workspace <add|list|remove>");
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (text.startsWith('/review')) {
|
|
203
|
+
if (!lastResponseText) {
|
|
204
|
+
appendMessage('error', 'Nothing to review yet. Get a response first.');
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
agentOrchestrator.setAgent('reviewer');
|
|
208
|
+
appendMessage('system', '⚖️ Requesting second-pass review from Mint Reviewer...');
|
|
209
|
+
text = `Please review this previous response and provide a critique:\n\n${lastResponseText}`;
|
|
210
|
+
} else {
|
|
211
|
+
// Other slash commands
|
|
212
|
+
const fakeRl = { close: () => { } };
|
|
213
|
+
appendMessage('user', text);
|
|
214
|
+
await handleSlashCommandUI(text, appendMessage, updateStatusModel, copyLastResponse, setThinking, requestApproval, setMode);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
110
217
|
}
|
|
111
218
|
appendMessage('user', text);
|
|
112
219
|
|
|
220
|
+
const routeDecision = await detectCodeIntent(text, process.cwd());
|
|
221
|
+
if (routeDecision.route === 'code') {
|
|
222
|
+
appendMessage('system', `Router: entering Code Mode. ${routeDecision.reason}`);
|
|
223
|
+
await runChatRoutedTask(text, {
|
|
224
|
+
appendMessage,
|
|
225
|
+
setThinking,
|
|
226
|
+
requestApproval,
|
|
227
|
+
setMode
|
|
228
|
+
});
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
setMode('Chat');
|
|
233
|
+
|
|
113
234
|
// Start thinking timer
|
|
114
235
|
let seconds = 0;
|
|
115
236
|
setThinking(true, seconds);
|
|
@@ -119,16 +240,92 @@ async function startInteractiveChat(initialMessage = null) {
|
|
|
119
240
|
}, 1000);
|
|
120
241
|
|
|
121
242
|
try {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
243
|
+
const config = require('./src/System/config_manager').readConfig();
|
|
244
|
+
const provider = config.aiProvider || 'gemini';
|
|
245
|
+
const currentAgent = agentOrchestrator.getCurrentAgent();
|
|
246
|
+
updateStatusModel(null, currentAgent.name);
|
|
247
|
+
if (provider === 'gemini') {
|
|
248
|
+
// ── Streaming path (Gemini only) ──────────────────────────────────
|
|
249
|
+
// Gemini returns JSON so we buffer all chunks and progressively
|
|
250
|
+
// extract the "response" field as more of the JSON arrives.
|
|
251
|
+
clearInterval(timer);
|
|
252
|
+
|
|
253
|
+
let jsonBuffer = '';
|
|
254
|
+
let finalParsed = null;
|
|
255
|
+
let streamer = null;
|
|
256
|
+
let displayedChars = 0; // chars of response text already sent to TUI
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
for await (const event of handleGeminiChatStream(text)) {
|
|
260
|
+
if (event.chunk) {
|
|
261
|
+
jsonBuffer += event.chunk;
|
|
262
|
+
|
|
263
|
+
// Progressively extract readable text from the growing JSON buffer
|
|
264
|
+
const match = jsonBuffer.match(/"response"\s*:\s*"((?:[^"\\]|\\.)*)"/s);
|
|
265
|
+
if (match) {
|
|
266
|
+
const fullText = match[1]
|
|
267
|
+
.replace(/\\n/g, '\n')
|
|
268
|
+
.replace(/\\"/g, '"')
|
|
269
|
+
.replace(/\\\\/g, '\\');
|
|
270
|
+
const newChars = fullText.slice(displayedChars);
|
|
271
|
+
if (newChars.length > 0) {
|
|
272
|
+
if (!streamer) {
|
|
273
|
+
setThinking(false);
|
|
274
|
+
streamer = streamMessage('assistant');
|
|
275
|
+
}
|
|
276
|
+
streamer.appendChunk(newChars);
|
|
277
|
+
displayedChars = fullText.length;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} else if (event.done) {
|
|
281
|
+
finalParsed = event.parsed;
|
|
282
|
+
// Flush any remaining response text not yet displayed
|
|
283
|
+
if (finalParsed && finalParsed.response) {
|
|
284
|
+
const remaining = finalParsed.response.slice(displayedChars);
|
|
285
|
+
if (!streamer) {
|
|
286
|
+
setThinking(false);
|
|
287
|
+
streamer = streamMessage('assistant');
|
|
288
|
+
}
|
|
289
|
+
if (remaining) streamer.appendChunk(remaining);
|
|
290
|
+
}
|
|
291
|
+
if (streamer) {
|
|
292
|
+
streamer.finalize(event.timestamp);
|
|
293
|
+
} else {
|
|
294
|
+
setThinking(false);
|
|
295
|
+
appendMessage('assistant',
|
|
296
|
+
finalParsed ? finalParsed.response : '',
|
|
297
|
+
event.timestamp);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} catch (streamErr) {
|
|
302
|
+
setThinking(false);
|
|
303
|
+
appendMessage('error', streamErr.message);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Execute Actions from the final parsed response
|
|
308
|
+
if (finalParsed) {
|
|
309
|
+
const { executeAction } = require('./mint-cli-logic');
|
|
310
|
+
if (finalParsed.action && finalParsed.action.type !== 'none') {
|
|
311
|
+
const result = await executeAction(finalParsed.action);
|
|
312
|
+
if (result) appendMessage('system', `Action: ${result}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
126
315
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
316
|
+
} else {
|
|
317
|
+
// ── Non-streaming fallback (Ollama, Anthropic, OpenAI, etc.) ──
|
|
318
|
+
const response = await handleChat(text);
|
|
319
|
+
clearInterval(timer);
|
|
320
|
+
setThinking(false);
|
|
321
|
+
lastResponseText = response.response;
|
|
322
|
+
appendMessage('assistant', response.response, response.timestamp);
|
|
323
|
+
|
|
324
|
+
const { executeAction } = require('./mint-cli-logic');
|
|
325
|
+
if (response.action && response.action.type !== 'none') {
|
|
326
|
+
const result = await executeAction(response.action);
|
|
327
|
+
if (result) appendMessage('system', `Action: ${result}`);
|
|
328
|
+
}
|
|
132
329
|
}
|
|
133
330
|
} catch (err) {
|
|
134
331
|
clearInterval(timer);
|
|
@@ -149,18 +346,30 @@ async function startInteractiveChat(initialMessage = null) {
|
|
|
149
346
|
// Handle initial message if passed via CLI arg
|
|
150
347
|
if (initialMessage) {
|
|
151
348
|
appendMessage('user', initialMessage);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
349
|
+
const routeDecision = await detectCodeIntent(initialMessage, process.cwd());
|
|
350
|
+
if (routeDecision.route === 'code') {
|
|
351
|
+
appendMessage('system', `Router: entering Code Mode. ${routeDecision.reason}`);
|
|
352
|
+
await runChatRoutedTask(initialMessage, {
|
|
353
|
+
appendMessage,
|
|
354
|
+
setThinking,
|
|
355
|
+
requestApproval,
|
|
356
|
+
setMode
|
|
357
|
+
});
|
|
358
|
+
} else {
|
|
359
|
+
setMode('Chat');
|
|
360
|
+
let seconds = 0;
|
|
361
|
+
setThinking(true, seconds);
|
|
362
|
+
const timer = setInterval(() => { seconds++; setThinking(true, seconds); }, 1000);
|
|
363
|
+
try {
|
|
364
|
+
const response = await handleChat(initialMessage);
|
|
365
|
+
clearInterval(timer);
|
|
366
|
+
setThinking(false);
|
|
367
|
+
appendMessage('assistant', response.response, response.timestamp);
|
|
368
|
+
} catch (err) {
|
|
369
|
+
clearInterval(timer);
|
|
370
|
+
setThinking(false);
|
|
371
|
+
appendMessage('error', err.message);
|
|
372
|
+
}
|
|
164
373
|
}
|
|
165
374
|
}
|
|
166
375
|
}
|
|
@@ -168,7 +377,7 @@ async function startInteractiveChat(initialMessage = null) {
|
|
|
168
377
|
/**
|
|
169
378
|
* Handles slash commands within the TUI context
|
|
170
379
|
*/
|
|
171
|
-
async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse) {
|
|
380
|
+
async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse, setThinking, requestApproval, setMode) {
|
|
172
381
|
const parts = input.split(' ');
|
|
173
382
|
const command = parts[0].toLowerCase();
|
|
174
383
|
const args = parts.slice(1);
|
|
@@ -178,6 +387,7 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
|
|
|
178
387
|
case '/?':
|
|
179
388
|
appendMessage('system', [
|
|
180
389
|
'Mint Slash Commands:',
|
|
390
|
+
' /code <task> — Force workspace Code Mode',
|
|
181
391
|
' /models [name] — List or switch Gemini models',
|
|
182
392
|
' /config — Show current configuration',
|
|
183
393
|
' /copy — Copy last response to clipboard',
|
|
@@ -192,29 +402,63 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
|
|
|
192
402
|
const config = readConfig();
|
|
193
403
|
if (args.length === 0) {
|
|
194
404
|
appendMessage('system', [
|
|
195
|
-
`Current
|
|
196
|
-
|
|
197
|
-
'
|
|
198
|
-
' - gemini-
|
|
199
|
-
' -
|
|
200
|
-
' -
|
|
405
|
+
`Current Provider: ${config.aiProvider}`,
|
|
406
|
+
`Current Gemini Model: ${config.geminiModel}`,
|
|
407
|
+
'Available Providers/Presets:',
|
|
408
|
+
' - gemini-2.5-flash (Default Gemini)',
|
|
409
|
+
' - ollama (Local provider)',
|
|
410
|
+
' - anthropic (Claude)',
|
|
411
|
+
' - openai (GPT)',
|
|
412
|
+
' - huggingface (Inference API)',
|
|
413
|
+
' - local (LM Studio / OpenAI Compatible)',
|
|
201
414
|
'Usage: /models <name> to switch'
|
|
202
415
|
].join('\n'));
|
|
203
416
|
} else {
|
|
204
417
|
const { writeConfig } = require('./src/System/config_manager');
|
|
205
418
|
const newModel = args[0];
|
|
419
|
+
let newProvider = 'gemini';
|
|
420
|
+
|
|
206
421
|
if (newModel === 'ollama') {
|
|
207
|
-
|
|
422
|
+
newProvider = 'ollama';
|
|
423
|
+
} else if (newModel === 'anthropic') {
|
|
424
|
+
newProvider = 'anthropic';
|
|
425
|
+
} else if (newModel === 'openai') {
|
|
426
|
+
newProvider = 'openai';
|
|
427
|
+
} else if (newModel === 'huggingface') {
|
|
428
|
+
newProvider = 'huggingface';
|
|
429
|
+
} else if (newModel === 'local' || newModel === 'local_openai') {
|
|
430
|
+
newProvider = 'local_openai';
|
|
431
|
+
} else if (newModel.startsWith('gpt-')) {
|
|
432
|
+
newProvider = 'openai';
|
|
433
|
+
config.openaiModel = newModel;
|
|
434
|
+
} else if (newModel.startsWith('claude-')) {
|
|
435
|
+
newProvider = 'anthropic';
|
|
436
|
+
config.anthropicModel = newModel;
|
|
208
437
|
} else {
|
|
209
|
-
|
|
438
|
+
newProvider = 'gemini';
|
|
210
439
|
config.geminiModel = newModel;
|
|
211
440
|
}
|
|
441
|
+
|
|
442
|
+
config.aiProvider = newProvider;
|
|
212
443
|
writeConfig(config);
|
|
213
|
-
appendMessage('system', `✅ Switched to: ${newModel}`);
|
|
214
|
-
if (updateStatusModel) updateStatusModel(newModel);
|
|
444
|
+
appendMessage('system', `✅ Switched to: ${newProvider} ${newProvider === 'gemini' ? `(${newModel})` : ''}`);
|
|
445
|
+
if (updateStatusModel) updateStatusModel(newProvider === 'gemini' ? newModel : newProvider);
|
|
215
446
|
}
|
|
216
447
|
break;
|
|
217
448
|
|
|
449
|
+
case '/code':
|
|
450
|
+
if (args.length === 0) {
|
|
451
|
+
appendMessage('system', 'Usage: /code <task>');
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
await runChatRoutedTask(`/code ${args.join(' ')}`, {
|
|
455
|
+
appendMessage,
|
|
456
|
+
setThinking,
|
|
457
|
+
requestApproval,
|
|
458
|
+
setMode
|
|
459
|
+
});
|
|
460
|
+
break;
|
|
461
|
+
|
|
218
462
|
case '/config':
|
|
219
463
|
const currentCfg = readConfig();
|
|
220
464
|
appendMessage('system', [
|
|
@@ -253,3 +497,36 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
|
|
|
253
497
|
}
|
|
254
498
|
}
|
|
255
499
|
|
|
500
|
+
async function requestCodeApproval(request) {
|
|
501
|
+
const typeLabel = request.type === 'shell'
|
|
502
|
+
? 'Shell Command'
|
|
503
|
+
: request.type === 'patch'
|
|
504
|
+
? 'Patch Edit'
|
|
505
|
+
: 'File Write';
|
|
506
|
+
|
|
507
|
+
console.log(`\n${colors.yellow}${colors.bright}[Approval Required]${colors.reset} ${typeLabel}`);
|
|
508
|
+
if (request.label) {
|
|
509
|
+
console.log(`${colors.gray}${request.label}${colors.reset}`);
|
|
510
|
+
}
|
|
511
|
+
if (request.preview) {
|
|
512
|
+
console.log(`${colors.gray}${request.preview}${colors.reset}\n`);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const rl = readline.createInterface({
|
|
516
|
+
input: process.stdin,
|
|
517
|
+
output: process.stdout
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
const answer = await new Promise((resolve) => {
|
|
521
|
+
rl.question('Approve this action? [y/N]: ', (value) => {
|
|
522
|
+
rl.close();
|
|
523
|
+
resolve((value || '').trim().toLowerCase());
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
|
|
527
|
+
const approved = answer === 'y' || answer === 'yes';
|
|
528
|
+
console.log(approved
|
|
529
|
+
? `${colors.mint}[Mint Code] Approved.${colors.reset}\n`
|
|
530
|
+
: `${colors.pink}[Mint Code] Denied.${colors.reset}\n`);
|
|
531
|
+
return approved;
|
|
532
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pheem49/mint",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.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": {
|
|
7
7
|
"start": "electron .",
|
|
8
|
-
"test": "
|
|
8
|
+
"test": "jest --testPathPatterns=tests/",
|
|
9
|
+
"test:watch": "jest --testPathPatterns=tests/ --watch",
|
|
9
10
|
"build:linux": "electron-builder --linux",
|
|
10
11
|
"cli": "node mint-cli.js"
|
|
11
12
|
},
|
|
13
|
+
"jest": {
|
|
14
|
+
"testEnvironment": "node",
|
|
15
|
+
"testMatch": ["**/tests/**/*.test.js"],
|
|
16
|
+
"collectCoverageFrom": [
|
|
17
|
+
"src/AI_Brain/memory_store.js",
|
|
18
|
+
"src/AI_Brain/knowledge_base.js",
|
|
19
|
+
"src/System/config_manager.js"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
12
22
|
"bin": {
|
|
13
23
|
"mint": "mint-cli.js"
|
|
14
24
|
},
|
|
@@ -22,24 +32,31 @@
|
|
|
22
32
|
"dependencies": {
|
|
23
33
|
"@google/genai": "^1.44.0",
|
|
24
34
|
"@inkjs/ui": "^2.0.0",
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
25
36
|
"axios": "^1.13.6",
|
|
26
37
|
"blessed": "^0.1.81",
|
|
27
38
|
"cheerio": "^1.2.0",
|
|
28
39
|
"commander": "^14.0.3",
|
|
29
40
|
"dotenv": "^17.3.1",
|
|
41
|
+
"framer-motion": "^12.38.0",
|
|
30
42
|
"google-tts-api": "^2.0.2",
|
|
31
43
|
"ink": "^7.0.1",
|
|
32
44
|
"ink-text-input": "^6.0.0",
|
|
33
45
|
"inquirer": "^13.4.1",
|
|
46
|
+
"lucide-react": "^1.9.0",
|
|
34
47
|
"mammoth": "^1.12.0",
|
|
35
48
|
"pdf-parse": "^2.4.5",
|
|
36
49
|
"puppeteer": "^24.38.0",
|
|
37
50
|
"react": "^19.2.5",
|
|
51
|
+
"react-dom": "^19.2.5",
|
|
38
52
|
"xlsx": "^0.18.5"
|
|
39
53
|
},
|
|
40
54
|
"devDependencies": {
|
|
55
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
41
56
|
"electron": "^40.7.0",
|
|
42
|
-
"electron-builder": "^26.8.1"
|
|
57
|
+
"electron-builder": "^26.8.1",
|
|
58
|
+
"jest": "^30.4.0",
|
|
59
|
+
"vite": "^8.0.10"
|
|
43
60
|
},
|
|
44
61
|
"build": {
|
|
45
62
|
"appId": "com.pheem49.mint",
|