@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,390 @@
1
+ use anyhow::Result;
2
+ use crossterm::event::{self, Event, KeyCode};
3
+ use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
4
+ use mint_core::{load_config, save_config};
5
+ use std::io::{self, Write};
6
+
7
+ struct ToolOption {
8
+ name: &'static str,
9
+ key: &'static str,
10
+ enabled: bool,
11
+ }
12
+
13
+ pub async fn run() -> Result<Option<String>> {
14
+ let mut config = load_config()?;
15
+
16
+ println!("\x1b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m");
17
+ println!("\x1b[32m Mint CLI Tool Manager Wizard\x1b[0m");
18
+ println!("\x1b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m");
19
+ println!("Configure which agent tools are enabled or disabled:");
20
+ println!(
21
+ " \x1b[90m[Keyboard Controls: ↑/↓: Navigate | Space: Toggle | a: All | i: Invert | Enter: Confirm]\x1b[0m"
22
+ );
23
+ println!();
24
+
25
+ let mut options = vec![
26
+ ToolOption {
27
+ name: "list_files (List Workspace Files)",
28
+ key: "list_files",
29
+ enabled: !config.disabled_tools.contains(&"list_files".to_string()),
30
+ },
31
+ ToolOption {
32
+ name: "read_file (Read File Content)",
33
+ key: "read_file",
34
+ enabled: !config.disabled_tools.contains(&"read_file".to_string()),
35
+ },
36
+ ToolOption {
37
+ name: "search_code (Search Code Text)",
38
+ key: "search_code",
39
+ enabled: !config.disabled_tools.contains(&"search_code".to_string()),
40
+ },
41
+ ToolOption {
42
+ name: "symbols (Index/Search Symbols)",
43
+ key: "symbols",
44
+ enabled: !config.disabled_tools.contains(&"symbols".to_string()),
45
+ },
46
+ ToolOption {
47
+ name: "semantic_index (Semantic Indexing)",
48
+ key: "semantic_index",
49
+ enabled: !config
50
+ .disabled_tools
51
+ .contains(&"semantic_index".to_string()),
52
+ },
53
+ ToolOption {
54
+ name: "semantic_search (Semantic Search)",
55
+ key: "semantic_search",
56
+ enabled: !config
57
+ .disabled_tools
58
+ .contains(&"semantic_search".to_string()),
59
+ },
60
+ ToolOption {
61
+ name: "knowledge_search (Search Local Knowledge)",
62
+ key: "knowledge_search",
63
+ enabled: !config
64
+ .disabled_tools
65
+ .contains(&"knowledge_search".to_string()),
66
+ },
67
+ ToolOption {
68
+ name: "web_search (Search Web)",
69
+ key: "web_search",
70
+ enabled: !config.disabled_tools.contains(&"web_search".to_string()),
71
+ },
72
+ ToolOption {
73
+ name: "memory_recall (Recall Long-term Memory)",
74
+ key: "memory_recall",
75
+ enabled: !config.disabled_tools.contains(&"memory_recall".to_string()),
76
+ },
77
+ ToolOption {
78
+ name: "git_status (Read Git Status)",
79
+ key: "git_status",
80
+ enabled: !config.disabled_tools.contains(&"git_status".to_string()),
81
+ },
82
+ ToolOption {
83
+ name: "git_diff (Read Git Diff)",
84
+ key: "git_diff",
85
+ enabled: !config.disabled_tools.contains(&"git_diff".to_string()),
86
+ },
87
+ ToolOption {
88
+ name: "git_log (Read Git Log)",
89
+ key: "git_log",
90
+ enabled: !config.disabled_tools.contains(&"git_log".to_string()),
91
+ },
92
+ ToolOption {
93
+ name: "git_branch (Read Git Branch)",
94
+ key: "git_branch",
95
+ enabled: !config.disabled_tools.contains(&"git_branch".to_string()),
96
+ },
97
+ ToolOption {
98
+ name: "create_plan (Create Task Plan)",
99
+ key: "create_plan",
100
+ enabled: !config.disabled_tools.contains(&"create_plan".to_string()),
101
+ },
102
+ ToolOption {
103
+ name: "update_plan (Update Task Plan)",
104
+ key: "update_plan",
105
+ enabled: !config.disabled_tools.contains(&"update_plan".to_string()),
106
+ },
107
+ ToolOption {
108
+ name: "request_user_approval (Request User Approval)",
109
+ key: "request_user_approval",
110
+ enabled: !config
111
+ .disabled_tools
112
+ .contains(&"request_user_approval".to_string()),
113
+ },
114
+ ToolOption {
115
+ name: "ask_user (Ask User)",
116
+ key: "ask_user",
117
+ enabled: !config.disabled_tools.contains(&"ask_user".to_string()),
118
+ },
119
+ ToolOption {
120
+ name: "detect_project (Detect Project Type)",
121
+ key: "detect_project",
122
+ enabled: !config
123
+ .disabled_tools
124
+ .contains(&"detect_project".to_string()),
125
+ },
126
+ ToolOption {
127
+ name: "list_tests (List Tests)",
128
+ key: "list_tests",
129
+ enabled: !config.disabled_tools.contains(&"list_tests".to_string()),
130
+ },
131
+ ToolOption {
132
+ name: "read_diagnostics (Read Diagnostics)",
133
+ key: "read_diagnostics",
134
+ enabled: !config
135
+ .disabled_tools
136
+ .contains(&"read_diagnostics".to_string()),
137
+ },
138
+ ToolOption {
139
+ name: "view_image (View Image)",
140
+ key: "view_image",
141
+ enabled: !config.disabled_tools.contains(&"view_image".to_string()),
142
+ },
143
+ ToolOption {
144
+ name: "note_write (Write Notes)",
145
+ key: "note_write",
146
+ enabled: !config.disabled_tools.contains(&"note_write".to_string()),
147
+ },
148
+ ToolOption {
149
+ name: "run_plugin (Run Native Plugins)",
150
+ key: "run_plugin",
151
+ enabled: !config.disabled_tools.contains(&"run_plugin".to_string()),
152
+ },
153
+ ToolOption {
154
+ name: "mcp_tool (Call MCP Tools)",
155
+ key: "mcp_tool",
156
+ enabled: !config.disabled_tools.contains(&"mcp_tool".to_string()),
157
+ },
158
+ ToolOption {
159
+ name: "run_shell (Run Shell Commands)",
160
+ key: "run_shell",
161
+ enabled: !config.disabled_tools.contains(&"run_shell".to_string()),
162
+ },
163
+ ToolOption {
164
+ name: "verify (Run Verification Checks)",
165
+ key: "verify",
166
+ enabled: !config.disabled_tools.contains(&"verify".to_string()),
167
+ },
168
+ ToolOption {
169
+ name: "apply_patch (Patch Files)",
170
+ key: "apply_patch",
171
+ enabled: !config.disabled_tools.contains(&"apply_patch".to_string()),
172
+ },
173
+ ToolOption {
174
+ name: "write_file (Write Files)",
175
+ key: "write_file",
176
+ enabled: !config.disabled_tools.contains(&"write_file".to_string()),
177
+ },
178
+ ];
179
+
180
+ let mut cursor = 0;
181
+ print_options(&options, cursor);
182
+ enable_raw_mode()?;
183
+
184
+ loop {
185
+ match event::poll(std::time::Duration::from_millis(100)) {
186
+ Ok(true) => {
187
+ if let Event::Key(key_event) = event::read()? {
188
+ if key_event.kind == event::KeyEventKind::Press {
189
+ let is_ctrl_c = matches!(key_event.code, KeyCode::Char('c'))
190
+ && key_event
191
+ .modifiers
192
+ .contains(crossterm::event::KeyModifiers::CONTROL);
193
+ if is_ctrl_c {
194
+ disable_raw_mode()?;
195
+ println!("\n\x1b[31mSetup cancelled.\x1b[0m");
196
+ return Ok(None);
197
+ }
198
+
199
+ match key_event.code {
200
+ KeyCode::Up => {
201
+ if cursor > 0 {
202
+ cursor -= 1;
203
+ } else {
204
+ cursor = options.len() - 1;
205
+ }
206
+ disable_raw_mode()?;
207
+ print!("\x1b[{}A\x1b[J", options.len());
208
+ print_options(&options, cursor);
209
+ enable_raw_mode()?;
210
+ }
211
+ KeyCode::Down => {
212
+ if cursor < options.len() - 1 {
213
+ cursor += 1;
214
+ } else {
215
+ cursor = 0;
216
+ }
217
+ disable_raw_mode()?;
218
+ print!("\x1b[{}A\x1b[J", options.len());
219
+ print_options(&options, cursor);
220
+ enable_raw_mode()?;
221
+ }
222
+ KeyCode::Char(' ') => {
223
+ options[cursor].enabled = !options[cursor].enabled;
224
+ disable_raw_mode()?;
225
+ print!("\x1b[{}A\x1b[J", options.len());
226
+ print_options(&options, cursor);
227
+ enable_raw_mode()?;
228
+ }
229
+ KeyCode::Char('a') => {
230
+ for opt in &mut options {
231
+ opt.enabled = true;
232
+ }
233
+ disable_raw_mode()?;
234
+ print!("\x1b[{}A\x1b[J", options.len());
235
+ print_options(&options, cursor);
236
+ enable_raw_mode()?;
237
+ }
238
+ KeyCode::Char('i') => {
239
+ for opt in &mut options {
240
+ opt.enabled = !opt.enabled;
241
+ }
242
+ disable_raw_mode()?;
243
+ print!("\x1b[{}A\x1b[J", options.len());
244
+ print_options(&options, cursor);
245
+ enable_raw_mode()?;
246
+ }
247
+ KeyCode::Enter => {
248
+ break;
249
+ }
250
+ _ => {}
251
+ }
252
+ }
253
+ }
254
+ }
255
+ Ok(false) => {}
256
+ Err(_) => {
257
+ break;
258
+ }
259
+ }
260
+ }
261
+ disable_raw_mode()?;
262
+ println!();
263
+
264
+ let disabled: Vec<String> = options
265
+ .iter()
266
+ .filter(|o| !o.enabled)
267
+ .map(|o| o.key.to_string())
268
+ .collect();
269
+
270
+ config.disabled_tools = disabled;
271
+ save_config(&config)?;
272
+
273
+ println!("\x1b[32mSuccessfully updated tool configurations!\x1b[0m\n");
274
+
275
+ println!("\x1b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m");
276
+ println!("\x1b[32m Choose where to run Mint AI Agent\x1b[0m");
277
+ println!("\x1b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m");
278
+ println!("Select the environment you want to launch:");
279
+ println!(" \x1b[90m[Keyboard Controls: ↑/↓: Navigate | Enter: Confirm]\x1b[0m");
280
+ println!();
281
+
282
+ let run_options = vec![
283
+ ToolOption {
284
+ name: "1. CLI (Interactive Terminal Assistant)",
285
+ key: "cli",
286
+ enabled: false,
287
+ },
288
+ ToolOption {
289
+ name: "2. Desktop App (Download & Install)",
290
+ key: "app_link",
291
+ enabled: false,
292
+ },
293
+ ToolOption {
294
+ name: "3. Web (Vite Web App UI)",
295
+ key: "web",
296
+ enabled: false,
297
+ },
298
+ ];
299
+
300
+ let mut run_cursor = 0;
301
+ print_run_options(&run_options, run_cursor);
302
+ enable_raw_mode()?;
303
+
304
+ loop {
305
+ match event::poll(std::time::Duration::from_millis(100)) {
306
+ Ok(true) => {
307
+ if let Event::Key(key_event) = event::read()? {
308
+ if key_event.kind == event::KeyEventKind::Press {
309
+ let is_ctrl_c = matches!(key_event.code, KeyCode::Char('c'))
310
+ && key_event
311
+ .modifiers
312
+ .contains(crossterm::event::KeyModifiers::CONTROL);
313
+ if is_ctrl_c {
314
+ disable_raw_mode()?;
315
+ println!("\n\x1b[31mRun selection cancelled.\x1b[0m");
316
+ return Ok(None);
317
+ }
318
+
319
+ match key_event.code {
320
+ KeyCode::Up => {
321
+ if run_cursor > 0 {
322
+ run_cursor -= 1;
323
+ } else {
324
+ run_cursor = run_options.len() - 1;
325
+ }
326
+ disable_raw_mode()?;
327
+ print!("\x1b[{}A\x1b[J", run_options.len());
328
+ print_run_options(&run_options, run_cursor);
329
+ enable_raw_mode()?;
330
+ }
331
+ KeyCode::Down => {
332
+ if run_cursor < run_options.len() - 1 {
333
+ run_cursor += 1;
334
+ } else {
335
+ run_cursor = 0;
336
+ }
337
+ disable_raw_mode()?;
338
+ print!("\x1b[{}A\x1b[J", run_options.len());
339
+ print_run_options(&run_options, run_cursor);
340
+ enable_raw_mode()?;
341
+ }
342
+ KeyCode::Enter => {
343
+ break;
344
+ }
345
+ _ => {}
346
+ }
347
+ }
348
+ }
349
+ }
350
+ Ok(false) => {}
351
+ Err(_) => {
352
+ break;
353
+ }
354
+ }
355
+ }
356
+ disable_raw_mode()?;
357
+ println!();
358
+
359
+ Ok(Some(run_options[run_cursor].key.to_string()))
360
+ }
361
+
362
+ fn print_options(options: &[ToolOption], cursor: usize) {
363
+ for (i, opt) in options.iter().enumerate() {
364
+ let checkbox = if opt.enabled {
365
+ "\x1b[32m◉\x1b[0m"
366
+ } else {
367
+ "\x1b[90m○\x1b[0m"
368
+ };
369
+ if i == cursor {
370
+ println!(
371
+ " \x1b[36m❯\x1b[0m {} \x1b[36m{}\x1b[0m",
372
+ checkbox, opt.name
373
+ );
374
+ } else {
375
+ println!(" {} {}", checkbox, opt.name);
376
+ }
377
+ }
378
+ let _ = io::stdout().flush();
379
+ }
380
+
381
+ fn print_run_options(options: &[ToolOption], cursor: usize) {
382
+ for (i, opt) in options.iter().enumerate() {
383
+ if i == cursor {
384
+ println!(" \x1b[36m❯\x1b[0m \x1b[36m{}\x1b[0m", opt.name);
385
+ } else {
386
+ println!(" {}", opt.name);
387
+ }
388
+ }
389
+ let _ = io::stdout().flush();
390
+ }
@@ -0,0 +1,8 @@
1
+ use std::path::Path;
2
+
3
+ use anyhow::Result;
4
+ use mint_core::{LearnedSkill, learn_skill};
5
+
6
+ pub fn learn(path: &Path) -> Result<LearnedSkill> {
7
+ Ok(learn_skill(path)?)
8
+ }
@@ -0,0 +1,279 @@
1
+ use std::path::PathBuf;
2
+ use std::process::Command;
3
+ use std::time::{SystemTime, UNIX_EPOCH};
4
+
5
+ use anyhow::{Context, Result, bail};
6
+
7
+ const PACKAGE: &str = "@pheem49/mint";
8
+
9
+ pub fn run(check_only: bool, dry_run: bool, approved: bool) -> Result<()> {
10
+ let current = env!("CARGO_PKG_VERSION");
11
+ let output = Command::new(npm())
12
+ .args(["view", PACKAGE, "version", "--json"])
13
+ .output()
14
+ .context("unable to run npm update check")?;
15
+ if !output.status.success() {
16
+ bail!(
17
+ "npm update check failed: {}",
18
+ String::from_utf8_lossy(&output.stderr)
19
+ );
20
+ }
21
+ let latest = String::from_utf8_lossy(&output.stdout)
22
+ .trim()
23
+ .trim_matches('"')
24
+ .to_owned();
25
+ write_cache(&latest);
26
+ if compare_versions(current, &latest) >= 0 {
27
+ println!("Mint is already up to date ({current}).");
28
+ return Ok(());
29
+ }
30
+ println!("Mint {latest} is available. Current version: {current}.");
31
+ if check_only {
32
+ return Ok(());
33
+ }
34
+ if !approved {
35
+ bail!("update installation requires --approve");
36
+ }
37
+ let mut command = Command::new(npm());
38
+ command.args(["install", "-g", &format!("{PACKAGE}@latest")]);
39
+ if dry_run {
40
+ command.arg("--dry-run");
41
+ }
42
+ let status = command
43
+ .status()
44
+ .context("unable to run npm global update")?;
45
+ if !status.success() {
46
+ bail!("npm global update failed with status {status}");
47
+ }
48
+ println!(
49
+ "{}",
50
+ if dry_run {
51
+ "Update dry run complete."
52
+ } else {
53
+ "Mint updated. Restart mint to use the new version."
54
+ }
55
+ );
56
+ Ok(())
57
+ }
58
+
59
+ fn npm() -> &'static str {
60
+ if cfg!(target_os = "windows") {
61
+ "npm.cmd"
62
+ } else {
63
+ "npm"
64
+ }
65
+ }
66
+
67
+ #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
68
+ struct UpdateCache {
69
+ last_checked: u64,
70
+ latest_version: String,
71
+ }
72
+
73
+ fn cache_path() -> Option<PathBuf> {
74
+ #[cfg(test)]
75
+ {
76
+ Some(std::env::temp_dir().join("update-cache.json"))
77
+ }
78
+ #[cfg(not(test))]
79
+ {
80
+ dirs::config_dir().map(|dir| dir.join("mint").join("update-cache.json"))
81
+ }
82
+ }
83
+
84
+ fn get_current_timestamp() -> u64 {
85
+ SystemTime::now()
86
+ .duration_since(UNIX_EPOCH)
87
+ .map(|d| d.as_secs())
88
+ .unwrap_or(0)
89
+ }
90
+
91
+ fn write_cache(latest_version: &str) -> Option<()> {
92
+ let path = cache_path()?;
93
+ if let Some(parent) = path.parent() {
94
+ std::fs::create_dir_all(parent).ok()?;
95
+ }
96
+ let cache = UpdateCache {
97
+ last_checked: get_current_timestamp(),
98
+ latest_version: latest_version.to_owned(),
99
+ };
100
+ let json = serde_json::to_string_pretty(&cache).ok()?;
101
+ std::fs::write(path, json).ok()?;
102
+ Some(())
103
+ }
104
+
105
+ pub fn get_cached_update_notice() -> Option<(String, String)> {
106
+ let path = cache_path()?;
107
+ if !path.exists() {
108
+ return None;
109
+ }
110
+ let data = std::fs::read_to_string(path).ok()?;
111
+ let cache: UpdateCache = serde_json::from_str(&data).ok()?;
112
+ let current = env!("CARGO_PKG_VERSION");
113
+ if compare_versions(current, &cache.latest_version) < 0 {
114
+ Some((current.to_owned(), cache.latest_version))
115
+ } else {
116
+ None
117
+ }
118
+ }
119
+
120
+ pub fn should_check_for_update() -> bool {
121
+ let path = match cache_path() {
122
+ Some(p) => p,
123
+ None => return false,
124
+ };
125
+ if !path.exists() {
126
+ return true;
127
+ }
128
+ let data = match std::fs::read_to_string(path) {
129
+ Ok(d) => d,
130
+ Err(_) => return true,
131
+ };
132
+ let cache: UpdateCache = match serde_json::from_str(&data) {
133
+ Ok(c) => c,
134
+ Err(_) => return true,
135
+ };
136
+ let now = get_current_timestamp();
137
+ // Check once every 24 hours (86400 seconds)
138
+ now.saturating_sub(cache.last_checked) > 86400
139
+ }
140
+
141
+ pub fn check_for_update_quietly() -> Option<(String, String)> {
142
+ let current = env!("CARGO_PKG_VERSION");
143
+ let output = Command::new(npm())
144
+ .args(["view", PACKAGE, "version", "--json"])
145
+ .output()
146
+ .ok()?;
147
+ if !output.status.success() {
148
+ return None;
149
+ }
150
+ let latest = String::from_utf8_lossy(&output.stdout)
151
+ .trim()
152
+ .trim_matches('"')
153
+ .to_owned();
154
+ write_cache(&latest);
155
+ if compare_versions(current, &latest) < 0 {
156
+ Some((current.to_owned(), latest))
157
+ } else {
158
+ None
159
+ }
160
+ }
161
+
162
+ pub fn print_update_notice(current: &str, latest: &str) {
163
+ let command_msg = "Run sh -c 'curl -fsSL https://raw.githubusercontent.com/Pheem49/Mint/main/install.sh | MINT_NON_INTERACTIVE=1 sh' to update.";
164
+ let notes_label = "See full release notes:";
165
+ let notes_url = "https://github.com/Pheem49/Mint/releases/latest";
166
+
167
+ // Text lengths (including 1 leading space)
168
+ let title_clean_len = 1
169
+ + 3
170
+ + format!("Update available! {} -> {}", current, latest)
171
+ .chars()
172
+ .count();
173
+ let command_msg_len = 1 + command_msg.len();
174
+ let notes_label_len = 1 + notes_label.len();
175
+ let notes_url_len = 1 + notes_url.len();
176
+
177
+ let max_len = command_msg_len
178
+ .max(title_clean_len)
179
+ .max(notes_label_len)
180
+ .max(notes_url_len)
181
+ + 1; // plus 1 for trailing space before right border
182
+
183
+ let border = "─".repeat(max_len);
184
+ println!("\x1b[33m╭{}╮\x1b[0m", border);
185
+
186
+ // Line 1: Title
187
+ let title_display = format!(
188
+ " ✨ Update available! \x1b[1;32m{}\x1b[0;33m -> \x1b[1;32m{}\x1b[0;33m",
189
+ current, latest
190
+ );
191
+ let padding1 = max_len - title_clean_len;
192
+ println!(
193
+ "\x1b[33m│\x1b[0m{}{}\x1b[33m│\x1b[0m",
194
+ title_display,
195
+ " ".repeat(padding1)
196
+ );
197
+
198
+ // Line 2: Command
199
+ let padding2 = max_len - command_msg_len;
200
+ println!(
201
+ "\x1b[33m│\x1b[0m \x1b[37m{}\x1b[0m{}\x1b[33m│\x1b[0m",
202
+ command_msg,
203
+ " ".repeat(padding2)
204
+ );
205
+
206
+ // Line 3: Empty separator
207
+ println!("\x1b[33m│\x1b[0m{}\x1b[33m│\x1b[0m", " ".repeat(max_len));
208
+
209
+ // Line 4: Notes label
210
+ let padding4 = max_len - notes_label_len;
211
+ println!(
212
+ "\x1b[33m│\x1b[0m \x1b[90m{}\x1b[0m{}\x1b[33m│\x1b[0m",
213
+ notes_label,
214
+ " ".repeat(padding4)
215
+ );
216
+
217
+ // Line 5: Notes URL
218
+ let padding5 = max_len - notes_url_len;
219
+ println!(
220
+ "\x1b[33m│\x1b[0m \x1b[36m{}\x1b[0m{}\x1b[33m│\x1b[0m",
221
+ notes_url,
222
+ " ".repeat(padding5)
223
+ );
224
+
225
+ println!("\x1b[33m╰{}╯\x1b[0m\n", border);
226
+ }
227
+
228
+ fn compare_versions(left: &str, right: &str) -> i8 {
229
+ let parse = |value: &str| {
230
+ value
231
+ .trim_start_matches('v')
232
+ .split('-')
233
+ .next()
234
+ .unwrap_or_default()
235
+ .split('.')
236
+ .map(|part| part.parse::<u64>().unwrap_or(0))
237
+ .collect::<Vec<_>>()
238
+ };
239
+ let left = parse(left);
240
+ let right = parse(right);
241
+ for index in 0..left.len().max(right.len()).max(3) {
242
+ match left
243
+ .get(index)
244
+ .unwrap_or(&0)
245
+ .cmp(right.get(index).unwrap_or(&0))
246
+ {
247
+ std::cmp::Ordering::Greater => return 1,
248
+ std::cmp::Ordering::Less => return -1,
249
+ std::cmp::Ordering::Equal => {}
250
+ }
251
+ }
252
+ 0
253
+ }
254
+
255
+ #[cfg(test)]
256
+ mod tests {
257
+ use super::*;
258
+
259
+ #[test]
260
+ fn compares_semantic_versions() {
261
+ assert_eq!(compare_versions("1.5.4", "1.6.0"), -1);
262
+ assert_eq!(compare_versions("v2.0.0-alpha.1", "2.0.0"), 0);
263
+ }
264
+
265
+ #[test]
266
+ fn test_write_and_read_cache() {
267
+ let path = cache_path().unwrap();
268
+ if path.exists() {
269
+ let _ = std::fs::remove_file(&path);
270
+ }
271
+ assert!(get_cached_update_notice().is_none());
272
+ assert!(write_cache("99.9.9").is_some());
273
+ let notice = get_cached_update_notice();
274
+ assert!(notice.is_some());
275
+ let (_current, latest) = notice.unwrap();
276
+ assert_eq!(latest, "99.9.9");
277
+ let _ = std::fs::remove_file(&path);
278
+ }
279
+ }
@@ -0,0 +1,22 @@
1
+ [package]
2
+ name = "mint-core"
3
+ version.workspace = true
4
+ edition.workspace = true
5
+ license.workspace = true
6
+
7
+ [dependencies]
8
+ base64.workspace = true
9
+ chrono.workspace = true
10
+ dirs.workspace = true
11
+ futures-util.workspace = true
12
+ image.workspace = true
13
+ quick-xml.workspace = true
14
+ regex.workspace = true
15
+ reqwest.workspace = true
16
+ rusqlite.workspace = true
17
+ serde.workspace = true
18
+ serde_json.workspace = true
19
+ sha2.workspace = true
20
+ thiserror.workspace = true
21
+ tokio.workspace = true
22
+ tokio-tungstenite.workspace = true