@pheem49/mint 1.5.5 → 1.6.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 (222) hide show
  1. package/.codex +0 -0
  2. package/.github/FUNDING.yml +2 -0
  3. package/.github/workflows/ci.yml +45 -0
  4. package/.github/workflows/release.yml +79 -0
  5. package/Cargo.lock +5792 -0
  6. package/Cargo.toml +32 -0
  7. package/README.md +387 -353
  8. package/assets/icon.png +0 -0
  9. package/bin/mint +0 -0
  10. package/crates/mint-cli/Cargo.toml +23 -0
  11. package/crates/mint-cli/src/agent.rs +851 -0
  12. package/crates/mint-cli/src/gmail.rs +216 -0
  13. package/crates/mint-cli/src/image.rs +142 -0
  14. package/crates/mint-cli/src/main.rs +2837 -0
  15. package/crates/mint-cli/src/mcp.rs +63 -0
  16. package/crates/mint-cli/src/onboard.rs +1149 -0
  17. package/crates/mint-cli/src/setup.rs +390 -0
  18. package/crates/mint-cli/src/skills.rs +8 -0
  19. package/crates/mint-cli/src/updater.rs +279 -0
  20. package/crates/mint-core/Cargo.toml +22 -0
  21. package/crates/mint-core/src/agent_loop.rs +94 -0
  22. package/crates/mint-core/src/api_server.rs +991 -0
  23. package/crates/mint-core/src/channels.rs +248 -0
  24. package/crates/mint-core/src/chat.rs +895 -0
  25. package/crates/mint-core/src/code_tools.rs +729 -0
  26. package/crates/mint-core/src/config.rs +368 -0
  27. package/crates/mint-core/src/files.rs +159 -0
  28. package/crates/mint-core/src/knowledge.rs +541 -0
  29. package/crates/mint-core/src/lib.rs +84 -0
  30. package/crates/mint-core/src/mcp.rs +273 -0
  31. package/crates/mint-core/src/memory.rs +673 -0
  32. package/crates/mint-core/src/orchestration.rs +2157 -0
  33. package/crates/mint-core/src/pictures.rs +314 -0
  34. package/crates/mint-core/src/plugins.rs +727 -0
  35. package/crates/mint-core/src/safety.rs +416 -0
  36. package/crates/mint-core/src/semantic.rs +254 -0
  37. package/crates/mint-core/src/shell.rs +317 -0
  38. package/crates/mint-core/src/skills.rs +71 -0
  39. package/crates/mint-core/src/symbols.rs +157 -0
  40. package/crates/mint-core/src/tasks.rs +308 -0
  41. package/crates/mint-core/src/tts.rs +92 -0
  42. package/crates/mint-core/src/weather.rs +93 -0
  43. package/crates/mint-core/src/web_search.rs +200 -0
  44. package/crates/mint-core/src/workflows.rs +81 -0
  45. package/crates/mint-core/tests/mcp_stdio.rs +45 -0
  46. package/crates/mint-core/tests/memory_persistence.rs +172 -0
  47. package/crates/mint-core/tests/pictures_storage.rs +14 -0
  48. package/crates/mint-core/tests/task_lifecycle.rs +87 -0
  49. package/package.json +35 -99
  50. package/src/bin/index.js +16 -0
  51. package/src/renderer/index-web.html +17 -0
  52. package/src/renderer/index.html +17 -0
  53. package/src/renderer/public/Live2DCubismCore.js +9 -0
  54. package/src/renderer/public/assets/icon.png +0 -0
  55. package/src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.model3.json +36 -0
  56. package/src/renderer/src/App.tsx +33 -0
  57. package/src/renderer/src/calculator.ts +47 -0
  58. package/src/renderer/src/components/ChatPanel.tsx +1598 -0
  59. package/src/renderer/src/components/DashboardSidebar.tsx +358 -0
  60. package/src/renderer/src/components/Live2DStage.tsx +374 -0
  61. package/src/renderer/src/components/MintDashboard.tsx +950 -0
  62. package/src/renderer/src/components/ModelPanel.tsx +154 -0
  63. package/src/renderer/src/components/PicturesLibrary.tsx +46 -0
  64. package/src/renderer/src/components/ProactiveGlow.tsx +19 -0
  65. package/src/renderer/src/components/ScreenPicker.tsx +579 -0
  66. package/src/renderer/src/components/SettingsWindow.tsx +1467 -0
  67. package/src/renderer/src/components/SpotlightWindow.tsx +280 -0
  68. package/src/renderer/src/components/WidgetWindow.tsx +36 -0
  69. package/src/renderer/src/components/WorkspacePanel.tsx +268 -0
  70. package/src/{UI → renderer/src/css}/settings.css +69 -16
  71. package/src/renderer/src/css/spotlight.css +113 -0
  72. package/src/renderer/src/css/styles.css +3722 -0
  73. package/src/renderer/src/css/widget.css +185 -0
  74. package/src/renderer/src/env.d.ts +116 -0
  75. package/src/renderer/src/index.css +379 -0
  76. package/src/renderer/src/main.tsx +13 -0
  77. package/src/renderer/src/tauri.ts +996 -0
  78. package/src/renderer/src-web/App.tsx +25 -0
  79. package/src/renderer/src-web/calculator.ts +47 -0
  80. package/src/renderer/src-web/components/ChatPanel.tsx +1662 -0
  81. package/src/renderer/src-web/components/DashboardSidebar.tsx +242 -0
  82. package/src/renderer/src-web/components/MintDashboard.tsx +763 -0
  83. package/src/renderer/src-web/components/PicturesLibrary.tsx +73 -0
  84. package/src/renderer/src-web/components/SettingsWindow.tsx +1500 -0
  85. package/src/renderer/src-web/css/settings.css +1100 -0
  86. package/src/{UI → renderer/src-web/css}/spotlight.css +4 -4
  87. package/src/{UI → renderer/src-web/css}/styles.css +1055 -159
  88. package/src/{UI → renderer/src-web/css}/widget.css +2 -2
  89. package/src/renderer/src-web/env.d.ts +107 -0
  90. package/src/renderer/src-web/index.css +379 -0
  91. package/src/renderer/src-web/main.tsx +13 -0
  92. package/src/renderer/src-web/tauri.ts +983 -0
  93. package/tsconfig.json +30 -0
  94. package/vite.config.ts +33 -0
  95. package/vite.config.web.ts +51 -0
  96. package/GUIDE_TH.md +0 -125
  97. package/assets/Agent_Mint.png +0 -0
  98. package/assets/CLI_Screen.png +0 -0
  99. package/assets/Settings.png +0 -0
  100. package/benchmark_ai.js +0 -71
  101. package/install.ps1 +0 -64
  102. package/install.sh +0 -54
  103. package/main.js +0 -139
  104. package/mint-cli-logic.js +0 -3
  105. package/mint-cli.js +0 -410
  106. package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.model3.json +0 -47
  107. package/models/Shiroko_Model/Shiroko//342/232/241/351/253/230/344/272/256/342/232/241/344/275/277/347/224/250/346/225/231/347/250/213/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.txt +0 -23
  108. package/preload-picker.js +0 -11
  109. package/preload-settings.js +0 -11
  110. package/preload.js +0 -41
  111. package/scripts/install_linux_desktop_entry.js +0 -48
  112. package/src/AI_Brain/Gemini_API.js +0 -813
  113. package/src/AI_Brain/agent_orchestrator.js +0 -73
  114. package/src/AI_Brain/autonomous_brain.js +0 -179
  115. package/src/AI_Brain/behavior_memory.js +0 -135
  116. package/src/AI_Brain/headless_agent.js +0 -143
  117. package/src/AI_Brain/knowledge_base.js +0 -349
  118. package/src/AI_Brain/memory_store.js +0 -662
  119. package/src/AI_Brain/proactive_engine.js +0 -172
  120. package/src/AI_Brain/provider_adapter.js +0 -365
  121. package/src/Automation_Layer/browser_automation.js +0 -149
  122. package/src/Automation_Layer/file_operations.js +0 -286
  123. package/src/Automation_Layer/open_app.js +0 -85
  124. package/src/Automation_Layer/open_website.js +0 -38
  125. package/src/CLI/approval_handler.js +0 -47
  126. package/src/CLI/chat_router.js +0 -247
  127. package/src/CLI/chat_ui.js +0 -1159
  128. package/src/CLI/cli_colors.js +0 -115
  129. package/src/CLI/cli_formatters.js +0 -94
  130. package/src/CLI/code_agent.js +0 -1667
  131. package/src/CLI/code_session_memory.js +0 -62
  132. package/src/CLI/gmail_auth.js +0 -210
  133. package/src/CLI/image_input.js +0 -90
  134. package/src/CLI/intent_detectors.js +0 -181
  135. package/src/CLI/interactive_chat.js +0 -658
  136. package/src/CLI/list_features.js +0 -64
  137. package/src/CLI/onboarding.js +0 -416
  138. package/src/CLI/repo_summarizer.js +0 -282
  139. package/src/CLI/semantic_code_search.js +0 -312
  140. package/src/CLI/skill_manager.js +0 -41
  141. package/src/CLI/slash_command_handler.js +0 -418
  142. package/src/CLI/symbol_indexer.js +0 -231
  143. package/src/CLI/updater.js +0 -230
  144. package/src/CLI/workspace_manager.js +0 -90
  145. package/src/Channels/brave_search_bridge.js +0 -35
  146. package/src/Channels/discord_bridge.js +0 -66
  147. package/src/Channels/google_search_bridge.js +0 -38
  148. package/src/Channels/line_bridge.js +0 -60
  149. package/src/Channels/slack_bridge.js +0 -48
  150. package/src/Channels/telegram_bridge.js +0 -41
  151. package/src/Channels/whatsapp_bridge.js +0 -57
  152. package/src/Command_Parser/parser.js +0 -45
  153. package/src/Plugins/dev_tools.js +0 -41
  154. package/src/Plugins/discord.js +0 -20
  155. package/src/Plugins/docker.js +0 -47
  156. package/src/Plugins/gmail.js +0 -251
  157. package/src/Plugins/google_calendar.js +0 -252
  158. package/src/Plugins/mcp_manager.js +0 -95
  159. package/src/Plugins/notion.js +0 -256
  160. package/src/Plugins/obsidian.js +0 -54
  161. package/src/Plugins/plugin_manager.js +0 -81
  162. package/src/Plugins/spotify.js +0 -173
  163. package/src/Plugins/system_metrics.js +0 -31
  164. package/src/Plugins/system_monitor.js +0 -72
  165. package/src/System/action_executor.js +0 -178
  166. package/src/System/bridge_manager.js +0 -76
  167. package/src/System/chat_history_manager.js +0 -83
  168. package/src/System/config_manager.js +0 -194
  169. package/src/System/custom_workflows.js +0 -163
  170. package/src/System/daemon_manager.js +0 -67
  171. package/src/System/google_tts_urls.js +0 -51
  172. package/src/System/granular_automation.js +0 -157
  173. package/src/System/ipc_handlers.js +0 -332
  174. package/src/System/notifications.js +0 -23
  175. package/src/System/optional_require.js +0 -23
  176. package/src/System/picture_store.js +0 -109
  177. package/src/System/proactive_loop.js +0 -153
  178. package/src/System/safety_manager.js +0 -273
  179. package/src/System/sandbox_runner.js +0 -182
  180. package/src/System/screen_capture.js +0 -175
  181. package/src/System/smart_context.js +0 -227
  182. package/src/System/system_automation.js +0 -162
  183. package/src/System/system_events.js +0 -79
  184. package/src/System/system_info.js +0 -125
  185. package/src/System/task_manager.js +0 -222
  186. package/src/System/tool_registry.js +0 -293
  187. package/src/System/window_manager.js +0 -220
  188. package/src/UI/floating.css +0 -80
  189. package/src/UI/floating.html +0 -17
  190. package/src/UI/floating.js +0 -67
  191. package/src/UI/live2d_manager.js +0 -600
  192. package/src/UI/preload-floating.js +0 -7
  193. package/src/UI/preload-spotlight.js +0 -11
  194. package/src/UI/preload-widget.js +0 -5
  195. package/src/UI/proactive-glow.html +0 -42
  196. package/src/UI/renderer.js +0 -2127
  197. package/src/UI/screenPicker.html +0 -214
  198. package/src/UI/screenPicker.js +0 -262
  199. package/src/UI/settings.html +0 -577
  200. package/src/UI/settings.js +0 -770
  201. package/src/UI/spotlight.html +0 -23
  202. package/src/UI/spotlight.js +0 -185
  203. package/src/UI/widget.html +0 -29
  204. package/src/UI/widget.js +0 -10
  205. /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/72d86db84cfa9730b894c241fd24c0db.png +0 -0
  206. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/233/264/350/243/231.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/apron.exp3.json} +0 -0
  207. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/214/253/345/222/252/346/273/244/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/catfilter.exp3.json} +0 -0
  208. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/click.exp3.json} +0 -0
  209. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazed.exp3.json} +0 -0
  210. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253/347/234/274/347/217/240/346/221/207/346/231/203.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazedeyes.exp3.json} +0 -0
  211. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/234/274/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/glasses.exp3.json} +0 -0
  212. /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/items_pinned_to_model.json +0 -0
  213. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/277/347/254/224.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/pen.exp3.json} +0 -0
  214. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/215/347/205/247.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/photo.exp3.json} +0 -0
  215. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_00.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_00.png} +0 -0
  216. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_01.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_01.png} +0 -0
  217. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_02.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_02.png} +0 -0
  218. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_03.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_03.png} +0 -0
  219. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.cdi3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.cdi3.json} +0 -0
  220. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.moc3" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.moc3} +0 -0
  221. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.physics3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.physics3.json} +0 -0
  222. /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.vtube.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.vtube.json} +0 -0
@@ -0,0 +1,81 @@
1
+ use std::{fs, path::PathBuf};
2
+
3
+ use serde_json::{Value, json};
4
+ use thiserror::Error;
5
+
6
+ use crate::{ConfigError, config_path};
7
+
8
+ #[derive(Debug, Error)]
9
+ pub enum WorkflowError {
10
+ #[error(transparent)]
11
+ Config(#[from] ConfigError),
12
+ #[error("workflow directory is unavailable")]
13
+ MissingDirectory,
14
+ #[error("unable to create workflow directory: {0}")]
15
+ CreateDirectory(std::io::Error),
16
+ #[error("unable to read {path}: {source}")]
17
+ Read {
18
+ path: PathBuf,
19
+ source: std::io::Error,
20
+ },
21
+ #[error("unable to parse {path}: {source}")]
22
+ Parse {
23
+ path: PathBuf,
24
+ source: serde_json::Error,
25
+ },
26
+ #[error("unable to serialize workflows: {0}")]
27
+ Serialize(serde_json::Error),
28
+ #[error("unable to write {path}: {source}")]
29
+ Write {
30
+ path: PathBuf,
31
+ source: std::io::Error,
32
+ },
33
+ }
34
+
35
+ pub fn workflows_path() -> Result<PathBuf, WorkflowError> {
36
+ Ok(config_path()?.with_file_name("workflows.json"))
37
+ }
38
+
39
+ pub fn load_workflows() -> Result<Vec<Value>, WorkflowError> {
40
+ let path = workflows_path()?;
41
+ if !path.exists() {
42
+ save_default_workflows(&path)?;
43
+ }
44
+ let raw = fs::read_to_string(&path).map_err(|source| WorkflowError::Read {
45
+ path: path.clone(),
46
+ source,
47
+ })?;
48
+ serde_json::from_str(&raw).map_err(|source| WorkflowError::Parse { path, source })
49
+ }
50
+
51
+ fn save_default_workflows(path: &PathBuf) -> Result<(), WorkflowError> {
52
+ let directory = path.parent().ok_or(WorkflowError::MissingDirectory)?;
53
+ fs::create_dir_all(directory).map_err(WorkflowError::CreateDirectory)?;
54
+ let workflows = json!([
55
+ {
56
+ "id": "wf-1",
57
+ "name": "Check Mic on Zoom",
58
+ "trigger": { "type": "process_running", "processName": "zoom" },
59
+ "action": {
60
+ "type": "system_info",
61
+ "message": "Looks like you opened Zoom. Should I check your system resources?",
62
+ "target": ""
63
+ }
64
+ },
65
+ {
66
+ "id": "wf-2",
67
+ "name": "Coding Time",
68
+ "trigger": { "type": "process_running", "processName": "code" },
69
+ "action": {
70
+ "type": "open_app",
71
+ "message": "Coding time. Want me to open Spotify?",
72
+ "target": "spotify"
73
+ }
74
+ }
75
+ ]);
76
+ let raw = serde_json::to_string_pretty(&workflows).map_err(WorkflowError::Serialize)?;
77
+ fs::write(path, format!("{raw}\n")).map_err(|source| WorkflowError::Write {
78
+ path: path.clone(),
79
+ source,
80
+ })
81
+ }
@@ -0,0 +1,45 @@
1
+ use mint_core::{MintConfig, call_mcp_tool, configured_mcp_servers};
2
+ use serde_json::json;
3
+
4
+ #[test]
5
+ fn reads_servers_from_config() {
6
+ let mut config = MintConfig::default();
7
+ config.extra.insert(
8
+ "mcpServers".into(),
9
+ json!({
10
+ "echo": {
11
+ "command": "echo",
12
+ "args": ["ok"],
13
+ "env": { "TOKEN": "value" }
14
+ }
15
+ }),
16
+ );
17
+ let servers = configured_mcp_servers(&config).unwrap();
18
+ assert_eq!(servers["echo"].command, "echo");
19
+ assert_eq!(servers["echo"].env["TOKEN"], "value");
20
+ }
21
+
22
+ #[cfg(unix)]
23
+ #[test]
24
+ fn calls_stdio_mcp_tool() {
25
+ let mut config = MintConfig::default();
26
+ config.extra.insert(
27
+ "mcpServers".into(),
28
+ json!({
29
+ "fake": {
30
+ "command": "sh",
31
+ "args": [
32
+ "-c",
33
+ "read init; read ready; read call; printf '{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":{\"ok\":true}}\\n'"
34
+ ]
35
+ }
36
+ }),
37
+ );
38
+ config
39
+ .extra
40
+ .insert("allowedMcpTools".into(), json!({ "fake": ["ping"] }));
41
+ assert_eq!(
42
+ call_mcp_tool(&config, "fake", "ping", json!({})).unwrap(),
43
+ json!({ "ok": true })
44
+ );
45
+ }
@@ -0,0 +1,172 @@
1
+ use std::{
2
+ path::PathBuf,
3
+ time::{SystemTime, UNIX_EPOCH},
4
+ };
5
+
6
+ use mint_core::{CHAT_CLI_ID, DEFAULT_CONVERSATION_ID, MemoryStore};
7
+
8
+ fn store(name: &str) -> MemoryStore {
9
+ let path = test_path(name, "sqlite");
10
+ let _ = std::fs::remove_file(&path);
11
+ MemoryStore::open(path)
12
+ }
13
+
14
+ fn test_path(name: &str, extension: &str) -> PathBuf {
15
+ let nanos = SystemTime::now()
16
+ .duration_since(UNIX_EPOCH)
17
+ .unwrap_or_default()
18
+ .as_nanos();
19
+ std::env::temp_dir().join(format!(
20
+ "mint-core-integration-{name}-{}-{nanos}.{extension}",
21
+ std::process::id(),
22
+ ))
23
+ }
24
+
25
+ #[test]
26
+ fn stores_and_reads_profile_values() {
27
+ let store = store("profile");
28
+ store.set_profile("name", "Mint").unwrap();
29
+ assert_eq!(store.get_profile("name").unwrap().as_deref(), Some("Mint"));
30
+ }
31
+
32
+ #[test]
33
+ fn stores_recent_interactions_with_provider_metadata() {
34
+ let store = store("interactions");
35
+ store
36
+ .add_interaction_with_metadata("hello", "hi", "gemini", "gemini-test")
37
+ .unwrap();
38
+ store
39
+ .add_interaction_for_chat_with_fallback(
40
+ "",
41
+ "question",
42
+ "answer",
43
+ "gemini",
44
+ "gemini-test",
45
+ Some("ollama"),
46
+ )
47
+ .unwrap();
48
+
49
+ let interactions = store.recent_interactions(2).unwrap();
50
+ assert_eq!(interactions[0].user_text, "question");
51
+ assert_eq!(interactions[0].ai_text, "answer");
52
+ assert_eq!(interactions[0].provider, "gemini");
53
+ assert_eq!(interactions[0].model, "gemini-test");
54
+ assert_eq!(interactions[0].fallback_provider, Some("ollama".to_owned()));
55
+
56
+ assert_eq!(interactions[1].user_text, "hello");
57
+ assert_eq!(interactions[1].fallback_provider, None);
58
+ }
59
+
60
+ #[test]
61
+ fn preserves_chat_history_when_store_is_reopened() {
62
+ let path = test_path("reopen-history", "sqlite");
63
+ let _ = std::fs::remove_file(&path);
64
+ let first = MemoryStore::open(&path);
65
+ first
66
+ .add_interaction_with_metadata("persist me", "still here", "openai", "gpt-test")
67
+ .unwrap();
68
+ drop(first);
69
+ let interactions = MemoryStore::open(&path).recent_interactions(10).unwrap();
70
+ assert_eq!(interactions[0].user_text, "persist me");
71
+ assert_eq!(interactions[0].provider, "openai");
72
+ let _ = std::fs::remove_file(path);
73
+ }
74
+
75
+ #[test]
76
+ fn clears_interactions() {
77
+ let store = store("clear-interactions");
78
+ store.add_interaction("hello", "hi").unwrap();
79
+ assert_eq!(store.clear_interactions().unwrap(), 1);
80
+ assert!(store.recent_interactions(10).unwrap().is_empty());
81
+ }
82
+
83
+ #[test]
84
+ fn keeps_cli_history_separate_from_conversation_history() {
85
+ let store = store("chat-session-split");
86
+ store
87
+ .add_interaction_for_chat(CHAT_CLI_ID, "cli question", "cli answer", "openai", "gpt")
88
+ .unwrap();
89
+ store
90
+ .add_interaction_for_chat(
91
+ "conversation-test",
92
+ "app question",
93
+ "app answer",
94
+ "gemini",
95
+ "gemini-test",
96
+ )
97
+ .unwrap();
98
+
99
+ let cli = store.recent_interactions_for_chat(CHAT_CLI_ID, 10).unwrap();
100
+ let app = store
101
+ .recent_interactions_for_chat("conversation-test", 10)
102
+ .unwrap();
103
+
104
+ assert_eq!(cli.len(), 1);
105
+ assert_eq!(cli[0].chat_id, CHAT_CLI_ID);
106
+ assert_eq!(cli[0].user_text, "cli question");
107
+ assert_eq!(app.len(), 1);
108
+ assert_eq!(app[0].chat_id, "conversation-test");
109
+ assert_eq!(app[0].user_text, "app question");
110
+ }
111
+
112
+ #[test]
113
+ fn legacy_recent_interactions_use_default_conversation() {
114
+ let store = store("default-conversation");
115
+ store
116
+ .add_interaction_with_metadata("default question", "default answer", "gemini", "test")
117
+ .unwrap();
118
+ store
119
+ .add_interaction_for_chat(CHAT_CLI_ID, "cli question", "cli answer", "openai", "test")
120
+ .unwrap();
121
+
122
+ let default_items = store.recent_interactions(10).unwrap();
123
+ assert_eq!(default_items.len(), 1);
124
+ assert_eq!(default_items[0].chat_id, DEFAULT_CONVERSATION_ID);
125
+ assert_eq!(default_items[0].user_text, "default question");
126
+ }
127
+
128
+ #[test]
129
+ fn deletes_conversation_without_deleting_cli_session() {
130
+ let store = store("delete-conversation");
131
+ store
132
+ .add_interaction_for_chat("conversation-delete", "remove me", "ok", "gemini", "test")
133
+ .unwrap();
134
+ store
135
+ .add_interaction_for_chat(CHAT_CLI_ID, "keep me", "ok", "openai", "test")
136
+ .unwrap();
137
+
138
+ assert_eq!(store.delete_chat_session("conversation-delete").unwrap(), 1);
139
+ assert!(
140
+ store
141
+ .recent_interactions_for_chat("conversation-delete", 10)
142
+ .unwrap()
143
+ .is_empty()
144
+ );
145
+ assert_eq!(
146
+ store.recent_interactions_for_chat(CHAT_CLI_ID, 10).unwrap()[0].user_text,
147
+ "keep me"
148
+ );
149
+ assert_eq!(store.delete_chat_session(CHAT_CLI_ID).unwrap(), 0);
150
+ }
151
+
152
+ #[test]
153
+ fn stores_workspace_session_summary() {
154
+ let store = store("workspace-session");
155
+ store
156
+ .save_workspace_session("/tmp/project", "implemented", "cargo test")
157
+ .unwrap();
158
+ let session = store.workspace_session("/tmp/project").unwrap().unwrap();
159
+ assert_eq!(session.summary, "implemented");
160
+ assert_eq!(session.verification, "cargo test");
161
+ }
162
+
163
+ #[test]
164
+ fn stores_lists_and_deletes_learned_skills() {
165
+ let store = store("skills");
166
+ store
167
+ .add_learned_skill("guide", "/tmp/guide.md", "Use focused patches.")
168
+ .unwrap();
169
+ assert_eq!(store.learned_skills(10).unwrap()[0].name, "guide");
170
+ assert_eq!(store.delete_learned_skill("guide").unwrap(), 1);
171
+ assert!(store.learned_skills(10).unwrap().is_empty());
172
+ }
@@ -0,0 +1,14 @@
1
+ use mint_core::parse_data_uri;
2
+
3
+ #[test]
4
+ fn parses_supported_image_data_uri() {
5
+ let parsed = parse_data_uri("data:image/png;base64,aGk=").unwrap();
6
+ assert_eq!(parsed.0, "image/png");
7
+ assert_eq!(parsed.1, "png");
8
+ assert_eq!(parsed.2, b"hi");
9
+ }
10
+
11
+ #[test]
12
+ fn rejects_unsupported_picture_data_uri() {
13
+ assert!(parse_data_uri("data:image/bmp;base64,aGk=").is_none());
14
+ }
@@ -0,0 +1,87 @@
1
+ use std::path::PathBuf;
2
+
3
+ use mint_core::TaskStore;
4
+
5
+ fn test_path(name: &str) -> PathBuf {
6
+ std::env::temp_dir().join(format!(
7
+ "mint-task-integration-{name}-{}.json",
8
+ std::process::id()
9
+ ))
10
+ }
11
+
12
+ #[test]
13
+ fn adds_and_reads_task() {
14
+ let path = test_path("add");
15
+ let _ = std::fs::remove_file(&path);
16
+ let store = TaskStore::open(&path);
17
+ let task = store.add("migrate backend").unwrap();
18
+ assert_eq!(
19
+ store.get(&task.id).unwrap().unwrap().description,
20
+ "migrate backend"
21
+ );
22
+ let _ = std::fs::remove_file(path);
23
+ }
24
+
25
+ #[test]
26
+ fn retries_failed_tasks_once_before_marking_them_failed() {
27
+ let path = test_path("retry");
28
+ let _ = std::fs::remove_file(&path);
29
+ let store = TaskStore::open(&path);
30
+ let task = store.add("retry task").unwrap();
31
+ assert_eq!(
32
+ store
33
+ .fail_with_retry(&task.id, "first")
34
+ .unwrap()
35
+ .unwrap()
36
+ .status,
37
+ "pending"
38
+ );
39
+ assert_eq!(
40
+ store
41
+ .fail_with_retry(&task.id, "second")
42
+ .unwrap()
43
+ .unwrap()
44
+ .status,
45
+ "failed"
46
+ );
47
+ let _ = std::fs::remove_file(path);
48
+ }
49
+
50
+ #[test]
51
+ fn resumes_interrupted_running_tasks() {
52
+ let path = test_path("resume");
53
+ let _ = std::fs::remove_file(&path);
54
+ let store = TaskStore::open(&path);
55
+ let task = store.add("resume task").unwrap();
56
+ store.update_status(&task.id, "running", None).unwrap();
57
+ assert_eq!(store.resume_running().unwrap()[0].status, "pending");
58
+ let _ = std::fs::remove_file(path);
59
+ }
60
+
61
+ #[test]
62
+ fn records_headless_task_lifecycle() {
63
+ let path = test_path("lifecycle");
64
+ let _ = std::fs::remove_file(&path);
65
+ let store = TaskStore::open(&path);
66
+ let task = store.add("background audit").unwrap();
67
+ store.update_status(&task.id, "running", None).unwrap();
68
+ store
69
+ .add_checkpoint(&task.id, serde_json::json!({ "phase": "started" }))
70
+ .unwrap();
71
+ store
72
+ .add_artifact(&task.id, serde_json::json!({ "type": "proposal" }))
73
+ .unwrap();
74
+ let completed = store
75
+ .update_status(
76
+ &task.id,
77
+ "completed",
78
+ Some(serde_json::json!({ "summary": "done" })),
79
+ )
80
+ .unwrap()
81
+ .unwrap();
82
+ assert_eq!(completed.status, "completed");
83
+ assert_eq!(completed.checkpoints.len(), 1);
84
+ assert_eq!(completed.artifacts.len(), 1);
85
+ assert_eq!(completed.result.unwrap()["summary"], "done");
86
+ let _ = std::fs::remove_file(path);
87
+ }
package/package.json CHANGED
@@ -1,32 +1,31 @@
1
1
  {
2
2
  "name": "@pheem49/mint",
3
- "version": "1.5.5",
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",
3
+ "version": "1.6.1",
4
+ "description": "A native Tauri desktop AI assistant with a Rust backend and React UI.",
6
5
  "scripts": {
7
- "start": "electron .",
8
- "test": "jest --testPathPatterns=tests/",
9
- "test:watch": "jest --testPathPatterns=tests/ --watch",
10
- "build:linux": "electron-builder --linux",
11
- "build:mac": "electron-builder --mac",
12
- "build:win": "electron-builder --win",
13
- "build:all": "electron-builder --linux --mac --win",
14
- "cli": "node mint-cli.js",
15
- "install:desktop": "node scripts/install_linux_desktop_entry.js"
16
- },
17
- "jest": {
18
- "testEnvironment": "node",
19
- "testMatch": [
20
- "**/tests/**/*.test.js"
21
- ],
22
- "collectCoverageFrom": [
23
- "src/AI_Brain/memory_store.js",
24
- "src/AI_Brain/knowledge_base.js",
25
- "src/System/config_manager.js"
26
- ]
27
- },
28
- "bin": {
29
- "mint": "mint-cli.js"
6
+ "dev:web": "vite --config vite.config.web.ts",
7
+ "web": "cargo run -p mint-cli -- web",
8
+ "typecheck": "tsc --noEmit",
9
+ "build:web": "vite build --config vite.config.web.ts",
10
+ "dev:desktop": "vite",
11
+ "build:desktop:ui": "vite build",
12
+ "build:desktop": "tauri build --no-bundle",
13
+ "build:desktop:bundle": "tauri build && mkdir -p target/release/mint-desktop-portable && cp target/release/mint-desktop target/release/mint-desktop-portable/mint-desktop && mkdir -p target/release/bundle/tar && tar -czf target/release/bundle/tar/mint-agent.tar.gz -C target/release mint-desktop-portable && rm -rf target/release/mint-desktop-portable && mv target/release/bundle/deb/Mint_*_amd64.deb target/release/bundle/deb/mint-agent_amd64.deb",
14
+ "build:cli": "cargo build -p mint-cli --release",
15
+ "build:all": "npm run build:web && npm run build:desktop && npm run build:cli",
16
+ "tauri": "tauri",
17
+ "tauri:dev": "tauri dev",
18
+ "tauri:build": "tauri build && mkdir -p target/release/mint-desktop-portable && cp target/release/mint-desktop target/release/mint-desktop-portable/mint-desktop && mkdir -p target/release/bundle/tar && tar -czf target/release/bundle/tar/mint-agent.tar.gz -C target/release mint-desktop-portable && rm -rf target/release/mint-desktop-portable && mv target/release/bundle/deb/Mint_*_amd64.deb target/release/bundle/deb/mint-agent_amd64.deb",
19
+ "package": "tauri build && mkdir -p target/release/mint-desktop-portable && cp target/release/mint-desktop target/release/mint-desktop-portable/mint-desktop && mkdir -p target/release/bundle/tar && tar -czf target/release/bundle/tar/mint-agent.tar.gz -C target/release mint-desktop-portable && rm -rf target/release/mint-desktop-portable && mv target/release/bundle/deb/Mint_*_amd64.deb target/release/bundle/deb/mint-agent_amd64.deb",
20
+ "rust:cli": "cargo run -p mint-cli --",
21
+ "rust:test": "cargo test -p mint-core -p mint-cli",
22
+ "dev": "tauri dev",
23
+ "build": "npm run build:desktop:ui",
24
+ "preview": "vite preview",
25
+ "start": "tauri dev",
26
+ "test": "cargo test -p mint-core -p mint-cli",
27
+ "cli": "cargo run -p mint-cli --",
28
+ "postinstall": "cargo build -p mint-cli --release && mkdir -p bin && cp target/release/mint bin/mint"
30
29
  },
31
30
  "keywords": [],
32
31
  "author": {
@@ -35,87 +34,24 @@
35
34
  },
36
35
  "license": "AGPL-3.0-only",
37
36
  "type": "commonjs",
38
- "dependencies": {
39
- "@google/genai": "^1.44.0",
40
- "@inkjs/ui": "^2.0.0",
41
- "axios": "^1.13.6",
42
- "cheerio": "^1.2.0",
43
- "commander": "^14.0.3",
44
- "dotenv": "^17.3.1",
45
- "ink": "^7.0.1",
46
- "ink-text-input": "^6.0.0",
47
- "mammoth": "^1.12.0",
48
- "pdf-parse": "^2.4.5",
49
- "react": "^19.2.5",
50
- "read-excel-file": "^9.0.10",
51
- "zod": "^4.4.3"
52
- },
53
- "peerDependenciesOptional": {
54
- "puppeteer": ">=22.0.0",
55
- "whatsapp-web.js": ">=1.0.0",
56
- "qrcode-terminal": ">=0.12.0",
57
- "discord.js": ">=14.0.0",
58
- "@slack/bolt": ">=4.0.0",
59
- "telegraf": ">=4.0.0",
60
- "@line/bot-sdk": ">=11.0.0",
61
- "express": ">=4.0.0"
37
+ "bin": {
38
+ "mint": "src/bin/index.js"
62
39
  },
63
- "devDependencies": {
64
- "@hazart-pkg/live2d-core": "^1.0.1",
40
+ "dependencies": {
41
+ "@tauri-apps/api": "^2.0.0",
65
42
  "@vitejs/plugin-react": "^6.0.1",
66
- "electron": "^40.7.0",
67
- "electron-builder": "^26.8.1",
68
- "framer-motion": "^12.38.0",
69
- "jest": "^30.4.0",
70
- "lucide-react": "^1.9.0",
43
+ "material-icon-theme": "^5.35.0",
71
44
  "pixi-live2d-display": "^0.4.0",
72
45
  "pixi.js": "^6.5.10",
46
+ "react": "^19.2.5",
73
47
  "react-dom": "^19.2.5",
48
+ "typescript": "^6.0.3",
74
49
  "vite": "^8.0.10"
75
50
  },
51
+ "devDependencies": {
52
+ "@tauri-apps/cli": "^2.0.0"
53
+ },
76
54
  "overrides": {
77
55
  "gh-pages": "^5.0.0"
78
- },
79
- "build": {
80
- "appId": "com.pheem49.mint",
81
- "productName": "Mint",
82
- "executableName": "mint-ai",
83
- "artifactName": "${productName}-${version}-${arch}.${ext}",
84
- "files": [
85
- "**/*",
86
- "!node_modules/.cache/**"
87
- ],
88
- "linux": {
89
- "icon": "assets/icon.png",
90
- "executableName": "mint-ai",
91
- "target": [
92
- "tar.gz",
93
- "deb"
94
- ],
95
- "category": "Utility"
96
- },
97
- "mac": {
98
- "icon": "assets/icon.png",
99
- "target": [
100
- "dmg",
101
- "zip"
102
- ],
103
- "category": "public.app-category.productivity"
104
- },
105
- "win": {
106
- "icon": "assets/icon.png",
107
- "target": [
108
- "nsis",
109
- "portable"
110
- ]
111
- },
112
- "nsis": {
113
- "oneClick": false,
114
- "allowToChangeInstallationDirectory": true
115
- },
116
- "deb": {
117
- "packageName": "mint-ai",
118
- "artifactName": "mint-ai_${version}_${arch}.${ext}"
119
- }
120
56
  }
121
57
  }
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+
6
+ // ชี้ไปยังไฟล์ Rust Binary ที่คอมไพล์สำเร็จแล้วในเครื่องผู้ใช้
7
+ const binaryPath = path.join(__dirname, '..', '..', 'bin', 'mint');
8
+
9
+ // สั่งทำงานไฟล์ Binary โดยส่งอาร์กิวเมนต์ทั้งหมดต่อเข้าไป
10
+ const child = spawn(binaryPath, process.argv.slice(2), {
11
+ stdio: 'inherit'
12
+ });
13
+
14
+ child.on('close', (code) => {
15
+ process.exit(code);
16
+ });
@@ -0,0 +1,17 @@
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>Agent Mint (Web)</title>
7
+ <link rel="icon" type="image/png" href="./assets/icon.png">
8
+ <!-- Load font families used in settings -->
9
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600&family=Mali:wght@400;500;600&family=Prompt:wght@400;500&family=Sarabun:wght@400;500&display=swap" rel="stylesheet">
10
+ <!-- Cubism must be available before the Live2D module is imported. -->
11
+ <script src="./Live2DCubismCore.js"></script>
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ <script type="module" src="./src-web/main.tsx"></script>
16
+ </body>
17
+ </html>
@@ -0,0 +1,17 @@
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>Agent Mint</title>
7
+ <link rel="icon" type="image/png" href="./assets/icon.png">
8
+ <!-- Load font families used in settings -->
9
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600&family=Mali:wght@400;500;600&family=Prompt:wght@400;500&family=Sarabun:wght@400;500&display=swap" rel="stylesheet">
10
+ <!-- Cubism must be available before the Live2D module is imported. -->
11
+ <script src="./Live2DCubismCore.js"></script>
12
+ </head>
13
+ <body>
14
+ <div id="root"></div>
15
+ <script type="module" src="./src/main.tsx"></script>
16
+ </body>
17
+ </html>