@pheem49/mint 1.4.2 → 1.5.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.
Files changed (60) hide show
  1. package/GUIDE_TH.md +113 -0
  2. package/README.md +239 -76
  3. package/assets/CLI_Screen.png +0 -0
  4. package/docs/assets/CLI_Screen.png +0 -0
  5. package/docs/guide.html +632 -0
  6. package/docs/index.html +5 -4
  7. package/main.js +66 -894
  8. package/mint-cli-logic.js +13 -1
  9. package/mint-cli.js +100 -9
  10. package/package.json +12 -4
  11. package/src/AI_Brain/Gemini_API.js +77 -20
  12. package/src/AI_Brain/autonomous_brain.js +10 -0
  13. package/src/AI_Brain/behavior_memory.js +26 -5
  14. package/src/AI_Brain/headless_agent.js +4 -0
  15. package/src/AI_Brain/knowledge_base.js +61 -8
  16. package/src/AI_Brain/memory_store.js +55 -7
  17. package/src/Automation_Layer/file_operations.js +1 -1
  18. package/src/CLI/chat_router.js +3 -2
  19. package/src/CLI/chat_ui.js +263 -838
  20. package/src/CLI/code_agent.js +144 -42
  21. package/src/CLI/gmail_auth.js +210 -0
  22. package/src/CLI/list_features.js +2 -0
  23. package/src/CLI/onboarding.js +307 -55
  24. package/src/CLI/updater.js +208 -0
  25. package/src/Channels/brave_search_bridge.js +35 -0
  26. package/src/Channels/discord_bridge.js +68 -0
  27. package/src/Channels/google_search_bridge.js +38 -0
  28. package/src/Channels/line_bridge.js +60 -0
  29. package/src/Channels/slack_bridge.js +53 -0
  30. package/src/Channels/telegram_bridge.js +49 -0
  31. package/src/Channels/whatsapp_bridge.js +55 -0
  32. package/src/Command_Parser/parser.js +12 -1
  33. package/src/Plugins/gmail.js +251 -0
  34. package/src/Plugins/google_calendar.js +245 -19
  35. package/src/Plugins/notion.js +256 -0
  36. package/src/System/action_executor.js +129 -0
  37. package/src/System/bridge_manager.js +76 -0
  38. package/src/System/chat_history_manager.js +23 -5
  39. package/src/System/config_manager.js +41 -7
  40. package/src/System/custom_workflows.js +31 -2
  41. package/src/System/google_tts_urls.js +51 -0
  42. package/src/System/ipc_handlers.js +238 -0
  43. package/src/System/proactive_loop.js +137 -0
  44. package/src/System/safety_manager.js +165 -0
  45. package/src/System/screen_capture.js +175 -0
  46. package/src/System/task_manager.js +15 -5
  47. package/src/System/window_manager.js +210 -0
  48. package/src/UI/renderer.js +33 -7
  49. package/src/UI/settings.html +24 -0
  50. package/src/UI/settings.js +14 -4
  51. package/src/UI/styles.css +14 -1
  52. package/tests/action_executor_safety.test.js +67 -0
  53. package/tests/gmail.test.js +135 -0
  54. package/tests/gmail_auth.test.js +129 -0
  55. package/tests/google_calendar.test.js +113 -0
  56. package/tests/google_tts_urls.test.js +24 -0
  57. package/tests/notion.test.js +121 -0
  58. package/tests/provider_routing.test.js +17 -1
  59. package/tests/safety_manager.test.js +40 -0
  60. package/tests/updater.test.js +32 -0
@@ -25,12 +25,32 @@ try {
25
25
 
26
26
  function getDbPath() {
27
27
  const fileName = 'mint-knowledge.sqlite'; // shared DB with knowledge_base
28
- if (app && app.getPath) {
29
- return path.join(app.getPath('userData'), fileName);
28
+ const configDir = path.join(os.homedir(), '.config', 'mint');
29
+ const dbPath = path.join(configDir, fileName);
30
+
31
+ if (!fs.existsSync(configDir)) {
32
+ fs.mkdirSync(configDir, { recursive: true });
30
33
  }
31
- const mintDir = path.join(os.homedir(), '.mint');
32
- if (!fs.existsSync(mintDir)) fs.mkdirSync(mintDir, { recursive: true });
33
- return path.join(mintDir, fileName);
34
+
35
+ // Migration Logic
36
+ if (!fs.existsSync(dbPath)) {
37
+ const electronDb = app && app.getPath ? path.join(app.getPath('userData'), fileName) : null;
38
+ const legacyDb = path.join(os.homedir(), '.mint', fileName);
39
+
40
+ if (electronDb && fs.existsSync(electronDb)) {
41
+ try {
42
+ fs.copyFileSync(electronDb, dbPath);
43
+ console.log('[Memory] Migrated database from Electron userData');
44
+ } catch (e) { console.error('[Memory] Migration from Electron failed:', e); }
45
+ } else if (fs.existsSync(legacyDb)) {
46
+ try {
47
+ fs.copyFileSync(legacyDb, dbPath);
48
+ console.log('[Memory] Migrated database from ~/.mint');
49
+ } catch (e) { console.error('[Memory] Migration from ~/.mint failed:', e); }
50
+ }
51
+ }
52
+
53
+ return dbPath;
34
54
  }
35
55
 
36
56
  // ── Lazy DatabaseSync init ─────────────────────────────────────────────────
@@ -45,6 +65,10 @@ function getDb() {
45
65
  if (dbInstance) return dbInstance;
46
66
  const Database = getDatabaseSync();
47
67
  dbInstance = new Database(getDbPath());
68
+
69
+ // Enable WAL mode for better concurrency
70
+ dbInstance.exec('PRAGMA journal_mode = WAL;');
71
+ dbInstance.exec('PRAGMA synchronous = NORMAL;');
48
72
 
49
73
  dbInstance.exec(`
50
74
  -- User profile: arbitrary key-value pairs
@@ -94,6 +118,19 @@ function setProfile(key, value) {
94
118
  }
95
119
  }
96
120
 
121
+ function deleteProfile(key) {
122
+ try {
123
+ getDb().prepare('DELETE FROM user_profile WHERE key = ?').run(key);
124
+ } catch (err) {
125
+ console.error('[Memory] deleteProfile error:', err.message);
126
+ }
127
+ }
128
+
129
+ function clearConversationScopedProfile() {
130
+ deleteProfile('preferred_language');
131
+ clearResponseCache();
132
+ }
133
+
97
134
  function getProfile(key, defaultValue = null) {
98
135
  try {
99
136
  const row = getDb().prepare('SELECT value FROM user_profile WHERE key = ?').get(key);
@@ -246,7 +283,7 @@ function getUserContext() {
246
283
  // Profile info
247
284
  if (Object.keys(profile).length > 0) {
248
285
  if (profile.preferred_language)
249
- lines.push(`• Preferred language: ${profile.preferred_language}`);
286
+ lines.push(`• Previously inferred language: ${profile.preferred_language} (do not override the current user message language)`);
250
287
  if (profile.last_active_project)
251
288
  lines.push(`• Last active project: ${profile.last_active_project} (${profile.last_active_project_path || ''})`);
252
289
  if (profile.total_interactions)
@@ -305,14 +342,25 @@ function cacheResponse(query, responseObj) {
305
342
  } catch (_) {}
306
343
  }
307
344
 
345
+ function clearResponseCache() {
346
+ try {
347
+ getDb().prepare('DELETE FROM response_cache').run();
348
+ } catch (err) {
349
+ console.error('[Memory] clearResponseCache error:', err.message);
350
+ }
351
+ }
352
+
308
353
  module.exports = {
309
354
  recordInteraction,
310
355
  saveSessionSummary,
311
356
  getUserContext,
312
357
  setProfile,
358
+ deleteProfile,
359
+ clearConversationScopedProfile,
313
360
  getProfile,
314
361
  getTopPatterns,
315
362
  getRecentMemories,
316
363
  getCachedResponse,
317
- cacheResponse
364
+ cacheResponse,
365
+ clearResponseCache
318
366
  };
@@ -226,7 +226,7 @@ async function openFile(target) {
226
226
  // ใช้ exec เพื่อให้รันผ่าน shell และรองรับการทำ fallback
227
227
  let cmd = `${platformCmd} "${resolvedPath}"`;
228
228
  if (process.platform === 'linux') {
229
- cmd = `xdg-open "${resolvedPath}" || gio open "${resolvedPath}" || nautilus "${resolvedPath}"`;
229
+ cmd = `xdg-open "${resolvedPath}" || gio open "${resolvedPath}" || nautilus "${resolvedPath}" || nemo "${resolvedPath}" || thunar "${resolvedPath}" || dolphin "${resolvedPath}"`;
230
230
  }
231
231
 
232
232
  exec(cmd, (err) => {
@@ -170,7 +170,7 @@ async function detectCodeIntent(text, workspaceRoot = process.cwd(), history = [
170
170
 
171
171
  async function runChatRoutedTask(input, context) {
172
172
  const text = input.startsWith('/code ') ? input.slice('/code '.length).trim() : input;
173
- const { appendMessage, setThinking, requestApproval, setMode, history } = context;
173
+ const { appendMessage, setThinking, requestApproval, askUser, setMode, history } = context;
174
174
 
175
175
  const config = readConfig();
176
176
  const availableProviders = getAvailableProviders(config);
@@ -190,6 +190,7 @@ async function runChatRoutedTask(input, context) {
190
190
  const result = await executeCodeTask(text, {
191
191
  cwd: process.cwd(),
192
192
  requestApproval,
193
+ askUser,
193
194
  provider: preferredProvider,
194
195
  history: history,
195
196
  onProgress: (info) => {
@@ -206,7 +207,7 @@ async function runChatRoutedTask(input, context) {
206
207
  `Code Mode finished.`,
207
208
  result.summary,
208
209
  `Verification: ${result.verification}`
209
- ].join('\n'));
210
+ ].join('\n'), { providerInfo: result.providerInfo });
210
211
  } catch (error) {
211
212
  clearInterval(timer);
212
213
  setThinking(false);