@pheem49/mint 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/Cargo.lock +55 -3
  2. package/Cargo.toml +2 -1
  3. package/Release_Note.md +285 -140
  4. package/bin/mint +0 -0
  5. package/crates/mint-cli/Cargo.toml +1 -0
  6. package/crates/mint-cli/src/actions.rs +233 -0
  7. package/crates/mint-cli/src/agent.rs +287 -43
  8. package/crates/mint-cli/src/gmail.rs +22 -2
  9. package/crates/mint-cli/src/interactive.rs +2888 -0
  10. package/crates/mint-cli/src/main.rs +336 -2854
  11. package/crates/mint-cli/src/markdown.rs +294 -0
  12. package/crates/mint-cli/src/onboard.rs +44 -1
  13. package/crates/mint-cli/src/updater.rs +48 -6
  14. package/crates/mint-core/Cargo.toml +1 -0
  15. package/crates/mint-core/src/agent_loop.rs +1 -0
  16. package/crates/mint-core/src/api_server.rs +376 -13
  17. package/crates/mint-core/src/browser.rs +629 -101
  18. package/crates/mint-core/src/channels.rs +105 -6
  19. package/crates/mint-core/src/chat.rs +52 -4
  20. package/crates/mint-core/src/code_tools.rs +29 -11
  21. package/crates/mint-core/src/config.rs +118 -0
  22. package/crates/mint-core/src/image_gen.rs +294 -33
  23. package/crates/mint-core/src/lib.rs +5 -2
  24. package/crates/mint-core/src/mcp.rs +119 -6
  25. package/crates/mint-core/src/orchestration.rs +133 -11
  26. package/crates/mint-core/src/pictures.rs +64 -1
  27. package/crates/mint-core/src/skills.rs +82 -6
  28. package/crates/mint-core/src/video_gen.rs +235 -0
  29. package/package.json +8 -2
  30. package/shared-modules/luajit/luajit.json +2 -2
  31. package/skills-lock.json +41 -0
  32. package/src/renderer/index-web.html +1 -1
  33. package/src/renderer/index.html +1 -1
  34. package/src/renderer/shared/constants/slashCommands.ts +27 -0
  35. package/src/renderer/shared/platform.ts +3 -0
  36. package/src/renderer/shared/types.ts +4 -0
  37. package/src/renderer/shared/utils/approval.tsx +86 -7
  38. package/src/renderer/shared/utils/markdown.tsx +217 -88
  39. package/src/renderer/shared/utils/slashCommandProcessor.ts +239 -0
  40. package/src/renderer/src/components/ChatPanel.tsx +461 -64
  41. package/src/renderer/src/components/DashboardSidebar.tsx +11 -2
  42. package/src/renderer/src/components/ImageStudioPanel.tsx +87 -4
  43. package/src/renderer/src/components/MintDashboard.tsx +150 -5
  44. package/src/renderer/src/components/PicturesLibrary.tsx +156 -15
  45. package/src/renderer/src/components/Settings/AutomationTab.tsx +316 -18
  46. package/src/renderer/src/components/Settings/GeneralTab.tsx +762 -634
  47. package/src/renderer/src/components/Settings/PluginsTab.tsx +304 -70
  48. package/src/renderer/src/components/Settings/ThemeTab.tsx +6 -1
  49. package/src/renderer/src/components/SettingsWindow.tsx +38 -2
  50. package/src/renderer/src/components/VeoStudioPanel.tsx +549 -0
  51. package/src/renderer/src/css/image-studio.css +106 -0
  52. package/src/renderer/src/css/settings.css +158 -0
  53. package/src/renderer/src/css/styles.css +352 -1
  54. package/src/renderer/src/css/veo-studio.css +626 -0
  55. package/src/renderer/src/index.css +1 -0
  56. package/src/renderer/src/tauri.ts +144 -17
  57. package/src/renderer/src-web/components/ChatPanel.tsx +360 -88
  58. package/src/renderer/src-web/components/DashboardSidebar.tsx +16 -1
  59. package/src/renderer/src-web/components/ImageStudioPanel.tsx +87 -4
  60. package/src/renderer/src-web/components/MintDashboard.tsx +137 -4
  61. package/src/renderer/src-web/components/PicturesLibrary.tsx +155 -15
  62. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +316 -18
  63. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +762 -629
  64. package/src/renderer/src-web/components/Settings/PluginsTab.tsx +304 -70
  65. package/src/renderer/src-web/components/Settings/ThemeTab.tsx +6 -1
  66. package/src/renderer/src-web/components/SettingsWindow.tsx +35 -2
  67. package/src/renderer/src-web/components/VeoStudioPanel.tsx +549 -0
  68. package/src/renderer/src-web/css/image-studio.css +106 -0
  69. package/src/renderer/src-web/css/settings.css +158 -0
  70. package/src/renderer/src-web/css/styles.css +353 -1
  71. package/src/renderer/src-web/css/veo-studio.css +650 -0
  72. package/src/renderer/src-web/index.css +1 -0
  73. package/src/renderer/src-web/tauri.ts +135 -16
  74. package/src-tauri/src/lib.rs +114 -8
  75. package/src-tauri/src/webhooks.rs +45 -31
  76. package/src-tauri/src/workflows.rs +1 -0
  77. package/src-tauri/tauri.conf.json +1 -1
  78. package/temp_gridgeist/AGENTS.md +8 -0
  79. package/temp_gridgeist/CHANGELOG.md +130 -0
  80. package/temp_gridgeist/LICENSE +21 -0
  81. package/temp_gridgeist/README.md +323 -0
  82. package/temp_gridgeist/README.th.md +325 -0
  83. package/temp_gridgeist/skills/gridgeist/SKILL.md +88 -0
  84. package/temp_gridgeist/skills/gridgeist/agents/openai.yaml +9 -0
  85. package/temp_gridgeist/skills/gridgeist/assets/gridgeist-small.svg +10 -0
  86. package/temp_gridgeist/skills/gridgeist/assets/gridgeist.png +0 -0
  87. package/temp_gridgeist/skills/gridgeist/assets/gridgeist.svg +18 -0
  88. package/temp_gridgeist/skills/gridgeist/references/design-language.md +88 -0
  89. package/temp_gridgeist/skills/gridgeist/references/review-checklist.md +128 -0
  90. package/temp_gridgeist/skills/gridgeist/references/system-contract.md +109 -0
@@ -59,6 +59,26 @@ export async function getRuntimeStatus(): Promise<RuntimeStatus> {
59
59
  return invoke<RuntimeStatus>('get_runtime_status')
60
60
  }
61
61
 
62
+ export async function setActiveModel(provider: string, model?: string): Promise<string> {
63
+ if (!isTauriRuntime()) {
64
+ const API_BASE = getLocalApiBase()
65
+ try {
66
+ const res = await fetch(`${API_BASE}/active-model`, {
67
+ method: 'POST',
68
+ headers: { 'Content-Type': 'application/json' },
69
+ body: JSON.stringify({ provider, model }),
70
+ })
71
+ const data = await res.json()
72
+ return data.displayName || `Changed model to ${provider}`
73
+ } catch (e) {
74
+ console.error('Failed to set active model via API:', e)
75
+ return `Changed model to ${provider}`
76
+ }
77
+ }
78
+ const { invoke } = await import('@tauri-apps/api/core')
79
+ return invoke<string>('set_active_model', { provider, model })
80
+ }
81
+
62
82
  export interface DetectedTools {
63
83
  docker: boolean
64
84
  git: boolean
@@ -81,23 +101,52 @@ export async function detectSystemTools(): Promise<DetectedTools> {
81
101
  return invoke<DetectedTools>('detect_system_tools')
82
102
  }
83
103
 
104
+ export async function uploadFile(file: File): Promise<string> {
105
+ if (!isTauriRuntime()) {
106
+ const API_BASE = getLocalApiBase();
107
+ const res = await fetch(`${API_BASE}/uploads?filename=${encodeURIComponent(file.name)}`, {
108
+ method: 'POST',
109
+ body: file,
110
+ });
111
+ if (!res.ok) {
112
+ const data = await res.json().catch(() => null);
113
+ throw new Error(data?.error || `HTTP ${res.status}`);
114
+ }
115
+ const data = await res.json();
116
+ return data.url;
117
+ }
118
+
119
+ // Tauri runtime: call native command with base64 payload
120
+ const { invoke } = await import('@tauri-apps/api/core');
121
+ const dataUri = await new Promise<string>((resolve, reject) => {
122
+ const reader = new FileReader();
123
+ reader.onload = () => resolve(reader.result as string);
124
+ reader.onerror = reject;
125
+ reader.readAsDataURL(file);
126
+ });
127
+ const base64 = dataUri.split(',')[1] || '';
128
+ const url = await invoke<string>('upload_file', { filename: file.name, dataB64: base64 });
129
+ return url;
130
+ }
131
+
84
132
  export async function sendChatMessage(
85
133
  message: string,
86
134
  imageDataUri?: string | null,
87
135
  audioDataUri?: string | null,
136
+ videoDataUri?: string | null,
88
137
  documentAttachment?: DocumentAttachment | null,
89
138
  workspacePath?: string | null,
90
139
  chatId?: string | null,
91
140
  agentId?: string | null,
92
141
  ): Promise<ChatResponse> {
93
- const outgoingMessage = withImagePlaceholder(message, imageDataUri)
142
+ const outgoingMessage = withImagePlaceholder(message, imageDataUri, videoDataUri)
94
143
  if (!isTauriRuntime()) {
95
144
  const API_BASE = getLocalApiBase();
96
145
  try {
97
146
  const res = await fetch(`${API_BASE}/chat`, {
98
147
  method: 'POST',
99
148
  headers: { 'Content-Type': 'application/json' },
100
- body: JSON.stringify({ message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, documentAttachment, agentId })
149
+ body: JSON.stringify({ message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, videoDataUri, documentAttachment, agentId })
101
150
  });
102
151
  const data = await res.json().catch(() => null);
103
152
  if (!res.ok) {
@@ -118,7 +167,7 @@ export async function sendChatMessage(
118
167
  }
119
168
  const { invoke } = await import('@tauri-apps/api/core')
120
169
  const response = await invoke<ChatResponse>('send_chat_message', {
121
- request: { message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, documentAttachment, workspacePath, agentId },
170
+ request: { message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, videoDataUri, documentAttachment, workspacePath, agentId },
122
171
  })
123
172
  if (imageDataUri) {
124
173
  await invoke('save_pictures', {
@@ -127,6 +176,13 @@ export async function sendChatMessage(
127
176
  message: outgoingMessage,
128
177
  })
129
178
  }
179
+ if (videoDataUri) {
180
+ await invoke('save_pictures', {
181
+ images: videoDataUri.split(' '),
182
+ source: 'chat',
183
+ message: outgoingMessage,
184
+ })
185
+ }
130
186
  return response
131
187
  }
132
188
 
@@ -135,6 +191,7 @@ export async function streamChatMessage(
135
191
  onChunk: (chunk: string) => void,
136
192
  imageDataUri?: string | null,
137
193
  audioDataUri?: string | null,
194
+ videoDataUri?: string | null,
138
195
  systemInstruction = '',
139
196
  onProgress?: (progress: AgentProgress) => void,
140
197
  documentAttachment?: DocumentAttachment | null,
@@ -144,11 +201,11 @@ export async function streamChatMessage(
144
201
  ): Promise<ChatResponse> {
145
202
  if (!isTauriRuntime()) {
146
203
  const API_BASE = getLocalApiBase();
147
- const outgoingMessage = withImagePlaceholder(message, imageDataUri);
204
+ const outgoingMessage = withImagePlaceholder(message, imageDataUri, videoDataUri);
148
205
  const res = await fetch(`${API_BASE}/chat-stream`, {
149
206
  method: 'POST',
150
207
  headers: { 'Content-Type': 'application/json' },
151
- body: JSON.stringify({ message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, documentAttachment, agentId })
208
+ body: JSON.stringify({ message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, videoDataUri, documentAttachment, agentId })
152
209
  });
153
210
  if (!res.ok) {
154
211
  const data = await res.json().catch(() => null);
@@ -187,14 +244,14 @@ export async function streamChatMessage(
187
244
  throw new Error("Stream closed without a final response");
188
245
  }
189
246
  const { invoke, Channel } = await import('@tauri-apps/api/core')
190
- const outgoingMessage = withImagePlaceholder(message, imageDataUri)
247
+ const outgoingMessage = withImagePlaceholder(message, imageDataUri, videoDataUri)
191
248
  const onEvent = new Channel<DesktopStreamEvent>()
192
249
  onEvent.onmessage = (event) => {
193
250
  if (event.type === 'chunk') onChunk(event.chunk)
194
251
  else onProgress?.(event.progress)
195
252
  }
196
253
  const response = await invoke<ChatResponse>('stream_chat_message', {
197
- request: { message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, documentAttachment, workspacePath, agentId },
254
+ request: { message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, videoDataUri, documentAttachment, workspacePath, agentId },
198
255
  onEvent,
199
256
  })
200
257
  if (imageDataUri) {
@@ -204,14 +261,29 @@ export async function streamChatMessage(
204
261
  message: outgoingMessage,
205
262
  })
206
263
  }
264
+ if (videoDataUri) {
265
+ await invoke('save_pictures', {
266
+ images: videoDataUri.split(' '),
267
+ source: 'chat',
268
+ message: outgoingMessage,
269
+ })
270
+ }
207
271
  return response
208
272
  }
209
273
 
210
- function withImagePlaceholder(message: string, imageDataUri?: string | null) {
211
- if (!imageDataUri || message.includes('[Image #1]')) return message
212
- const imageCount = imageDataUri.split(/\s+/).filter(Boolean).length
213
- const markers = Array.from({ length: imageCount }, (_, index) => `[Image #${index + 1}]`).join(' ')
214
- return markers ? `${message} ${markers}` : message
274
+ function withImagePlaceholder(message: string, imageDataUri?: string | null, videoDataUri?: string | null) {
275
+ let finalMessage = message
276
+ if (imageDataUri && !finalMessage.includes('[Image #1]')) {
277
+ const imageCount = imageDataUri.split(/\s+/).filter(Boolean).length
278
+ const markers = Array.from({ length: imageCount }, (_, index) => `[Image #${index + 1}]`).join(' ')
279
+ if (markers) finalMessage = `${finalMessage} ${markers}`
280
+ }
281
+ if (videoDataUri && !finalMessage.includes('[Video #1]')) {
282
+ const videoCount = videoDataUri.split(/\s+/).filter(Boolean).length
283
+ const markers = Array.from({ length: videoCount }, (_, index) => `[Video #${index + 1}]`).join(' ')
284
+ if (markers) finalMessage = `${finalMessage} ${markers}`
285
+ }
286
+ return finalMessage
215
287
  }
216
288
 
217
289
  export async function getTtsUrls(text: string): Promise<TtsUrl[]> {
@@ -254,6 +326,7 @@ export async function getRecentInteractions(limit = 50, chatId?: string | null):
254
326
  export async function saveSystemInteraction(
255
327
  chatId: string,
256
328
  userText: string,
329
+ aiText: string,
257
330
  provider: string,
258
331
  model: string,
259
332
  ): Promise<any> {
@@ -263,7 +336,7 @@ export async function saveSystemInteraction(
263
336
  const res = await fetch(`${API_BASE}/interactions`, {
264
337
  method: 'POST',
265
338
  headers: { 'Content-Type': 'application/json' },
266
- body: JSON.stringify({ chatId, userText, provider, model }),
339
+ body: JSON.stringify({ chatId, userText, aiText, provider, model }),
267
340
  });
268
341
  return await res.json();
269
342
  } catch (e) {
@@ -272,7 +345,7 @@ export async function saveSystemInteraction(
272
345
  }
273
346
  }
274
347
  const { invoke } = await import('@tauri-apps/api/core')
275
- return invoke('save_system_interaction', { chatId, userText, provider, model })
348
+ return invoke('save_system_interaction', { chatId, userText, aiText, provider, model })
276
349
  }
277
350
 
278
351
  export async function saveInteractionAgentActivity(
@@ -399,15 +472,20 @@ export interface LearnedSkill {
399
472
  }
400
473
 
401
474
  export async function listLearnedSkills(workspacePath?: string): Promise<LearnedSkill[]> {
402
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
475
+ if (typeof window === 'undefined' || !isTauriRuntime()) {
403
476
  try {
477
+ const API_BASE = getLocalApiBase()
478
+ const res = await fetch(`${API_BASE}/learned-skills`)
479
+ if (res.ok) {
480
+ return await res.json()
481
+ }
404
482
  const val = await getProfileValue('learned-skills-web-mock')
405
483
  if (val) {
406
484
  return JSON.parse(val)
407
485
  }
408
486
  return []
409
487
  } catch (e) {
410
- console.error("Failed to load web mock skills:", e)
488
+ console.error("Failed to load web skills:", e)
411
489
  return []
412
490
  }
413
491
  }
@@ -517,6 +595,9 @@ export async function generateImages(
517
595
  numImages: request.numImages ?? 1,
518
596
  model: request.model,
519
597
  provider: request.provider,
598
+ imageDataUri: request.imageDataUri,
599
+ maskDataUri: request.maskDataUri,
600
+ mode: request.mode,
520
601
  }),
521
602
  })
522
603
  if (!res.ok) {
@@ -1072,7 +1153,7 @@ export function installTauriAdapters() {
1072
1153
  }
1073
1154
 
1074
1155
  window.api = {
1075
- sendMessage: (message, imageDataUri, audioDataUri, documentAttachment) => sendChatMessage(message, imageDataUri, audioDataUri, documentAttachment),
1156
+ sendMessage: (message, imageDataUri, audioDataUri, documentAttachment) => sendChatMessage(message, imageDataUri, audioDataUri, undefined, documentAttachment),
1076
1157
  closeWindow: async () => {
1077
1158
  const { invoke } = await import('@tauri-apps/api/core')
1078
1159
  const { getCurrentWindow } = await import('@tauri-apps/api/window')
@@ -1229,6 +1310,52 @@ export async function readClipboardImage(): Promise<string | null> {
1229
1310
  }
1230
1311
  }
1231
1312
 
1313
+ // ─── Veo Studio — Video Generation (stub; real Tauri command in follow-up) ───
1314
+
1315
+ export interface VideoGenRequest {
1316
+ prompt: string
1317
+ negativePrompt?: string
1318
+ aspectRatio: '16:9' | '9:16' | '1:1'
1319
+ duration: 5 | 8
1320
+ model?: string
1321
+ provider: string
1322
+ }
1323
+
1324
+ export interface VideoGenEntry {
1325
+ id: string
1326
+ url: string
1327
+ path: string
1328
+ message?: string
1329
+ createdAt?: string
1330
+ }
1331
+
1332
+ export interface VideoGenResponse {
1333
+ videos: VideoGenEntry[]
1334
+ provider: string
1335
+ model: string
1336
+ description?: string
1337
+ }
1338
+
1339
+ export interface VideoGenProviders {
1340
+ active: string
1341
+ available: string[]
1342
+ }
1343
+
1344
+ /**
1345
+ * Generate a video using the configured provider.
1346
+ * NOTE: This is a frontend stub — the real Tauri backend command will be
1347
+ * added in a follow-up PR once the Veo REST API integration is ready.
1348
+ */
1349
+ export async function generateVideo(request: VideoGenRequest): Promise<VideoGenResponse> {
1350
+ const { invoke } = await import('@tauri-apps/api/core')
1351
+ return invoke<VideoGenResponse>('generate_video', { request })
1352
+ }
1353
+
1354
+ export async function getVideoGenProviders(): Promise<VideoGenProviders> {
1355
+ return { active: 'veo', available: ['veo'] }
1356
+ }
1357
+
1358
+
1232
1359
  // Enforce compile-time check against the shared platform interface
1233
1360
  const _apiCheck: MintPlatformApi = {
1234
1361
  getRuntimeStatus,