@pheem49/mint 1.2.1

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.
Files changed (69) hide show
  1. package/BUILD_AND_RELEASE.md +75 -0
  2. package/LICENSE +654 -0
  3. package/README.md +165 -0
  4. package/assets/Agent_Mint.png +0 -0
  5. package/assets/CLI_Screen.png +0 -0
  6. package/assets/Settings.png +0 -0
  7. package/assets/icon.png +0 -0
  8. package/benchmark_ai.js +71 -0
  9. package/main.js +968 -0
  10. package/mint-cli-logic.js +71 -0
  11. package/mint-cli.js +239 -0
  12. package/package.json +60 -0
  13. package/preload-picker.js +11 -0
  14. package/preload-settings.js +11 -0
  15. package/preload.js +37 -0
  16. package/privacy.txt +1 -0
  17. package/src/AI_Brain/Gemini_API.js +419 -0
  18. package/src/AI_Brain/autonomous_brain.js +139 -0
  19. package/src/AI_Brain/behavior_memory.js +114 -0
  20. package/src/AI_Brain/headless_agent.js +120 -0
  21. package/src/AI_Brain/knowledge_base.js +222 -0
  22. package/src/AI_Brain/proactive_engine.js +168 -0
  23. package/src/Automation_Layer/browser_automation.js +147 -0
  24. package/src/Automation_Layer/file_operations.js +80 -0
  25. package/src/Automation_Layer/open_app.js +56 -0
  26. package/src/Automation_Layer/open_website.js +38 -0
  27. package/src/CLI/chat_ui.js +468 -0
  28. package/src/CLI/list_features.js +56 -0
  29. package/src/CLI/onboarding.js +60 -0
  30. package/src/Command_Parser/parser.js +34 -0
  31. package/src/Plugins/dev_tools.js +41 -0
  32. package/src/Plugins/discord.js +20 -0
  33. package/src/Plugins/docker.js +45 -0
  34. package/src/Plugins/google_calendar.js +26 -0
  35. package/src/Plugins/obsidian.js +54 -0
  36. package/src/Plugins/plugin_manager.js +81 -0
  37. package/src/Plugins/spotify.js +45 -0
  38. package/src/Plugins/system_metrics.js +31 -0
  39. package/src/System/chat_history_manager.js +57 -0
  40. package/src/System/config_manager.js +73 -0
  41. package/src/System/custom_workflows.js +127 -0
  42. package/src/System/daemon_manager.js +67 -0
  43. package/src/System/system_automation.js +88 -0
  44. package/src/System/system_events.js +79 -0
  45. package/src/System/system_info.js +55 -0
  46. package/src/System/task_manager.js +85 -0
  47. package/src/UI/floating.css +80 -0
  48. package/src/UI/floating.html +17 -0
  49. package/src/UI/floating.js +67 -0
  50. package/src/UI/index.html +126 -0
  51. package/src/UI/preload-floating.js +7 -0
  52. package/src/UI/preload-spotlight.js +10 -0
  53. package/src/UI/preload-widget.js +5 -0
  54. package/src/UI/proactive-glow.html +42 -0
  55. package/src/UI/renderer.js +978 -0
  56. package/src/UI/screenPicker.html +214 -0
  57. package/src/UI/screenPicker.js +262 -0
  58. package/src/UI/settings.css +705 -0
  59. package/src/UI/settings.html +396 -0
  60. package/src/UI/settings.js +514 -0
  61. package/src/UI/spotlight.css +119 -0
  62. package/src/UI/spotlight.html +23 -0
  63. package/src/UI/spotlight.js +181 -0
  64. package/src/UI/styles.css +627 -0
  65. package/src/UI/widget.css +218 -0
  66. package/src/UI/widget.html +29 -0
  67. package/src/UI/widget.js +10 -0
  68. package/tech_news.txt +3 -0
  69. package/test_knowledge.txt +3 -0
@@ -0,0 +1,71 @@
1
+ // Mint CLI Action Logic
2
+ const { openApp } = require('./src/Automation_Layer/open_app');
3
+ const { openWebsite, openSearch } = require('./src/Automation_Layer/open_website');
4
+ const { createFolder, openFile, deleteFile } = require('./src/Automation_Layer/file_operations');
5
+ const { indexFile } = require('./src/AI_Brain/knowledge_base');
6
+ const SystemAutomation = require('./src/System/system_automation');
7
+ const pluginManager = require('./src/Plugins/plugin_manager');
8
+
9
+ async function executeAction(action) {
10
+ if (!action || action.type === 'none') return null;
11
+
12
+ try {
13
+ switch (action.type) {
14
+ case 'open_url':
15
+ openWebsite(action.target);
16
+ return `Opened URL: ${action.target}`;
17
+ case 'search':
18
+ openSearch(action.target);
19
+ return `Searching for: ${action.target}`;
20
+ case 'open_app':
21
+ openApp(action.target);
22
+ return `Opening app: ${action.target}`;
23
+ case 'create_folder':
24
+ createFolder(action.target);
25
+ return `Created folder: ${action.target}`;
26
+ case 'open_file':
27
+ await openFile(action.target);
28
+ return `Opening: ${action.target}`;
29
+ case 'delete_file':
30
+ await deleteFile(action.target);
31
+ return `Deleted: ${action.target}`;
32
+ case 'learn_file':
33
+ return await indexFile(action.target);
34
+ case 'plugin':
35
+ return await pluginManager.executePlugin(action.pluginName, action.target);
36
+ case 'system_automation':
37
+ return await handleSystemAutomation(action.target);
38
+ default:
39
+ return `Action ${action.type} is not yet fully supported in CLI.`;
40
+ }
41
+ } catch (err) {
42
+ return `Error executing action: ${err.message}`;
43
+ }
44
+ }
45
+
46
+ async function handleSystemAutomation(target) {
47
+ const [cmd, value] = target.split(':');
48
+ switch (cmd) {
49
+ case 'volume':
50
+ return await SystemAutomation.setVolume(parseInt(value));
51
+ case 'mute':
52
+ return await SystemAutomation.mute();
53
+ case 'brightness':
54
+ return await SystemAutomation.setBrightness(parseInt(value));
55
+ case 'sleep':
56
+ return await SystemAutomation.sleep();
57
+ case 'restart':
58
+ return await SystemAutomation.restart();
59
+ case 'shutdown':
60
+ return await SystemAutomation.shutdown();
61
+ case 'minimize_all':
62
+ return await SystemAutomation.minimizeAll();
63
+ default:
64
+ if (SystemAutomation[target]) {
65
+ return await SystemAutomation[target]();
66
+ }
67
+ throw new Error(`Unknown system command: ${target}`);
68
+ }
69
+ }
70
+
71
+ module.exports = { executeAction };
package/mint-cli.js ADDED
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env node
2
+ require('dotenv').config();
3
+ const { Command } = require('commander');
4
+ const { handleChat, resetChat } = require('./src/AI_Brain/Gemini_API');
5
+ const { runOnboarding } = require('./src/CLI/onboarding');
6
+ const { startAgent } = require('./src/AI_Brain/headless_agent');
7
+ const { displayFeatures } = require('./src/CLI/list_features');
8
+ const { readConfig, writeConfig } = require('./src/System/config_manager');
9
+ const readline = require('readline');
10
+ const { createChatUI } = require('./src/CLI/chat_ui');
11
+
12
+ // ANSI Colors
13
+ const colors = {
14
+ reset: "\x1b[0m",
15
+ bright: "\x1b[1m",
16
+ mint: "\x1b[38;5;121m",
17
+ pink: "\x1b[38;5;213m",
18
+ gray: "\x1b[90m",
19
+ cyan: "\x1b[36m",
20
+ yellow: "\x1b[33m"
21
+ };
22
+
23
+ const program = new Command();
24
+
25
+ program
26
+ .name('mint-ai')
27
+ .description('Mint - Your Personal AI Assistant CLI')
28
+ .version('1.0.0');
29
+
30
+ // Chat Command (Interactive Mode)
31
+ program
32
+ .command('chat', { isDefault: true })
33
+ .description('Start interactive chat session with Mint')
34
+ .argument('[message]', 'Initial message to send to Mint')
35
+ .action(async (message) => {
36
+ await startInteractiveChat(message);
37
+ });
38
+
39
+ // Onboard Command
40
+ program
41
+ .command('onboard')
42
+ .description('Setup Mint for the first time')
43
+ .option('--install-daemon', 'Automatically install systemd background agent')
44
+ .action(async (options) => {
45
+ await runOnboarding(options);
46
+ });
47
+
48
+ // Agent Command (Headless Daemon Mode)
49
+ program
50
+ .command('agent')
51
+ .description('Run Mint as a background agent (headless)')
52
+ .argument('[initialTask]', 'Optional first task to perform immediately on startup')
53
+ .action(async (initialTask) => {
54
+ if (initialTask) {
55
+ const taskManager = require('./src/System/task_manager');
56
+ taskManager.addTask(initialTask);
57
+ console.log(`\n${colors.mint}${colors.bright}[Mint-Agent] Starting with initial task:${colors.reset} "${initialTask}"`);
58
+ }
59
+ await startAgent();
60
+ });
61
+
62
+ // List Command
63
+ program
64
+ .command('list')
65
+ .description('Show list of Mint features and commands')
66
+ .action(() => {
67
+ displayFeatures();
68
+ });
69
+
70
+ // Task Command (Autonomous Background Task)
71
+ program
72
+ .command('task')
73
+ .description('Delegate a complex task to the background agent')
74
+ .argument('<description>', 'Description of the task for Mint to perform autonomously')
75
+ .action(async (description) => {
76
+ const taskManager = require('./src/System/task_manager');
77
+ const task = taskManager.addTask(description);
78
+ console.log(`\n${colors.mint}${colors.bright}Task Received!${colors.reset}`);
79
+ console.log(`${colors.gray}Task ID: ${task.id}${colors.reset}`);
80
+ console.log(`"${description}"`);
81
+ console.log(`\n${colors.cyan}Mint Agent is starting to work on this in the background.${colors.reset}`);
82
+ console.log(`${colors.gray}You will receive a notification when it's done.${colors.reset}\n`);
83
+ });
84
+
85
+ program.parse(process.argv);
86
+
87
+ /**
88
+ * The Interactive Chat Loop — Gemini-style TUI
89
+ */
90
+ async function startInteractiveChat(initialMessage = null) {
91
+ const { screen, appendMessage, setThinking, updateStatusModel, copyLastResponse } = createChatUI({
92
+ onSubmit: async (text) => {
93
+ if (text.startsWith('/')) {
94
+ // Slash commands via fake rl-compatible object
95
+ const fakeRl = { close: () => {} };
96
+ appendMessage('user', text);
97
+ await handleSlashCommandUI(text, appendMessage, updateStatusModel, copyLastResponse);
98
+ return;
99
+ }
100
+ appendMessage('user', text);
101
+
102
+ // Start thinking timer
103
+ let seconds = 0;
104
+ setThinking(true, seconds);
105
+ const timer = setInterval(() => {
106
+ seconds++;
107
+ setThinking(true, seconds);
108
+ }, 1000);
109
+
110
+ try {
111
+ const response = await handleChat(text);
112
+ clearInterval(timer);
113
+ setThinking(false);
114
+ appendMessage('assistant', response.response);
115
+
116
+ // Execute Actions
117
+ const { executeAction } = require('./mint-cli-logic');
118
+ if (response.action && response.action.type !== 'none') {
119
+ const result = await executeAction(response.action);
120
+ if (result) appendMessage('system', `Action: ${result}`);
121
+ }
122
+ } catch (err) {
123
+ clearInterval(timer);
124
+ setThinking(false);
125
+ appendMessage('error', err.message);
126
+ }
127
+ },
128
+ onExit: () => {
129
+ screen.destroy();
130
+ console.log(`\n${colors.pink}Goodbye! See you again soon!${colors.reset}\n`);
131
+ process.exit(0);
132
+ }
133
+ });
134
+
135
+ // Handle initial message if passed via CLI arg
136
+ if (initialMessage) {
137
+ appendMessage('user', initialMessage);
138
+ let seconds = 0;
139
+ setThinking(true, seconds);
140
+ const timer = setInterval(() => { seconds++; setThinking(true, seconds); }, 1000);
141
+ try {
142
+ const response = await handleChat(initialMessage);
143
+ clearInterval(timer);
144
+ setThinking(false);
145
+ appendMessage('assistant', response.response);
146
+ } catch (err) {
147
+ clearInterval(timer);
148
+ setThinking(false);
149
+ appendMessage('error', err.message);
150
+ }
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Handles slash commands within the TUI context
156
+ */
157
+ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse) {
158
+ const parts = input.split(' ');
159
+ const command = parts[0].toLowerCase();
160
+ const args = parts.slice(1);
161
+
162
+ switch (command) {
163
+ case '/help':
164
+ case '/?':
165
+ appendMessage('system', [
166
+ 'Mint Slash Commands:',
167
+ ' /models [name] — List or switch Gemini models',
168
+ ' /config — Show current configuration',
169
+ ' /copy — Copy last response to clipboard',
170
+ ' /clear — Clear conversation history',
171
+ ' /reset — Reset conversation history',
172
+ ' /exit — Exit Mint'
173
+ ].join('\n'));
174
+ break;
175
+
176
+ case '/models':
177
+ const config = readConfig();
178
+ if (args.length === 0) {
179
+ appendMessage('system', [
180
+ `Current Model: ${config.geminiModel}`,
181
+ 'Available Presets:',
182
+ ' - gemini-2.5-flash (Default)',
183
+ ' - gemini-3.1-flash-lite-preview',
184
+ ' - gemini-3.1-flash-lite',
185
+ ' - ollama (local provider)',
186
+ 'Usage: /models <name> to switch'
187
+ ].join('\n'));
188
+ } else {
189
+ const { writeConfig } = require('./src/System/config_manager');
190
+ const newModel = args[0];
191
+ if (newModel === 'ollama') {
192
+ config.aiProvider = 'ollama';
193
+ } else {
194
+ config.aiProvider = 'gemini';
195
+ config.geminiModel = newModel;
196
+ }
197
+ writeConfig(config);
198
+ appendMessage('system', `✅ Switched to: ${newModel}`);
199
+ if (updateStatusModel) updateStatusModel(newModel);
200
+ }
201
+ break;
202
+
203
+ case '/config':
204
+ const currentCfg = readConfig();
205
+ appendMessage('system', [
206
+ 'Current Configuration:',
207
+ ` Provider : ${currentCfg.aiProvider}`,
208
+ ` Model : ${currentCfg.geminiModel}`,
209
+ ` Ollama : ${currentCfg.ollamaModel}`,
210
+ ` Voice : ${currentCfg.enableVoiceReply ? 'ON' : 'OFF'}`,
211
+ ` Language : ${currentCfg.language}`,
212
+ ` API Key : ${currentCfg.apiKey ? 'SET (****)' : 'NOT SET'}`
213
+ ].join('\n'));
214
+ break;
215
+
216
+ case '/copy':
217
+ if (copyLastResponse && copyLastResponse()) {
218
+ appendMessage('system', '✓ Last response copied to clipboard.');
219
+ } else {
220
+ appendMessage('system', '✖ Nothing to copy, or xclip/xsel not installed.');
221
+ }
222
+ break;
223
+
224
+ case '/clear':
225
+ case '/reset':
226
+ resetChat();
227
+ appendMessage('system', 'Conversation history cleared.');
228
+ break;
229
+
230
+ case '/exit':
231
+ case '/quit':
232
+ process.exit(0);
233
+ break;
234
+
235
+ default:
236
+ appendMessage('system', `Unknown command: ${command}. Type /help for options.`);
237
+ }
238
+ }
239
+
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@pheem49/mint",
3
+ "version": "1.2.1",
4
+ "description": "A powerful Electron-based AI desktop assistant powered by Google Gemini, featuring screen vision, web automation, and proactive suggestions.",
5
+ "main": "main.js",
6
+ "scripts": {
7
+ "start": "electron .",
8
+ "test": "echo \"Error: no test specified\" && exit 1",
9
+ "build:linux": "electron-builder --linux",
10
+ "cli": "node mint-cli.js"
11
+ },
12
+ "bin": {
13
+ "mint": "mint-cli.js"
14
+ },
15
+ "keywords": [],
16
+ "author": {
17
+ "name": "Pheem49",
18
+ "email": "killerpheem13@gmail.com"
19
+ },
20
+ "license": "AGPL-3.0-only",
21
+ "type": "commonjs",
22
+ "dependencies": {
23
+ "@google/genai": "^1.44.0",
24
+ "@inkjs/ui": "^2.0.0",
25
+ "axios": "^1.13.6",
26
+ "blessed": "^0.1.81",
27
+ "cheerio": "^1.2.0",
28
+ "commander": "^14.0.3",
29
+ "dotenv": "^17.3.1",
30
+ "google-tts-api": "^2.0.2",
31
+ "ink": "^7.0.1",
32
+ "ink-text-input": "^6.0.0",
33
+ "inquirer": "^13.4.1",
34
+ "mammoth": "^1.12.0",
35
+ "pdf-parse": "^2.4.5",
36
+ "puppeteer": "^24.38.0",
37
+ "react": "^19.2.5",
38
+ "xlsx": "^0.18.5"
39
+ },
40
+ "devDependencies": {
41
+ "electron": "^40.7.0",
42
+ "electron-builder": "^26.8.1"
43
+ },
44
+ "build": {
45
+ "appId": "com.yourname.mint",
46
+ "productName": "Mint",
47
+ "files": [
48
+ "**/*",
49
+ "!node_modules/.cache/**"
50
+ ],
51
+ "linux": {
52
+ "icon": "assets/icon.png",
53
+ "target": [
54
+ "AppImage",
55
+ "deb"
56
+ ],
57
+ "category": "Utility"
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,11 @@
1
+ const { contextBridge, ipcRenderer } = require('electron');
2
+
3
+ contextBridge.exposeInMainWorld('electronPicker', {
4
+ onScreenshot: (callback) => ipcRenderer.on('screenshot-data', (_, data) => callback(data)),
5
+ sendSelection: (base64Image) => ipcRenderer.send('vision-selection', base64Image),
6
+ startContinuousTranslation: (rect) => ipcRenderer.send('vision-translate-start', rect),
7
+ stopContinuousTranslation: () => ipcRenderer.send('vision-translate-stop'),
8
+ onTranslationResult: (callback) => ipcRenderer.on('vision-translate-result', (_, text) => callback(text)),
9
+ closePicker: () => ipcRenderer.send('vision-cancel'),
10
+ setOverlayInteractable: (isInteractable) => ipcRenderer.send('vision-overlay-interactable', isInteractable)
11
+ });
@@ -0,0 +1,11 @@
1
+ const { contextBridge, ipcRenderer } = require('electron');
2
+
3
+ contextBridge.exposeInMainWorld('settingsApi', {
4
+ getSettings: () => ipcRenderer.invoke('get-settings'),
5
+ saveSettings: (config) => ipcRenderer.invoke('save-settings', config),
6
+ closeSettings: () => ipcRenderer.send('close-settings'),
7
+ quitApp: () => ipcRenderer.send('quit-app'),
8
+ openExternal: (url) => ipcRenderer.invoke('open-external', url),
9
+ openCustomWorkflows: () => ipcRenderer.invoke('open-custom-workflows'),
10
+ reloadCustomWorkflows: () => ipcRenderer.invoke('reload-custom-workflows'),
11
+ });
package/preload.js ADDED
@@ -0,0 +1,37 @@
1
+ const { contextBridge, ipcRenderer } = require('electron');
2
+
3
+ contextBridge.exposeInMainWorld('api', {
4
+ sendMessage: (message, base64Image, base64Audio) => ipcRenderer.invoke('chat-message', message, base64Image, base64Audio),
5
+ closeWindow: () => ipcRenderer.send('close-window'),
6
+ minimizeWindow: () => ipcRenderer.send('minimize-window'),
7
+ quitApp: () => ipcRenderer.send('quit-app'),
8
+ maximizeWindow: () => ipcRenderer.send('maximize-window'),
9
+ resetChat: () => ipcRenderer.invoke('reset-chat'),
10
+ getChatHistory: () => ipcRenderer.invoke('get-chat-history'),
11
+ openSettings: () => ipcRenderer.invoke('open-settings'),
12
+ // Clipboard
13
+ readClipboard: () => ipcRenderer.invoke('clipboard-read'),
14
+ writeClipboard: (text) => ipcRenderer.invoke('clipboard-write', text),
15
+ // System Info
16
+ getSystemInfo: () => ipcRenderer.invoke('get-system-info'),
17
+ getWeather: (city) => ipcRenderer.invoke('get-weather', city),
18
+ // Settings
19
+ getSettings: () => ipcRenderer.invoke('get-settings'),
20
+ // Listen for settings changes from other window
21
+ onSettingsChanged: (callback) => ipcRenderer.on('settings-changed', (event, data) => callback(data)),
22
+ // Vision
23
+ startVision: () => ipcRenderer.invoke('start-screen-capture'),
24
+ onVisionReady: (callback) => ipcRenderer.on('vision-ready', (event, data) => callback(data)),
25
+ captureSilentScreen: () => ipcRenderer.invoke('capture-silent-screen'),
26
+ // Proactive Assistant
27
+ onProactiveSuggestion: (callback) => ipcRenderer.on('proactive-suggestion', (event, data) => callback(data)),
28
+ onProactiveNotification: (callback) => ipcRenderer.on('proactive-notification', (event, data) => callback(data)),
29
+ toggleProactive: (isOn) => ipcRenderer.send('toggle-proactive', isOn),
30
+ recordBehavior: (context) => ipcRenderer.send('record-behavior', context),
31
+ executeProactiveAction: (action) => ipcRenderer.invoke('execute-proactive-action', action),
32
+ onSpotlightToChat: (callback) => ipcRenderer.on('spotlight-to-chat', (_event, query) => callback(query)),
33
+ notifyAiResponse: () => ipcRenderer.send('ai-notify'),
34
+ clearAiNotifications: () => ipcRenderer.send('ai-notify-clear'),
35
+ getTtsUrls: (text) => ipcRenderer.invoke('get-tts-urls', text),
36
+ setAiState: (state) => ipcRenderer.send('set-ai-state', state)
37
+ });
package/privacy.txt ADDED
@@ -0,0 +1 @@
1
+ DuckDuckGo is considered more private than Google because it does not store your search history, track your personal data, or build advertising profiles based on your activity. While Google uses user search data to create personalized profiles for targeted advertising, DuckDuckGo provides anonymous search results. Additionally, DuckDuckGo's browser and extensions offer features like third-party tracker blocking and automatic HTTPS upgrades to further enhance user anonymity and security.