@pheem49/mint 1.6.2 → 1.6.4

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 (74) hide show
  1. package/.github/workflows/ci.yml +14 -0
  2. package/Cargo.lock +3 -3
  3. package/Cargo.toml +1 -1
  4. package/README.md +82 -21
  5. package/assets/Mint_CLI.png +0 -0
  6. package/assets/Mint_Desktop.png +0 -0
  7. package/assets/Mint_Web.png +0 -0
  8. package/assets/Mint_WorkSpace.png +0 -0
  9. package/assets/Setting.png +0 -0
  10. package/assets/bridges.svg +4 -0
  11. package/assets/chat.svg +3 -0
  12. package/assets/code.svg +4 -0
  13. package/assets/features.svg +3 -0
  14. package/assets/imagegen.svg +5 -0
  15. package/assets/live2d.svg +6 -0
  16. package/assets/memory.svg +5 -0
  17. package/assets/screencapture.svg +4 -0
  18. package/assets/setup.svg +3 -0
  19. package/assets/tools.svg +4 -0
  20. package/bin/mint +0 -0
  21. package/crates/mint-cli/src/agent.rs +6 -2
  22. package/crates/mint-cli/src/main.rs +145 -5
  23. package/crates/mint-cli/src/onboard.rs +134 -1
  24. package/crates/mint-core/src/api_server.rs +108 -3
  25. package/crates/mint-core/src/config.rs +20 -1
  26. package/crates/mint-core/src/image_gen.rs +895 -0
  27. package/crates/mint-core/src/lib.rs +4 -0
  28. package/package.json +3 -3
  29. package/src/bin/index.js +0 -0
  30. package/src/renderer/index-web.html +1 -1
  31. package/src/renderer/index.html +1 -1
  32. package/src/renderer/src/components/ChatPanel.tsx +252 -26
  33. package/src/renderer/src/components/DashboardSidebar.tsx +11 -3
  34. package/src/renderer/src/components/ImageStudioPanel.tsx +638 -0
  35. package/src/renderer/src/components/MintDashboard.tsx +14 -5
  36. package/src/renderer/src/components/SettingsWindow.tsx +29 -20
  37. package/src/renderer/src/css/image-studio.css +722 -0
  38. package/src/renderer/src/css/settings.css +13 -3
  39. package/src/renderer/src/css/styles.css +50 -26
  40. package/src/renderer/src/index.css +106 -0
  41. package/src/renderer/src/tauri.ts +123 -0
  42. package/src/renderer/src-web/components/ChatPanel.tsx +273 -25
  43. package/src/renderer/src-web/components/DashboardSidebar.tsx +11 -3
  44. package/src/renderer/src-web/components/ImageStudioPanel.tsx +638 -0
  45. package/src/renderer/src-web/components/MintDashboard.tsx +13 -4
  46. package/src/renderer/src-web/components/SettingsWindow.tsx +29 -20
  47. package/src/renderer/src-web/css/image-studio.css +722 -0
  48. package/src/renderer/src-web/css/settings.css +14 -4
  49. package/src/renderer/src-web/css/styles.css +50 -26
  50. package/src/renderer/src-web/index.css +106 -0
  51. package/src/renderer/src-web/tauri.ts +124 -0
  52. package/src-tauri/Cargo.toml +29 -0
  53. package/src-tauri/build.rs +3 -0
  54. package/src-tauri/capabilities/main.json +7 -0
  55. package/src-tauri/gen/schemas/acl-manifests.json +1 -0
  56. package/src-tauri/gen/schemas/capabilities.json +1 -0
  57. package/src-tauri/gen/schemas/desktop-schema.json +2412 -0
  58. package/src-tauri/gen/schemas/linux-schema.json +2412 -0
  59. package/src-tauri/src/browser.rs +141 -0
  60. package/src-tauri/src/desktop.rs +392 -0
  61. package/src-tauri/src/discord_rpc.rs +99 -0
  62. package/src-tauri/src/events.rs +70 -0
  63. package/src-tauri/src/headless.rs +222 -0
  64. package/src-tauri/src/integrations.rs +126 -0
  65. package/src-tauri/src/lib.rs +1076 -0
  66. package/src-tauri/src/main.rs +3 -0
  67. package/src-tauri/src/plugins.rs +16 -0
  68. package/src-tauri/src/proactive.rs +254 -0
  69. package/src-tauri/src/system.rs +250 -0
  70. package/src-tauri/src/updater.rs +148 -0
  71. package/src-tauri/src/webhooks.rs +255 -0
  72. package/src-tauri/src/workflows.rs +70 -0
  73. package/src-tauri/tauri.conf.json +48 -0
  74. package/tsconfig.json +1 -1
@@ -23,6 +23,20 @@ jobs:
23
23
  node-version: 22
24
24
  cache: npm
25
25
 
26
+ - name: Set up Rust
27
+ run: |
28
+ rustup update stable
29
+ rustup default stable
30
+
31
+ - name: Install Tauri Linux dependencies
32
+ run: |
33
+ sudo apt-get update
34
+ sudo apt-get install -y \
35
+ build-essential curl file pkg-config wget \
36
+ libdbus-1-dev libwebkit2gtk-4.1-dev \
37
+ libayatana-appindicator3-dev librsvg2-dev \
38
+ poppler-utils unzip patchelf
39
+
26
40
  - name: Install dependencies
27
41
  run: npm ci
28
42
 
package/Cargo.lock CHANGED
@@ -2095,7 +2095,7 @@ dependencies = [
2095
2095
 
2096
2096
  [[package]]
2097
2097
  name = "mint-cli"
2098
- version = "1.6.0"
2098
+ version = "1.6.4"
2099
2099
  dependencies = [
2100
2100
  "anyhow",
2101
2101
  "base64 0.22.1",
@@ -2113,7 +2113,7 @@ dependencies = [
2113
2113
 
2114
2114
  [[package]]
2115
2115
  name = "mint-core"
2116
- version = "1.6.0"
2116
+ version = "1.6.4"
2117
2117
  dependencies = [
2118
2118
  "base64 0.22.1",
2119
2119
  "chrono",
@@ -2134,7 +2134,7 @@ dependencies = [
2134
2134
 
2135
2135
  [[package]]
2136
2136
  name = "mint-desktop"
2137
- version = "1.6.0"
2137
+ version = "1.6.4"
2138
2138
  dependencies = [
2139
2139
  "base64 0.22.1",
2140
2140
  "dirs",
package/Cargo.toml CHANGED
@@ -7,7 +7,7 @@ members = [
7
7
  resolver = "2"
8
8
 
9
9
  [workspace.package]
10
- version = "1.6.2"
10
+ version = "1.6.4"
11
11
  edition = "2024"
12
12
  license = "AGPL-3.0-only"
13
13
 
package/README.md CHANGED
@@ -16,27 +16,27 @@ The desktop application and native CLI share the same Rust domain layer, so chat
16
16
  memory, knowledge, tools, safety policies, and integrations behave consistently
17
17
  across both interfaces.
18
18
 
19
- ## 🌟 What Mint Can Do
19
+ ## <img src="assets/features.svg" width="24" height="24" valign="middle" /> What Mint Can Do
20
20
 
21
21
  Mint is a local-first AI assistant running on your machine, capable of handling tasks via either the desktop application or the terminal interface (CLI):
22
22
 
23
23
  ---
24
24
 
25
- ### 1. 🤖 AI Chat & Multi-Providers
25
+ ### 1. <img src="assets/chat.svg" width="18" height="18" valign="middle" /> AI Chat & Multi-Providers
26
26
  - Connect to **Gemini, OpenAI, Anthropic (Claude), Ollama (Local), Hugging Face**, and LM Studio.
27
27
  - Run private local LLMs inside your machine using Ollama or connect to leading cloud APIs.
28
28
  - Supports system instructions, temperature adjustments, voice replies, and image analysis (Multimodal).
29
29
 
30
30
  ---
31
31
 
32
- ### 2. 🎨 Interactive Live2D Desktop Assistant
32
+ ### 2. <img src="assets/live2d.svg" width="18" height="18" valign="middle" /> Interactive Live2D Desktop Assistant
33
33
  - An interactive anime avatar (**Shiroko**) displayed right on your desktop with gaze tracking (eye/face follows your mouse pointer).
34
34
  - Toggle expression changes and cycle through character accessories dynamically.
35
35
  - Custom interaction zones (Head, Cheek, Hands, Body) that trigger unique animations and message toasts.
36
36
 
37
37
  ---
38
38
 
39
- ### 3. 💻 Autonomous Code Agent
39
+ ### 3. <img src="assets/code.svg" width="18" height="18" valign="middle" /> Autonomous Code Agent
40
40
  - Run code agent loops via `/code <task>` or the terminal command `mint code agent "<task>"`.
41
41
  - Scan your project workspace, build multi-file implementation plans, fix test suite errors, and write edits automatically.
42
42
  - Run local tests, cargo checks, and shell commands.
@@ -45,20 +45,20 @@ Mint is a local-first AI assistant running on your machine, capable of handling
45
45
 
46
46
  ---
47
47
 
48
- ### 4. 🧠 Long-Term Memory & Knowledge Base
48
+ ### 4. <img src="assets/memory.svg" width="18" height="18" valign="middle" /> Long-Term Memory & Knowledge Base
49
49
  - Persistent conversation memory stored locally in SQLite. Manage user profile memory with `/memory set/get` or CLI commands.
50
50
  - Index local directories, text files, and documentation to build your private searchable knowledge base.
51
51
 
52
52
  ---
53
53
 
54
- ### 5. 🔌 Tool & MCP Integrations
54
+ ### 5. <img src="assets/tools.svg" width="18" height="18" valign="middle" /> Tool & MCP Integrations
55
55
  - Support **Model Context Protocol (MCP)** to connect tools like Google/Brave Search, Filesystem servers, and GitHub context.
56
56
  - **Auto GitHub Link Resolver:** Automatically detects GitHub URLs in chat messages (CLI, Web, and Desktop) and Code Agent tasks. It fetches and injects the repository's metadata, directory structure, and README as prompt context, serving as an instant fallback when the GitHub MCP server is not active.
57
57
  - Local plugins for Spotify playback control, Google Calendar, Gmail drafts, and Notion workspace reading.
58
58
 
59
59
  ---
60
60
 
61
- ### 6. 🌐 Messaging Bridges
61
+ ### 6. <img src="assets/bridges.svg" width="18" height="18" valign="middle" /> Messaging Bridges
62
62
  - Bridge your local AI assistant to messaging services: **Telegram, Discord Gateway, Discord RPC, Slack, LINE, and WhatsApp**.
63
63
  - Host local chatbot webhooks that relay chat traffic into your configured LLM.
64
64
  > [!TIP]
@@ -66,16 +66,23 @@ Mint is a local-first AI assistant running on your machine, capable of handling
66
66
 
67
67
  ---
68
68
 
69
- ### 7. 📸 Screen Capture & Translation
69
+ ### 7. <img src="assets/screencapture.svg" width="18" height="18" valign="middle" /> Screen Capture & Translation
70
70
  - Capture screen snapshots for instant visual analysis by the AI.
71
71
  - Real-time continuous overlay translation of specific screen regions.
72
72
 
73
73
  ---
74
74
 
75
+ ### 8. <img src="assets/imagegen.svg" width="18" height="18" valign="middle" /> AI Image Generation
76
+ - Generate high-quality images directly from chat or terminal using **DALL-E 3, Stability AI (Stable Diffusion), Ideogram, Replicate (Flux)**, and Google NanoBanana.
77
+ - Supports aspect ratio selections, negative prompts, custom image counts, and automatic storage of generated pictures to the local library.
78
+
79
+ ---
80
+
75
81
  ## Highlights
76
82
 
77
83
  - Multi-provider chat with Gemini, OpenAI, Anthropic, Ollama, Hugging Face, and
78
84
  local OpenAI-compatible endpoints.
85
+ - Image generation using DALL-E 3, Stability AI, Ideogram, Replicate, and NanoBanana.
79
86
  - Native streaming responses, SQLite-backed memory, tasks, searchable local
80
87
  knowledge, skills, and semantic code search.
81
88
  - Desktop dashboard with a Live2D assistant, model interaction areas, pictures,
@@ -89,22 +96,21 @@ Mint is a local-first AI assistant running on your machine, capable of handling
89
96
  Cloud API integrations.
90
97
  - Signed Tauri update checks with an explicit approval step before installation.
91
98
 
92
- ## Screenshots
93
-
94
- | Desktop assistant | Settings |
95
- | --- | --- |
96
- | ![Mint desktop assistant](docs/assets/Agent_Mint.png) | ![Mint settings](docs/assets/Settings.png) |
99
+ ## <img src="assets/setup.svg" width="24" height="24" valign="middle" /> Prerequisites
97
100
 
98
- ![Mint CLI](docs/assets/CLI_Screen.png)
101
+ Before you can build or run Mint locally, make sure you have the following system tools installed:
99
102
 
100
- ## Prerequisites
103
+ | Tool | Description | Required For |
104
+ | :--- | :--- | :--- |
105
+ | **Node.js & npm** | JavaScript runtime and package manager | Frontend UI (React, Vite, TypeScript) |
106
+ | **Rust Toolchain** | Rust compiler (`rustc`) and package manager (`cargo`) | Shared domain logic, CLI, and Tauri backend |
107
+ | **System Dependencies** | Native OS libraries (compiler tools, dbus, webkit) | Compiling window GUI, Webview rendering, and OS utilities |
101
108
 
102
- - Node.js and npm
103
- - A Rust toolchain
104
- - Tauri v2 native build dependencies for your operating system
109
+ ### Linux Dependencies
105
110
 
106
- On Debian, Ubuntu, or Linux Mint:
111
+ Install the required C compilers, WebKitGTK, and system libraries for your specific Linux distribution:
107
112
 
113
+ **Debian / Ubuntu / Linux Mint:**
108
114
  ```bash
109
115
  sudo apt-get install -y \
110
116
  build-essential curl file pkg-config wget \
@@ -113,8 +119,25 @@ sudo apt-get install -y \
113
119
  poppler-utils unzip patchelf
114
120
  ```
115
121
 
116
- See the [Tauri prerequisites guide](https://v2.tauri.app/start/prerequisites/)
117
- for other platforms.
122
+ **Fedora / RHEL / CentOS:**
123
+ ```bash
124
+ sudo dnf groupinstall -y "Development Tools"
125
+ sudo dnf install -y \
126
+ webkit2gtk4.1-devel openssl-devel curl wget glibc-devel \
127
+ dbus-devel libayatana-appindicator-devel librsvg2-devel \
128
+ poppler-utils unzip patchelf
129
+ ```
130
+
131
+ **Arch Linux:**
132
+ ```bash
133
+ sudo pacman -Syu --needed \
134
+ base-devel webkit2gtk-4.1 openssl curl wget \
135
+ dbus libayatana-appindicator librsvg \
136
+ poppler unzip patchelf
137
+ ```
138
+
139
+ > [!TIP]
140
+ > **Other Platforms:** If you are developing on macOS or Windows, follow the official [Tauri Prerequisites Guide](https://v2.tauri.app/start/prerequisites/) to set up your build environment.
118
141
 
119
142
  ## Installation
120
143
 
@@ -139,6 +162,7 @@ mint setup
139
162
  mint
140
163
  mint web
141
164
  mint chat "Hello"
165
+ mint imagine "A futuristic mint-colored robot" --aspect 16:9
142
166
  ```
143
167
 
144
168
  Most integrations can be configured from:
@@ -184,6 +208,42 @@ To install the `mint` command-line tool globally:
184
208
  * **Option C (Development Shell Alias):**
185
209
  If you are actively modifying code and want changes to reflect instantly, set up the alias under the [Setting up the mint Shortcut](#setting-up-the-mint-shortcut) section.
186
210
 
211
+
212
+ ## User Interface
213
+
214
+ ### Desktop App
215
+ <table width="100%">
216
+ <tr>
217
+ <td align="center" width="50%"><b>Desktop Assistant</b></td>
218
+ <td align="center" width="50%"><b>Settings</b></td>
219
+ </tr>
220
+ <tr>
221
+ <td><img src="assets/Mint_Desktop.png" alt="Desktop Assistant" /></td>
222
+ <td><img src="assets/Setting.png" alt="Settings" /></td>
223
+ </tr>
224
+ </table>
225
+
226
+ ### Web UI
227
+ <table width="100%">
228
+ <tr>
229
+ <td align="center"><img src="assets/Mint_Web.png" alt="Web UI" /></td>
230
+ </tr>
231
+ </table>
232
+
233
+ ### CLI
234
+ <table width="100%">
235
+ <tr>
236
+ <td align="center"><img src="assets/Mint_CLI.png" alt="CLI" /></td>
237
+ </tr>
238
+ </table>
239
+
240
+ ### Workspace & Agent
241
+ <table width="100%">
242
+ <tr>
243
+ <td align="center"><img src="assets/Mint_WorkSpace.png" alt="Workspace & Agent" /></td>
244
+ </tr>
245
+ </table>
246
+
187
247
  ## Desktop Assistant
188
248
 
189
249
  The desktop application provides:
@@ -290,6 +350,7 @@ mint chat "<message>"
290
350
  | `mint config doctor` | Validate the local setup |
291
351
  | `mint providers` | List configured AI providers |
292
352
  | `mint chat "<message>"` | Send one chat message |
353
+ | `mint imagine "<prompt>"` | Generate an image from a text prompt |
293
354
  | `mint memory recent` | Show recent conversation memory |
294
355
  | `mint task list` | List all tasks (pending and completed) |
295
356
  | `mint task pending` | List pending tasks |
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
3
+ <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
3
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <polyline points="16 18 22 12 16 6"/>
3
+ <polyline points="8 6 2 12 8 18"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 3.5 1 9.8a7 7 0 0 1-9 8.2zm0 0v-5m-2.5 1.5l3-3m-4.5 0l4-4" />
3
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
3
+ <circle cx="8.5" cy="8.5" r="1.5"/>
4
+ <polyline points="21 15 16 10 5 21"/>
5
+ </svg>
@@ -0,0 +1,6 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <circle cx="12" cy="12" r="10"/>
3
+ <path d="M8 14s1.5 2 4 2 4-2 4-2"/>
4
+ <line x1="9" y1="9" x2="9.01" y2="9"/>
5
+ <line x1="15" y1="9" x2="15.01" y2="9"/>
6
+ </svg>
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <ellipse cx="12" cy="5" rx="9" ry="3"/>
3
+ <path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
4
+ <path d="M3 12c0 1.66 4 3 9 3s9-1.34 9-3"/>
5
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/>
3
+ <circle cx="12" cy="13" r="4"/>
4
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
3
+ </svg>
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2
+ <circle cx="12" cy="12" r="3"/>
3
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
4
+ </svg>
package/bin/mint CHANGED
Binary file
@@ -178,7 +178,7 @@ pub async fn run_code_agent_with_options(
178
178
  ));
179
179
  render_live_status(&mut status);
180
180
  }
181
- tokio::time::sleep(Duration::from_secs(1)).await;
181
+ tokio::time::sleep(Duration::from_millis(150)).await;
182
182
  }
183
183
  });
184
184
  }
@@ -479,6 +479,7 @@ struct LiveStatus {
479
479
  committed_activities: usize,
480
480
  committed_tasks: usize,
481
481
  rendered_lines: usize,
482
+ spinner_tick: usize,
482
483
  }
483
484
 
484
485
  #[derive(Debug, Clone)]
@@ -551,7 +552,10 @@ fn render_live_status(status: &mut LiveStatus) {
551
552
  lines.extend(activities_lines(&status.activities[activities_start..]));
552
553
  lines.extend(explored_lines(&status.explored[explored_start..]));
553
554
  if let Some(thinking) = &status.thinking {
554
- lines.push(format!("{MINT}●{RESET} {BRIGHT}{thinking}{RESET}"));
555
+ let frames = &["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
556
+ let frame = frames[status.spinner_tick % frames.len()];
557
+ status.spinner_tick += 1;
558
+ lines.push(format!("{MINT}{frame}{RESET}{BRIGHT}{thinking}{RESET}"));
555
559
  }
556
560
  if lines.is_empty() {
557
561
  return;
@@ -7,10 +7,10 @@ use std::{
7
7
  };
8
8
 
9
9
  use mint_core::{
10
- CHAT_CLI_ID, Capability, ChatRequest, CodeEdit, CodePatchHunk, KnowledgeStore, MemoryStore,
11
- MintConfig, TaskStore, apply_code_edits, assert_path_capability, build_code_patch,
10
+ CHAT_CLI_ID, Capability, ChatRequest, CodeEdit, CodePatchHunk, ImageGenRequest, KnowledgeStore,
11
+ MemoryStore, MintConfig, TaskStore, apply_code_edits, assert_path_capability, build_code_patch,
12
12
  build_symbol_index, classify_shell_command, config_path, create_folder, execute_native_plugin,
13
- fetch_github_repo_summary, find_paths, index_semantic_code, initialize_config,
13
+ fetch_github_repo_summary, find_paths, generate_images, index_semantic_code, initialize_config,
14
14
  inspect_code_plan, list_code_files, load_config, native_plugins,
15
15
  orchestrate_chat_stream_with_fallback, orchestrate_chat_with_fallback, parse_github_url,
16
16
  propose_code_edits, read_code_file, repository_summary, run_shell_command, search_code,
@@ -180,6 +180,23 @@ enum Command {
180
180
  Onboard,
181
181
  /// Interactively manage enabled agent tools.
182
182
  Setup,
183
+ /// Generate an image from a text prompt using NanoBanana (Gemini image model).
184
+ Imagine {
185
+ /// Text description of the image to generate.
186
+ prompt: String,
187
+ /// Aspect ratio: 1:1, 16:9, 9:16, or 4:3 [default: 1:1]
188
+ #[arg(long, default_value = "1:1")]
189
+ aspect: String,
190
+ /// Number of images to generate (1–4) [default: 1]
191
+ #[arg(long, default_value_t = 1)]
192
+ count: u8,
193
+ /// Negative prompt — elements to avoid in the image
194
+ #[arg(long)]
195
+ negative: Option<String>,
196
+ /// Save the first generated image to this path
197
+ #[arg(long)]
198
+ output: Option<PathBuf>,
199
+ },
183
200
  }
184
201
 
185
202
  #[derive(Debug, Subcommand)]
@@ -926,6 +943,72 @@ async fn main() -> Result<()> {
926
943
  launch_mint_target(target).await?;
927
944
  }
928
945
  }
946
+ Command::Imagine {
947
+ prompt,
948
+ aspect,
949
+ count,
950
+ negative,
951
+ output,
952
+ } => {
953
+ let config = load_config()?;
954
+ let count = count.clamp(1, 4);
955
+ eprint!("{DIM}✦ Generating {count} image(s)...{RESET}");
956
+ let _ = std::io::stderr().flush();
957
+ let request = ImageGenRequest {
958
+ prompt: prompt.clone(),
959
+ negative_prompt: negative,
960
+ aspect_ratio: Some(aspect),
961
+ num_images: Some(count),
962
+ model: None,
963
+ provider: None,
964
+ };
965
+ match generate_images(&config, &request).await {
966
+ Ok(result) => {
967
+ eprintln!(
968
+ "\r{MINT}✦ Generated {} image(s) {RESET}",
969
+ result.images.len()
970
+ );
971
+ let data_uris: Vec<String> = result
972
+ .images
973
+ .iter()
974
+ .map(|img| img.data_uri.clone())
975
+ .collect();
976
+ match mint_core::save_chat_images(
977
+ data_uris,
978
+ Some(result.provider.clone()),
979
+ Some(prompt.clone()),
980
+ ) {
981
+ Ok(saved) => {
982
+ for entry in &saved {
983
+ println!("{MINT}✓{RESET} Saved: {}", entry.path.display());
984
+ }
985
+ // If --output specified, copy first image there
986
+ if let (Some(out_path), Some(first)) = (&output, saved.first()) {
987
+ match std::fs::copy(&first.path, out_path) {
988
+ Ok(_) => println!(
989
+ "{MINT}✓{RESET} Copied to: {}",
990
+ out_path.display()
991
+ ),
992
+ Err(e) => eprintln!(
993
+ "{WARN}Warning: could not copy to output path: {e}{RESET}"
994
+ ),
995
+ }
996
+ }
997
+ if let Some(desc) = &result.description {
998
+ if !desc.is_empty() {
999
+ println!("\n{DIM}{desc}{RESET}");
1000
+ }
1001
+ }
1002
+ }
1003
+ Err(e) => eprintln!("{ERROR}Failed to save images: {e}{RESET}"),
1004
+ }
1005
+ }
1006
+ Err(e) => {
1007
+ eprintln!("{ERROR}✗ Image generation failed: {e}{RESET}");
1008
+ anyhow::bail!("image generation failed: {e}");
1009
+ }
1010
+ }
1011
+ }
929
1012
  },
930
1013
  }
931
1014
  Ok(())
@@ -1214,6 +1297,10 @@ async fn handle_slash_command(
1214
1297
  ("/memory clear", "Clear all interactions"),
1215
1298
  ("/memory get <key>", "Read a profile value"),
1216
1299
  ("/memory set <key> <val>", "Store a profile value"),
1300
+ (
1301
+ "/image-provider [name]",
1302
+ "List image gen providers or switch default provider",
1303
+ ),
1217
1304
  ("/mcp list", "List configured MCP servers"),
1218
1305
  ("/mcp allow <server> <tool>", "Allow an MCP tool"),
1219
1306
  ("/stats", "Show session statistics"),
@@ -1270,6 +1357,55 @@ async fn handle_slash_command(
1270
1357
  Some(SlashResult::Handled)
1271
1358
  }
1272
1359
 
1360
+ "/image-provider" => {
1361
+ let mut available = Vec::new();
1362
+ if !session.config.api_key.trim().is_empty() {
1363
+ available.push("nanobanana");
1364
+ }
1365
+ if !session.config.openai_api_key.trim().is_empty() {
1366
+ available.push("dalle");
1367
+ }
1368
+ if !session.config.stability_api_key.trim().is_empty() {
1369
+ available.push("stability");
1370
+ }
1371
+ if !session.config.ideogram_api_key.trim().is_empty() {
1372
+ available.push("ideogram");
1373
+ }
1374
+ if !session.config.replicate_api_key.trim().is_empty() {
1375
+ available.push("replicate");
1376
+ }
1377
+ if available.is_empty() {
1378
+ available.push("nanobanana");
1379
+ }
1380
+
1381
+ if rest.is_empty() {
1382
+ println!("\n{BLUE}Configured image generation providers:{RESET}");
1383
+ for p in &available {
1384
+ let active = if p == &session.config.image_gen_provider.as_str() {
1385
+ format!(" {MINT}← active{RESET}")
1386
+ } else {
1387
+ String::new()
1388
+ };
1389
+ println!(" {p}{active}");
1390
+ }
1391
+ println!();
1392
+ } else {
1393
+ if available.contains(&rest) {
1394
+ session.config.image_gen_provider = rest.to_owned();
1395
+ match mint_core::save_config(&session.config) {
1396
+ Ok(()) => println!(
1397
+ "{DIM}Switched default image provider to: {}{RESET}\n",
1398
+ session.config.image_gen_provider
1399
+ ),
1400
+ Err(error) => println!("{ERROR}Config error:{RESET} {error}"),
1401
+ }
1402
+ } else {
1403
+ println!("{ERROR}Provider '{rest}' is not configured or invalid.{RESET}\n");
1404
+ }
1405
+ }
1406
+ Some(SlashResult::Handled)
1407
+ }
1408
+
1273
1409
  "/clear" | "/reset" => {
1274
1410
  println!("Clear conversation history? [y/N] ");
1275
1411
  if let Ok(true) = confirm("Clear conversation history? [y/N] ") {
@@ -1884,6 +2020,10 @@ const AUTOCOMPLETE_COMMANDS: &[(&str, &str)] = &[
1884
2020
  ("/help", "Show help menu"),
1885
2021
  ("/fast", "Toggle fast mode (hide thinking traces)"),
1886
2022
  ("/models", "List AI providers or switch active provider"),
2023
+ (
2024
+ "/image-provider",
2025
+ "List image gen providers or switch default provider",
2026
+ ),
1887
2027
  ("/clear", "Clear conversation history"),
1888
2028
  ("/cd", "Change active workspace directory"),
1889
2029
  ("/image", "Attach image from disk"),
@@ -1963,9 +2103,9 @@ fn draw_input_box(
1963
2103
  let highlight_idx = tab_index.map(|idx| idx % matches.len());
1964
2104
  for (i, (cmd, desc)) in matches.iter().enumerate() {
1965
2105
  if Some(i) == highlight_idx {
1966
- println!(" {BLUE}▶ {:<12}{RESET} {DIM}- {}{RESET}", cmd, desc);
2106
+ println!(" {BLUE}▶ {:<16}{RESET} {DIM}- {}{RESET}", cmd, desc);
1967
2107
  } else {
1968
- println!(" {DIM}{:<12} - {}{RESET}", cmd, desc);
2108
+ println!(" {DIM}{:<16} - {}{RESET}", cmd, desc);
1969
2109
  }
1970
2110
  }
1971
2111
  }