@pheem49/mint 1.7.1 → 1.8.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 (66) hide show
  1. package/.github/workflows/release.yml +1 -1
  2. package/Cargo.lock +34 -3
  3. package/Cargo.toml +2 -2
  4. package/README.md +40 -0
  5. package/Release_Note.md +95 -0
  6. package/assets/Mint_CLI.png +0 -0
  7. package/crates/mint-cli/Cargo.toml +1 -0
  8. package/crates/mint-cli/src/agent.rs +142 -48
  9. package/crates/mint-cli/src/main.rs +231 -22
  10. package/crates/mint-core/src/api_server.rs +71 -4
  11. package/crates/mint-core/src/browser.rs +401 -0
  12. package/crates/mint-core/src/chat.rs +79 -0
  13. package/crates/mint-core/src/config.rs +69 -1
  14. package/crates/mint-core/src/lib.rs +6 -1
  15. package/crates/mint-core/src/orchestration.rs +137 -1
  16. package/crates/mint-core/src/skills.rs +113 -4
  17. package/crates/mint-core/src/workflows.rs +9 -22
  18. package/package.json +2 -1
  19. package/src/renderer/src/App.tsx +1 -1
  20. package/src/renderer/src/components/ChatPanel.tsx +197 -47
  21. package/src/renderer/src/components/DashboardSidebar.tsx +71 -12
  22. package/src/renderer/src/components/ImageStudioPanel.tsx +18 -4
  23. package/src/renderer/src/components/MintDashboard.tsx +239 -7
  24. package/src/renderer/src/components/PicturesLibrary.tsx +1 -3
  25. package/src/renderer/src/components/Settings/AudioTab.tsx +97 -0
  26. package/src/renderer/src/components/Settings/AutomationTab.tsx +195 -0
  27. package/src/renderer/src/components/Settings/GeneralTab.tsx +950 -0
  28. package/src/renderer/src/components/Settings/MemoryTab.tsx +60 -0
  29. package/src/renderer/src/components/Settings/PluginsTab.tsx +632 -0
  30. package/src/renderer/src/components/Settings/ShortcutsTab.tsx +30 -0
  31. package/src/renderer/src/components/Settings/ThemeTab.tsx +129 -0
  32. package/src/renderer/src/components/SettingsWindow.tsx +175 -970
  33. package/src/renderer/src/components/WorkflowBuilderPanel.tsx +536 -0
  34. package/src/renderer/src/components/WorkflowsWindow.tsx +46 -0
  35. package/src/renderer/src/components/WorkspacePanel.tsx +66 -9
  36. package/src/renderer/src/css/image-studio.css +15 -4
  37. package/src/renderer/src/css/settings.css +75 -6
  38. package/src/renderer/src/css/styles.css +419 -49
  39. package/src/renderer/src/css/workflows.css +542 -0
  40. package/src/renderer/src/env.d.ts +2 -0
  41. package/src/renderer/src/index.css +13 -1
  42. package/src/renderer/src/tauri.ts +140 -2
  43. package/src/renderer/src-web/components/ChatPanel.tsx +190 -46
  44. package/src/renderer/src-web/components/DashboardSidebar.tsx +17 -1
  45. package/src/renderer/src-web/components/ImageStudioPanel.tsx +18 -4
  46. package/src/renderer/src-web/components/MintDashboard.tsx +197 -3
  47. package/src/renderer/src-web/components/PicturesLibrary.tsx +1 -3
  48. package/src/renderer/src-web/components/Settings/AudioTab.tsx +97 -0
  49. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +196 -0
  50. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +948 -0
  51. package/src/renderer/src-web/components/Settings/MemoryTab.tsx +60 -0
  52. package/src/renderer/src-web/components/Settings/PluginsTab.tsx +632 -0
  53. package/src/renderer/src-web/components/Settings/ShortcutsTab.tsx +30 -0
  54. package/src/renderer/src-web/components/Settings/ThemeTab.tsx +129 -0
  55. package/src/renderer/src-web/components/SettingsWindow.tsx +187 -976
  56. package/src/renderer/src-web/css/image-studio.css +15 -4
  57. package/src/renderer/src-web/css/settings.css +75 -6
  58. package/src/renderer/src-web/css/styles.css +394 -50
  59. package/src/renderer/src-web/env.d.ts +2 -0
  60. package/src/renderer/src-web/index.css +12 -1
  61. package/src/renderer/src-web/tauri.ts +60 -2
  62. package/src-tauri/src/browser.rs +1 -141
  63. package/src-tauri/src/headless.rs +3 -2
  64. package/src-tauri/src/lib.rs +195 -111
  65. package/src-tauri/src/workflows.rs +56 -4
  66. package/src-tauri/tauri.conf.json +1 -1
@@ -1,5 +1,5 @@
1
- import { useEffect, useState } from 'react'
2
- import { getWorkspaceTree, type WorkspaceTreeEntry } from '../tauri'
1
+ import React, { useEffect, useState } from 'react'
2
+ import { getWorkspaceTree, type WorkspaceTreeEntry, createWorkspaceFile, createWorkspaceFolder, deleteWorkspaceItem } from '../tauri'
3
3
  import folderIcon from 'material-icon-theme/icons/folder.svg?url'
4
4
  import folderOpenIcon from 'material-icon-theme/icons/folder-open.svg?url'
5
5
  import folderComponentsIcon from 'material-icon-theme/icons/folder-components.svg?url'
@@ -147,7 +147,7 @@ function materialFileIcon(name: string, fileExtension: string) {
147
147
  return FILE_ICONS_BY_NAME[name.toLowerCase()] || FILE_ICONS_BY_EXTENSION[fileExtension] || documentIcon
148
148
  }
149
149
 
150
- function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number; key?: string }) {
150
+ function TreeNode({ entry, level, onRefresh, workspacePath }: { entry: WorkspaceTreeEntry; level: number; onRefresh: () => void; workspacePath: string; key?: string }) {
151
151
  const [open, setOpen] = useState(level < 1)
152
152
  const isDirectory = entry.kind === 'directory'
153
153
  const hasChildren = entry.children.length > 0
@@ -156,6 +156,20 @@ function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number;
156
156
  const materialIcon = isDirectory ? materialFolderIcon(entry.name, open) : materialFileIcon(entry.name, fileExtension)
157
157
  const dragText = `@${entry.path}`
158
158
 
159
+ const handleContextMenu = async (event: React.MouseEvent) => {
160
+ event.preventDefault()
161
+ const confirmed = confirm(`Are you sure you want to delete "${entry.name}"?`)
162
+ if (!confirmed) return
163
+
164
+ try {
165
+ const absolutePath = `${workspacePath}/${entry.path}`
166
+ await deleteWorkspaceItem(absolutePath)
167
+ onRefresh()
168
+ } catch (err) {
169
+ alert(`Failed to delete item: ${err instanceof Error ? err.message : String(err)}`)
170
+ }
171
+ }
172
+
159
173
  return (
160
174
  <div className="workspace-tree-node">
161
175
  <button
@@ -163,6 +177,7 @@ function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number;
163
177
  className={`workspace-tree-row ${isDirectory ? 'is-directory' : 'is-file'}`}
164
178
  style={{ paddingLeft: `${level * 16 + 8}px` }}
165
179
  onClick={() => isDirectory && hasChildren && setOpen((current) => !current)}
180
+ onContextMenu={handleContextMenu}
166
181
  title={entry.path}
167
182
  draggable
168
183
  onDragStart={(event) => {
@@ -186,7 +201,7 @@ function TreeNode({ entry, level }: { entry: WorkspaceTreeEntry; level: number;
186
201
  {isDirectory && open && hasChildren && (
187
202
  <div className="workspace-tree-children">
188
203
  {entry.children.map((child) => (
189
- <TreeNode key={child.path} entry={child} level={level + 1} />
204
+ <TreeNode key={child.path} entry={child} level={level + 1} onRefresh={onRefresh} workspacePath={workspacePath} />
190
205
  ))}
191
206
  </div>
192
207
  )}
@@ -217,11 +232,52 @@ export default function WorkspacePanel({ agentMode, sending, workspacePath, onEn
217
232
 
218
233
  useEffect(() => {
219
234
  refresh()
235
+
236
+ // Refresh when the window gains focus (e.g., switching back from VS Code)
237
+ const handleFocus = () => {
238
+ refresh()
239
+ }
240
+ window.addEventListener('focus', handleFocus)
241
+
242
+ // Poll every 15 seconds to catch edits/updates in real-time
243
+ const interval = setInterval(() => {
244
+ refresh()
245
+ }, 15000)
246
+
247
+ return () => {
248
+ window.removeEventListener('focus', handleFocus)
249
+ clearInterval(interval)
250
+ }
220
251
  }, [workspacePath])
221
252
 
222
- const startWorkspacePrompt = () => {
223
- onEnableAgentMode()
224
- onSetMessage('Review this workspace and help plan next steps')
253
+ const handleCreateFile = async () => {
254
+ if (!workspacePath.trim()) return
255
+ const name = prompt('Enter name of new file:')
256
+ if (!name || !name.trim()) return
257
+
258
+ try {
259
+ setError('')
260
+ const fullPath = `${workspacePath}/${name.trim()}`
261
+ await createWorkspaceFile(fullPath)
262
+ await refresh()
263
+ } catch (err) {
264
+ setError(err instanceof Error ? err.message : String(err))
265
+ }
266
+ }
267
+
268
+ const handleCreateFolder = async () => {
269
+ if (!workspacePath.trim()) return
270
+ const name = prompt('Enter name of new folder:')
271
+ if (!name || !name.trim()) return
272
+
273
+ try {
274
+ setError('')
275
+ const fullPath = `${workspacePath}/${name.trim()}`
276
+ await createWorkspaceFolder(fullPath)
277
+ await refresh()
278
+ } catch (err) {
279
+ setError(err instanceof Error ? err.message : String(err))
280
+ }
225
281
  }
226
282
 
227
283
  return (
@@ -237,7 +293,8 @@ export default function WorkspacePanel({ agentMode, sending, workspacePath, onEn
237
293
  </header>
238
294
 
239
295
  <div className="workspace-panel-actions">
240
- <button type="button" onClick={startWorkspacePrompt}>Use Agent</button>
296
+ <button type="button" onClick={handleCreateFile} disabled={!workspacePath.trim()}>New File</button>
297
+ <button type="button" onClick={handleCreateFolder} disabled={!workspacePath.trim()}>New Folder</button>
241
298
  <button type="button" onClick={refresh} disabled={!workspacePath.trim()}>Refresh</button>
242
299
  </div>
243
300
 
@@ -255,7 +312,7 @@ export default function WorkspacePanel({ agentMode, sending, workspacePath, onEn
255
312
  </div>
256
313
  <div className="workspace-tree">
257
314
  {tree.children.map((entry) => (
258
- <TreeNode key={entry.path} entry={entry} level={0} />
315
+ <TreeNode key={entry.path} entry={entry} level={0} onRefresh={refresh} workspacePath={workspacePath} />
259
316
  ))}
260
317
  </div>
261
318
  </>
@@ -4,7 +4,7 @@
4
4
 
5
5
  /* Root panel: overlays the main content area, aligned with sidebar */
6
6
  .img-studio {
7
- display: none;
7
+ display: flex;
8
8
  position: absolute;
9
9
  top: 0;
10
10
  bottom: 0;
@@ -14,7 +14,10 @@
14
14
  overflow: hidden;
15
15
  background: var(--bg-gradient, radial-gradient(circle at top left, #064e3b, #111827 52%, #0b1020));
16
16
  z-index: 10;
17
- transition: left 0.22s ease;
17
+ opacity: 0;
18
+ pointer-events: none;
19
+ transform: translateY(12px) scale(0.995);
20
+ transition: left 0.22s ease, opacity 0.22s cubic-bezier(0.4, 0, 0.2, 1), transform 0.22s cubic-bezier(0.4, 0, 0.2, 1);
18
21
  }
19
22
 
20
23
  /* Adjust left position when the sidebar is collapsed */
@@ -23,8 +26,10 @@
23
26
  }
24
27
 
25
28
  /* Only visible when view === 'imagine' */
26
- .img-studio[id="image-studio-panel"]:not([hidden]) {
27
- display: flex;
29
+ .img-studio.is-visible {
30
+ opacity: 1;
31
+ pointer-events: auto;
32
+ transform: translateY(0) scale(1);
28
33
  }
29
34
 
30
35
  /* MintDashboard renders ImageStudioPanel always, use view prop to show/hide via :not class trick */
@@ -720,3 +725,9 @@
720
725
  overflow-y: auto;
721
726
  }
722
727
  }
728
+
729
+ @media (max-width: 760px) {
730
+ .img-studio {
731
+ left: 0 !important;
732
+ }
733
+ }
@@ -546,7 +546,7 @@ input[type="color"] {
546
546
  color: var(--text-main);
547
547
  }
548
548
 
549
- .toggle-switch {
549
+ .settings-toggle-switch {
550
550
  position: relative;
551
551
  display: inline-block;
552
552
  width: 46px;
@@ -554,13 +554,13 @@ input[type="color"] {
554
554
  height: 26px;
555
555
  }
556
556
 
557
- .toggle-switch input {
557
+ .settings-toggle-switch input {
558
558
  width: 0;
559
559
  height: 0;
560
560
  opacity: 0;
561
561
  }
562
562
 
563
- .toggle-slider {
563
+ .settings-toggle-slider {
564
564
  position: absolute;
565
565
  inset: 0;
566
566
  cursor: pointer;
@@ -570,7 +570,7 @@ input[type="color"] {
570
570
  transition: background 0.18s, border-color 0.18s;
571
571
  }
572
572
 
573
- .toggle-slider::before {
573
+ .settings-toggle-slider::before {
574
574
  position: absolute;
575
575
  content: "";
576
576
  width: 18px;
@@ -582,12 +582,12 @@ input[type="color"] {
582
582
  transition: transform 0.18s, background 0.18s;
583
583
  }
584
584
 
585
- input:checked + .toggle-slider {
585
+ input:checked + .settings-toggle-slider {
586
586
  background: var(--accent);
587
587
  border-color: var(--accent);
588
588
  }
589
589
 
590
- input:checked + .toggle-slider::before {
590
+ input:checked + .settings-toggle-slider::before {
591
591
  transform: translateX(20px);
592
592
  background: #ffffff;
593
593
  }
@@ -1064,4 +1064,73 @@ kbd {
1064
1064
  align-items: flex-start;
1065
1065
  }
1066
1066
 
1067
+ /* Provider Cards styling */
1068
+ .provider-cards-container {
1069
+ padding: 16px;
1070
+ display: flex;
1071
+ flex-direction: column;
1072
+ gap: 16px;
1073
+ }
1074
+
1075
+ .provider-card {
1076
+ border: 1px solid var(--border);
1077
+ border-radius: 12px;
1078
+ background: var(--surface-bg);
1079
+ padding: 16px;
1080
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
1081
+ }
1082
+
1083
+ .provider-card:hover {
1084
+ border-color: var(--border-strong);
1085
+ }
1086
+
1087
+ .provider-card.active-provider {
1088
+ border-color: var(--accent);
1089
+ box-shadow: 0 0 0 1px var(--accent);
1090
+ background: color-mix(in srgb, var(--accent) 2%, var(--surface-bg));
1091
+ }
1092
+
1093
+ .provider-card-header {
1094
+ display: flex;
1095
+ align-items: center;
1096
+ justify-content: space-between;
1097
+ margin-bottom: 12px;
1098
+ padding-bottom: 8px;
1099
+ border-bottom: 1px solid var(--border);
1100
+ }
1101
+
1102
+ .provider-card-title {
1103
+ font-size: 0.92rem;
1104
+ font-weight: 600;
1105
+ color: var(--text-main);
1106
+ display: flex;
1107
+ align-items: center;
1108
+ gap: 8px;
1109
+ }
1110
+
1111
+ .provider-active-badge {
1112
+ background: color-mix(in srgb, var(--accent) 15%, transparent);
1113
+ color: var(--accent-hover);
1114
+ border: 1px solid var(--accent);
1115
+ font-size: 0.7rem;
1116
+ font-weight: 600;
1117
+ padding: 2px 8px;
1118
+ border-radius: 20px;
1119
+ text-transform: uppercase;
1120
+ letter-spacing: 0.05em;
1121
+ }
1122
+
1123
+ .provider-card-body {
1124
+ display: flex;
1125
+ flex-direction: column;
1126
+ gap: 12px;
1127
+ }
1128
+
1129
+ .provider-card-body .setting-row {
1130
+ border-top: none;
1131
+ padding: 6px 0;
1132
+ grid-template-columns: 180px 1fr;
1133
+ }
1134
+
1135
+
1067
1136