@pheem49/mint 1.8.2 → 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 (106) hide show
  1. package/Cargo.lock +55 -3
  2. package/Cargo.toml +2 -1
  3. package/Release_Note.md +297 -107
  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 +382 -127
  8. package/crates/mint-cli/src/gmail.rs +22 -2
  9. package/crates/mint-cli/src/image.rs +8 -8
  10. package/crates/mint-cli/src/interactive.rs +2888 -0
  11. package/crates/mint-cli/src/main.rs +391 -2506
  12. package/crates/mint-cli/src/markdown.rs +294 -0
  13. package/crates/mint-cli/src/onboard.rs +152 -109
  14. package/crates/mint-cli/src/setup.rs +143 -143
  15. package/crates/mint-cli/src/updater.rs +48 -6
  16. package/crates/mint-core/Cargo.toml +1 -0
  17. package/crates/mint-core/src/agent_loop.rs +1 -0
  18. package/crates/mint-core/src/api_server.rs +431 -65
  19. package/crates/mint-core/src/browser.rs +630 -102
  20. package/crates/mint-core/src/channels.rs +105 -6
  21. package/crates/mint-core/src/chat.rs +174 -11
  22. package/crates/mint-core/src/code_tools.rs +47 -31
  23. package/crates/mint-core/src/config.rs +302 -17
  24. package/crates/mint-core/src/image_gen.rs +299 -38
  25. package/crates/mint-core/src/lib.rs +10 -7
  26. package/crates/mint-core/src/mcp.rs +119 -6
  27. package/crates/mint-core/src/memory.rs +6 -1
  28. package/crates/mint-core/src/orchestration.rs +237 -96
  29. package/crates/mint-core/src/pictures.rs +67 -5
  30. package/crates/mint-core/src/semantic.rs +1 -1
  31. package/crates/mint-core/src/shell.rs +1 -1
  32. package/crates/mint-core/src/skills.rs +128 -25
  33. package/crates/mint-core/src/video_gen.rs +235 -0
  34. package/package.json +8 -2
  35. package/shared-modules/linux-audio/fluidsynth2-static.json +9 -3
  36. package/shared-modules/linux-audio/fluidsynth2.json +8 -2
  37. package/shared-modules/linux-audio/lilv.json +26 -19
  38. package/shared-modules/linux-audio/lv2.json +0 -1
  39. package/shared-modules/luajit/luajit.json +2 -2
  40. package/skills-lock.json +41 -0
  41. package/src/renderer/index-web.html +1 -1
  42. package/src/renderer/index.html +1 -1
  43. package/src/renderer/shared/components/AgentActivityTable.tsx +25 -6
  44. package/src/renderer/shared/constants/slashCommands.ts +27 -0
  45. package/src/renderer/shared/platform.ts +3 -0
  46. package/src/renderer/shared/types.ts +4 -0
  47. package/src/renderer/shared/utils/approval.tsx +86 -7
  48. package/src/renderer/shared/utils/fileIcons.ts +135 -0
  49. package/src/renderer/shared/utils/markdown.tsx +217 -88
  50. package/src/renderer/shared/utils/slashCommandProcessor.ts +239 -0
  51. package/src/renderer/src/components/ChatPanel.tsx +486 -69
  52. package/src/renderer/src/components/DashboardSidebar.tsx +11 -2
  53. package/src/renderer/src/components/ImageStudioPanel.tsx +87 -4
  54. package/src/renderer/src/components/MintDashboard.tsx +195 -7
  55. package/src/renderer/src/components/PicturesLibrary.tsx +156 -15
  56. package/src/renderer/src/components/Settings/AgentsTab.tsx +21 -2
  57. package/src/renderer/src/components/Settings/AutomationTab.tsx +316 -18
  58. package/src/renderer/src/components/Settings/GeneralTab.tsx +795 -413
  59. package/src/renderer/src/components/Settings/PluginsTab.tsx +304 -70
  60. package/src/renderer/src/components/Settings/ThemeTab.tsx +6 -1
  61. package/src/renderer/src/components/SettingsWindow.tsx +106 -3
  62. package/src/renderer/src/components/VeoStudioPanel.tsx +549 -0
  63. package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
  64. package/src/renderer/src/css/image-studio.css +106 -0
  65. package/src/renderer/src/css/settings.css +158 -0
  66. package/src/renderer/src/css/styles.css +368 -1
  67. package/src/renderer/src/css/veo-studio.css +626 -0
  68. package/src/renderer/src/index.css +1 -0
  69. package/src/renderer/src/tauri.ts +144 -17
  70. package/src/renderer/src-web/components/ChatPanel.tsx +385 -93
  71. package/src/renderer/src-web/components/DashboardSidebar.tsx +16 -1
  72. package/src/renderer/src-web/components/ImageStudioPanel.tsx +87 -4
  73. package/src/renderer/src-web/components/MintDashboard.tsx +156 -5
  74. package/src/renderer/src-web/components/PicturesLibrary.tsx +155 -15
  75. package/src/renderer/src-web/components/Settings/AgentsTab.tsx +21 -2
  76. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +316 -18
  77. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +795 -411
  78. package/src/renderer/src-web/components/Settings/PluginsTab.tsx +304 -70
  79. package/src/renderer/src-web/components/Settings/ThemeTab.tsx +6 -1
  80. package/src/renderer/src-web/components/SettingsWindow.tsx +110 -3
  81. package/src/renderer/src-web/components/VeoStudioPanel.tsx +549 -0
  82. package/src/renderer/src-web/css/image-studio.css +106 -0
  83. package/src/renderer/src-web/css/settings.css +158 -0
  84. package/src/renderer/src-web/css/styles.css +369 -1
  85. package/src/renderer/src-web/css/veo-studio.css +650 -0
  86. package/src/renderer/src-web/index.css +1 -0
  87. package/src/renderer/src-web/tauri.ts +135 -16
  88. package/src-tauri/src/desktop.rs +18 -16
  89. package/src-tauri/src/discord_rpc.rs +1 -1
  90. package/src-tauri/src/lib.rs +155 -25
  91. package/src-tauri/src/webhooks.rs +45 -31
  92. package/src-tauri/src/workflows.rs +1 -0
  93. package/src-tauri/tauri.conf.json +1 -1
  94. package/temp_gridgeist/AGENTS.md +8 -0
  95. package/temp_gridgeist/CHANGELOG.md +130 -0
  96. package/temp_gridgeist/LICENSE +21 -0
  97. package/temp_gridgeist/README.md +323 -0
  98. package/temp_gridgeist/README.th.md +325 -0
  99. package/temp_gridgeist/skills/gridgeist/SKILL.md +88 -0
  100. package/temp_gridgeist/skills/gridgeist/agents/openai.yaml +9 -0
  101. package/temp_gridgeist/skills/gridgeist/assets/gridgeist-small.svg +10 -0
  102. package/temp_gridgeist/skills/gridgeist/assets/gridgeist.png +0 -0
  103. package/temp_gridgeist/skills/gridgeist/assets/gridgeist.svg +18 -0
  104. package/temp_gridgeist/skills/gridgeist/references/design-language.md +88 -0
  105. package/temp_gridgeist/skills/gridgeist/references/review-checklist.md +128 -0
  106. package/temp_gridgeist/skills/gridgeist/references/system-contract.md +109 -0
@@ -2,7 +2,10 @@ use std::{
2
2
  collections::BTreeMap,
3
3
  io::{BufRead, BufReader, Write},
4
4
  process::{Child, Command, Stdio},
5
- sync::mpsc,
5
+ sync::{
6
+ atomic::{AtomicBool, Ordering},
7
+ mpsc,
8
+ },
6
9
  time::{Duration, Instant},
7
10
  };
8
11
 
@@ -12,7 +15,8 @@ use thiserror::Error;
12
15
 
13
16
  use crate::{ConfigError, MintConfig, load_config, save_config};
14
17
 
15
- const MCP_TIMEOUT: Duration = Duration::from_secs(10);
18
+ const MCP_TIMEOUT: Duration = Duration::from_secs(30);
19
+ static OAUTH_DETECTED: AtomicBool = AtomicBool::new(false);
16
20
 
17
21
  #[derive(Debug, Clone, Deserialize, Serialize)]
18
22
  pub struct McpServer {
@@ -21,6 +25,8 @@ pub struct McpServer {
21
25
  pub args: Vec<String>,
22
26
  #[serde(default)]
23
27
  pub env: BTreeMap<String, String>,
28
+ #[serde(default, skip_serializing_if = "Option::is_none")]
29
+ pub icon: Option<String>,
24
30
  }
25
31
 
26
32
  #[derive(Debug, Error)]
@@ -33,7 +39,9 @@ pub enum McpError {
33
39
  InvalidEnvironment,
34
40
  #[error("MCP server '{0}' is not configured")]
35
41
  MissingServer(String),
36
- #[error("MCP tool '{server}/{tool}' is not allowed by policy")]
42
+ #[error(
43
+ "MCP tool '{server}/{tool}' is not allowed by policy. To allow it, please run: /mcp allow {server} {tool} (or /mcp allow {server} * to allow all tools on this server)"
44
+ )]
37
45
  NotAllowed { server: String, tool: String },
38
46
  #[error("unable to start MCP server '{command}': {source}")]
39
47
  Start {
@@ -82,6 +90,7 @@ pub fn add_mcp_server(
82
90
  command: command.into(),
83
91
  args,
84
92
  env: parse_env(env)?,
93
+ icon: None,
85
94
  },
86
95
  );
87
96
  save_mcp_servers(&mut config, servers)
@@ -186,18 +195,86 @@ fn parse_env(values: Vec<String>) -> Result<BTreeMap<String, String>, McpError>
186
195
  .collect()
187
196
  }
188
197
 
198
+ fn find_url(line: &str) -> Option<String> {
199
+ let start_idx = line.find("http://").or_else(|| line.find("https://"))?;
200
+ let rest = &line[start_idx..];
201
+ let end_idx = rest
202
+ .find(|c: char| c.is_whitespace() || c == '"' || c == '\'' || c == '<' || c == '>')
203
+ .unwrap_or(rest.len());
204
+ let url = rest[..end_idx].to_string();
205
+
206
+ let lower = url.to_lowercase();
207
+ if lower.contains("registry.npmjs.org")
208
+ || lower.contains("npmjs.com")
209
+ || lower.contains("github.com/modelcontextprotocol")
210
+ {
211
+ return None;
212
+ }
213
+
214
+ if lower.contains("oauth")
215
+ || lower.contains("auth")
216
+ || lower.contains("login")
217
+ || lower.contains("google.com")
218
+ || lower.contains("authorize")
219
+ {
220
+ Some(url)
221
+ } else {
222
+ None
223
+ }
224
+ }
225
+
226
+ fn open_url_in_browser(url: &str) -> std::io::Result<()> {
227
+ #[cfg(target_os = "linux")]
228
+ {
229
+ Command::new("xdg-open").arg(url).spawn().map(|_| ())
230
+ }
231
+ #[cfg(target_os = "macos")]
232
+ {
233
+ Command::new("open").arg(url).spawn().map(|_| ())
234
+ }
235
+ #[cfg(target_os = "windows")]
236
+ {
237
+ Command::new("cmd")
238
+ .args(&["/C", "start", url])
239
+ .spawn()
240
+ .map(|_| ())
241
+ }
242
+ #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
243
+ {
244
+ let _ = url;
245
+ Ok(())
246
+ }
247
+ }
248
+
189
249
  fn start_server(server: &McpServer) -> Result<Child, McpError> {
190
250
  let mut process = Command::new(&server.command)
191
251
  .args(&server.args)
192
252
  .envs(&server.env)
193
253
  .stdin(Stdio::piped())
194
254
  .stdout(Stdio::piped())
195
- .stderr(Stdio::null())
255
+ .stderr(Stdio::piped())
196
256
  .spawn()
197
257
  .map_err(|source| McpError::Start {
198
258
  command: server.command.clone(),
199
259
  source,
200
260
  })?;
261
+
262
+ if let Some(stderr) = process.stderr.take() {
263
+ std::thread::spawn(move || {
264
+ let reader = BufReader::new(stderr);
265
+ for line in reader.lines().map_while(Result::ok) {
266
+ if let Some(url) = find_url(&line) {
267
+ println!(
268
+ "\n\x1b[1;33m[MCP Authorization Needed]\x1b[0m Opening browser to authenticate: {}\n",
269
+ url
270
+ );
271
+ OAUTH_DETECTED.store(true, Ordering::Relaxed);
272
+ let _ = open_url_in_browser(&url);
273
+ }
274
+ }
275
+ });
276
+ }
277
+
201
278
  write_message(
202
279
  &mut process,
203
280
  &json!({
@@ -224,26 +301,62 @@ fn exchange(process: &mut Child, request: Value) -> Result<Value, McpError> {
224
301
  let (sender, receiver) = mpsc::channel();
225
302
  std::thread::spawn(move || {
226
303
  for line in BufReader::new(stdout).lines().map_while(Result::ok) {
304
+ if let Some(url) = find_url(&line) {
305
+ println!(
306
+ "\n\x1b[1;33m[MCP Authorization Needed]\x1b[0m Opening browser to authenticate: {}\n",
307
+ url
308
+ );
309
+ OAUTH_DETECTED.store(true, Ordering::Relaxed);
310
+ let _ = open_url_in_browser(&url);
311
+ }
227
312
  if let Ok(value) = serde_json::from_str::<Value>(&line) {
228
313
  let _ = sender.send(value);
229
314
  }
230
315
  }
231
316
  });
317
+
318
+ let timeout = if OAUTH_DETECTED.load(Ordering::Relaxed) {
319
+ Duration::from_secs(120)
320
+ } else {
321
+ MCP_TIMEOUT
322
+ };
323
+
232
324
  let started = Instant::now();
233
- while started.elapsed() < MCP_TIMEOUT {
325
+ while started.elapsed() < timeout {
234
326
  let response = receiver
235
- .recv_timeout(MCP_TIMEOUT.saturating_sub(started.elapsed()))
327
+ .recv_timeout(timeout.saturating_sub(started.elapsed()))
236
328
  .map_err(|_| McpError::Timeout)?;
237
329
  if response["id"] == 2 {
330
+ OAUTH_DETECTED.store(false, Ordering::Relaxed);
238
331
  if let Some(error) = response.get("error") {
239
332
  return Err(McpError::Tool(error.clone()));
240
333
  }
241
334
  return Ok(response.get("result").cloned().unwrap_or(Value::Null));
242
335
  }
243
336
  }
337
+ OAUTH_DETECTED.store(false, Ordering::Relaxed);
244
338
  Err(McpError::Timeout)
245
339
  }
246
340
 
341
+ pub fn list_server_tools(config: &MintConfig, server_name: &str) -> Result<Value, McpError> {
342
+ let servers = configured_mcp_servers(config)?;
343
+ let server = servers
344
+ .get(server_name)
345
+ .ok_or_else(|| McpError::MissingServer(server_name.into()))?;
346
+ let mut process = start_server(server)?;
347
+ let result = exchange(
348
+ &mut process,
349
+ json!({
350
+ "jsonrpc": "2.0",
351
+ "id": 2,
352
+ "method": "tools/list",
353
+ "params": {}
354
+ }),
355
+ );
356
+ let _ = process.kill();
357
+ result
358
+ }
359
+
247
360
  fn write_message(process: &mut Child, message: &Value) -> Result<(), McpError> {
248
361
  let stdin = process.stdin.as_mut().ok_or(McpError::MissingStdin)?;
249
362
  writeln!(stdin, "{message}").map_err(McpError::Write)?;
@@ -58,6 +58,8 @@ pub struct LearnedSkill {
58
58
  pub source_path: String,
59
59
  pub content: String,
60
60
  pub created_at: String,
61
+ #[serde(default)]
62
+ pub description: Option<String>,
61
63
  }
62
64
 
63
65
  #[derive(Debug, Clone, Serialize, PartialEq, Eq)]
@@ -624,12 +626,15 @@ fn ensure_column(
624
626
  }
625
627
 
626
628
  fn learned_skill_row(row: &rusqlite::Row<'_>) -> Result<LearnedSkill, rusqlite::Error> {
629
+ let content: String = row.get(3)?;
630
+ let description = crate::skills::parse_skill_description(&content);
627
631
  Ok(LearnedSkill {
628
632
  id: row.get(0)?,
629
633
  name: row.get(1)?,
630
634
  source_path: row.get(2)?,
631
- content: row.get(3)?,
635
+ content,
632
636
  created_at: row.get(4)?,
637
+ description,
633
638
  })
634
639
  }
635
640