@pheem49/mint 1.2.4 → 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 CHANGED
@@ -22,6 +22,9 @@
22
22
  ## 🌟 Highlights
23
23
 
24
24
  - **Dual-Mode AI**: Switch between a beautiful **Desktop GUI** and a professional **CLI**.
25
+ - **Code Agent Mode**: Use `mint code "<task>"` to inspect, edit, and verify a project directly from the current terminal workspace.
26
+ - **Chat-First Workflow**: Regular Mint chat can now auto-route coding requests into workspace Code Mode, so the main chat acts as the control surface.
27
+ - **Visible Mode State**: The CLI status bar now shows whether Mint is currently in `Chat` or `Code` mode.
25
28
  - **Interactive Slash Commands**: Manage models and settings in the terminal with `/model`, `/config`, `/clear`, etc.
26
29
  - **Smart TUI Experience**: Professional message framing, character-wrapped Thai text support, and mouse scroll wheel navigation.
27
30
  - **System Information Action**: Retrieve OS, Kernel, and Architecture details via natural language.
@@ -55,6 +58,7 @@ Mint CLI is built for speed and efficiency. Use the **`mint`** command from anyw
55
58
 
56
59
  ### 🚀 Professional Commands
57
60
  - **`mint`** : Start interactive chat mode (Default).
61
+ - **`mint code "task"`** : Run Mint as a workspace-aware coding agent in the current project folder.
58
62
  - **`mint agent`** : Run Mint as a headless background agent (Monitoring mode).
59
63
  - **`mint agent "task"`** : **[NEW]** Start agent and execute an autonomous task immediately.
60
64
  - **`mint task "task"`** : Delegate a multi-step task to an already running background agent.
@@ -66,6 +70,30 @@ Mint CLI is built for speed and efficiency. Use the **`mint`** command from anyw
66
70
  ### 🤖 Autonomous Agent (Task Delegate)
67
71
  Mint isn't just a chatbot—it's an autonomous worker. Assign complex tasks that require multiple steps of reasoning.
68
72
 
73
+ ### 👨‍💻 Code Agent Mode
74
+ Mint now includes a dedicated coding workflow as the first step toward a Claude-Code-like experience in the terminal.
75
+
76
+ **What it can do now:**
77
+ - Inspect the current workspace before editing
78
+ - Search code across the repo
79
+ - Read targeted file ranges
80
+ - Run non-destructive shell commands in the project with interactive approval
81
+ - Apply patch-based file edits with approval before changes are written
82
+ - Reuse lightweight session memory and git/test context per project
83
+
84
+ **Usage Example:**
85
+ ```bash
86
+ mint code "fix the failing CLI command and verify it"
87
+ ```
88
+
89
+ **Chat-first Example:**
90
+ ```bash
91
+ mint
92
+ > สำรวจโปรเจคนี้ให้หน่อย
93
+ ```
94
+
95
+ Mint will classify the request, switch the status bar to `Code`, and return to `Chat` mode after the coding flow finishes.
96
+
69
97
  **Supported Autonomous Tools:**
70
98
  - 🌐 **Web Automation**: Full Puppeteer-based browsing, info extraction, and research.
71
99
  - 📁 **File System**: Create, Write, Delete, and Manage folders using `~/` path expansion.
package/index.html ADDED
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Mint AI</title>
7
+ <!-- We can add Google Fonts here -->
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Outfit:wght@500;600;700&display=swap" rel="stylesheet">
11
+ </head>
12
+ <body>
13
+ <div id="root"></div>
14
+ <script type="module" src="/ui/src/main.jsx"></script>
15
+ </body>
16
+ </html>
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
- function createFloatingWindow() {
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
- function updateFloatingUnread() {
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: `⚠️ แบตเตอรี่เหลือน้อยแล้วนะคะ (${level}%) อย่าลืมเสียบสายชาร์จนะค๊า ✨`,
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.hide();
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
- break;
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
@@ -7,6 +7,8 @@ const { runOnboarding } = require('./src/CLI/onboarding');
7
7
  const { startAgent } = require('./src/AI_Brain/headless_agent');
8
8
  const { displayFeatures } = require('./src/CLI/list_features');
9
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');
10
12
  const readline = require('readline');
11
13
  const { createChatUI } = require('./src/CLI/chat_ui');
12
14
 
@@ -93,23 +95,64 @@ program
93
95
  console.log(`${colors.gray}You will receive a notification when it's done.${colors.reset}\n`);
94
96
  });
95
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
+
96
125
  program.parse(process.argv);
97
126
 
98
127
  /**
99
128
  * The Interactive Chat Loop — Gemini-style TUI
100
129
  */
101
130
  async function startInteractiveChat(initialMessage = null) {
102
- const { screen, appendMessage, setThinking, updateStatusModel, copyLastResponse } = createChatUI({
131
+ const { screen, appendMessage, setThinking, updateStatusModel, copyLastResponse, requestApproval, setMode } = createChatUI({
103
132
  onSubmit: async (text) => {
104
133
  if (text.startsWith('/')) {
105
134
  // Slash commands via fake rl-compatible object
106
135
  const fakeRl = { close: () => { } };
107
136
  appendMessage('user', text);
108
- await handleSlashCommandUI(text, appendMessage, updateStatusModel, copyLastResponse);
137
+ await handleSlashCommandUI(text, appendMessage, updateStatusModel, copyLastResponse, setThinking, requestApproval, setMode);
109
138
  return;
110
139
  }
111
140
  appendMessage('user', text);
112
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
+
113
156
  // Start thinking timer
114
157
  let seconds = 0;
115
158
  setThinking(true, seconds);
@@ -149,18 +192,30 @@ async function startInteractiveChat(initialMessage = null) {
149
192
  // Handle initial message if passed via CLI arg
150
193
  if (initialMessage) {
151
194
  appendMessage('user', initialMessage);
152
- let seconds = 0;
153
- setThinking(true, seconds);
154
- const timer = setInterval(() => { seconds++; setThinking(true, seconds); }, 1000);
155
- try {
156
- const response = await handleChat(initialMessage);
157
- clearInterval(timer);
158
- setThinking(false);
159
- appendMessage('assistant', response.response, response.timestamp);
160
- } catch (err) {
161
- clearInterval(timer);
162
- setThinking(false);
163
- appendMessage('error', err.message);
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
+ }
164
219
  }
165
220
  }
166
221
  }
@@ -168,7 +223,7 @@ async function startInteractiveChat(initialMessage = null) {
168
223
  /**
169
224
  * Handles slash commands within the TUI context
170
225
  */
171
- async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse) {
226
+ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, copyLastResponse, setThinking, requestApproval, setMode) {
172
227
  const parts = input.split(' ');
173
228
  const command = parts[0].toLowerCase();
174
229
  const args = parts.slice(1);
@@ -178,6 +233,7 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
178
233
  case '/?':
179
234
  appendMessage('system', [
180
235
  'Mint Slash Commands:',
236
+ ' /code <task> — Force workspace Code Mode',
181
237
  ' /models [name] — List or switch Gemini models',
182
238
  ' /config — Show current configuration',
183
239
  ' /copy — Copy last response to clipboard',
@@ -215,6 +271,19 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
215
271
  }
216
272
  break;
217
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
+
218
287
  case '/config':
219
288
  const currentCfg = readConfig();
220
289
  appendMessage('system', [
@@ -253,3 +322,36 @@ async function handleSlashCommandUI(input, appendMessage, updateStatusModel, cop
253
322
  }
254
323
  }
255
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.2.4",
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",