@pheem49/mint 1.8.1 → 1.9.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 (200) hide show
  1. package/Cargo.lock +3 -3
  2. package/Cargo.toml +1 -1
  3. package/README.md +0 -17
  4. package/Release_Note.md +137 -58
  5. package/bin/mint +0 -0
  6. package/crates/mint-cli/src/agent.rs +150 -45
  7. package/crates/mint-cli/src/image.rs +8 -8
  8. package/crates/mint-cli/src/main.rs +929 -412
  9. package/crates/mint-cli/src/onboard.rs +108 -108
  10. package/crates/mint-cli/src/setup.rs +143 -143
  11. package/crates/mint-core/src/agent_loop.rs +1 -0
  12. package/crates/mint-core/src/api_server.rs +108 -52
  13. package/crates/mint-core/src/browser.rs +56 -1
  14. package/crates/mint-core/src/channels.rs +1 -0
  15. package/crates/mint-core/src/chat.rs +126 -8
  16. package/crates/mint-core/src/code_tools.rs +18 -20
  17. package/crates/mint-core/src/config.rs +245 -17
  18. package/crates/mint-core/src/image_gen.rs +5 -5
  19. package/crates/mint-core/src/lib.rs +16 -2
  20. package/crates/mint-core/src/memory.rs +6 -1
  21. package/crates/mint-core/src/orchestration.rs +260 -72
  22. package/crates/mint-core/src/pictures.rs +3 -4
  23. package/crates/mint-core/src/semantic.rs +1 -1
  24. package/crates/mint-core/src/shell.rs +1 -1
  25. package/crates/mint-core/src/skills.rs +46 -19
  26. package/crates/mint-core/src/tts.rs +3 -1
  27. package/flatpak/com.pheem49.mint.desktop +9 -0
  28. package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
  29. package/flatpak/com.pheem49.mint.yaml +52 -0
  30. package/package.json +1 -1
  31. package/shared-modules/.github/workflows/ci.yml +120 -0
  32. package/shared-modules/.github/workflows/update.yaml +28 -0
  33. package/shared-modules/CODEOWNERS +23 -0
  34. package/shared-modules/README.md +79 -0
  35. package/shared-modules/SDL/README.md +3 -0
  36. package/shared-modules/SDL/SDL-1.2.15.json +51 -0
  37. package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
  38. package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
  39. package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
  40. package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
  41. package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
  42. package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
  43. package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
  44. package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
  45. package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
  46. package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
  47. package/shared-modules/SDL/sdl12-compat.json +22 -0
  48. package/shared-modules/SDL2/SDL2_image.json +27 -0
  49. package/shared-modules/SDL2/SDL2_ttf.json +29 -0
  50. package/shared-modules/cld2/CMakeLists.txt +157 -0
  51. package/shared-modules/cld2/cld2.json +24 -0
  52. package/shared-modules/clutter/clutter.json +72 -0
  53. package/shared-modules/dbus-glib/dbus-glib.json +29 -0
  54. package/shared-modules/glew/glew.json +36 -0
  55. package/shared-modules/glu/glu-9.json +12 -0
  56. package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
  57. package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
  58. package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
  59. package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
  60. package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
  61. package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
  62. package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
  63. package/shared-modules/gtk2/gtk2.json +120 -0
  64. package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
  65. package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
  66. package/shared-modules/gtk2/readme.md +10 -0
  67. package/shared-modules/intltool/intltool-0.51.json +20 -0
  68. package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
  69. package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
  70. package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
  71. package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
  72. package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
  73. package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
  74. package/shared-modules/lame/lame-3.99.5.json +32 -0
  75. package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
  76. package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
  77. package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
  78. package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
  79. package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
  80. package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
  81. package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
  82. package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
  83. package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
  84. package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
  85. package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
  86. package/shared-modules/libcanberra/libcanberra.json +44 -0
  87. package/shared-modules/libmad/libmad.json +19 -0
  88. package/shared-modules/libsecret/libsecret.json +23 -0
  89. package/shared-modules/libsoup/libsoup-2.4.json +14 -0
  90. package/shared-modules/libusb/libusb.json +27 -0
  91. package/shared-modules/linux-audio/dssi.json +31 -0
  92. package/shared-modules/linux-audio/fftw3f-static.json +44 -0
  93. package/shared-modules/linux-audio/fftw3f.json +42 -0
  94. package/shared-modules/linux-audio/fluidsynth2-static.json +36 -0
  95. package/shared-modules/linux-audio/fluidsynth2.json +25 -0
  96. package/shared-modules/linux-audio/ladspa.json +26 -0
  97. package/shared-modules/linux-audio/lash.json +35 -0
  98. package/shared-modules/linux-audio/libinstpatch.json +16 -0
  99. package/shared-modules/linux-audio/liblo-static.json +22 -0
  100. package/shared-modules/linux-audio/liblo.json +17 -0
  101. package/shared-modules/linux-audio/lilv-static.json +94 -0
  102. package/shared-modules/linux-audio/lilv.json +89 -0
  103. package/shared-modules/linux-audio/lrdf.json +57 -0
  104. package/shared-modules/linux-audio/lv2.json +20 -0
  105. package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
  106. package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
  107. package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
  108. package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
  109. package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
  110. package/shared-modules/linux-audio/stk.json +28 -0
  111. package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
  112. package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
  113. package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
  114. package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
  115. package/shared-modules/lua5.3/lua.pc.in +8 -0
  116. package/shared-modules/lua5.3/luaconf.patch +47 -0
  117. package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
  118. package/shared-modules/lua5.4/lua-5.4.json +41 -0
  119. package/shared-modules/lua5.4/lua.pc.in +8 -0
  120. package/shared-modules/lua5.4/luaconf.patch +34 -0
  121. package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
  122. package/shared-modules/luajit/luajit.json +30 -0
  123. package/shared-modules/lzo/lzo.json +27 -0
  124. package/shared-modules/mac/mac.json +18 -0
  125. package/shared-modules/physfs/physfs.json +26 -0
  126. package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
  127. package/shared-modules/pygame/cython-fixes.patch +34 -0
  128. package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
  129. package/shared-modules/pygame/glib.patch +25 -0
  130. package/shared-modules/pygame/pygame1-python2.json +157 -0
  131. package/shared-modules/pygtk/pygtk-c99.patch +15 -0
  132. package/shared-modules/pygtk/pygtk.json +117 -0
  133. package/shared-modules/pygtk/pygtk.patch +39 -0
  134. package/shared-modules/python2.7/python-2.7.json +48 -0
  135. package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
  136. package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
  137. package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
  138. package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
  139. package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
  140. package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
  141. package/shared-modules/update-checker.sh +50 -0
  142. package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
  143. package/shared-modules/vorbisgain/0002-errno.patch +33 -0
  144. package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
  145. package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
  146. package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
  147. package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
  148. package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
  149. package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
  150. package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
  151. package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
  152. package/shared-modules/vorbisgain/README.md +23 -0
  153. package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
  154. package/src/renderer/shared/agentProgress.ts +145 -0
  155. package/src/renderer/shared/calculator.ts +52 -0
  156. package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
  157. package/src/renderer/shared/components/AgentActivityTable.tsx +85 -0
  158. package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
  159. package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
  160. package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
  161. package/src/renderer/shared/constants/models.ts +91 -0
  162. package/src/renderer/shared/platform.ts +82 -0
  163. package/src/renderer/shared/types.ts +140 -0
  164. package/src/renderer/shared/utils/agentActivity.ts +187 -0
  165. package/src/renderer/shared/utils/approval.ts +1 -0
  166. package/src/renderer/shared/utils/approval.tsx +64 -0
  167. package/src/renderer/shared/utils/fileIcons.ts +135 -0
  168. package/src/renderer/shared/utils/markdown.tsx +347 -0
  169. package/src/renderer/shared/utils/providers.ts +36 -0
  170. package/src/renderer/shared/utils/speech.ts +216 -0
  171. package/src/renderer/shared/utils/ui.ts +147 -0
  172. package/src/renderer/src/agentProgress.ts +11 -39
  173. package/src/renderer/src/calculator.ts +3 -46
  174. package/src/renderer/src/components/ChatPanel.tsx +219 -1308
  175. package/src/renderer/src/components/MintDashboard.tsx +67 -170
  176. package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
  177. package/src/renderer/src/components/Settings/AgentsTab.tsx +381 -0
  178. package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
  179. package/src/renderer/src/components/Settings/GeneralTab.tsx +256 -2
  180. package/src/renderer/src/components/SettingsWindow.tsx +120 -3
  181. package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
  182. package/src/renderer/src/css/styles.css +100 -0
  183. package/src/renderer/src/tauri.ts +128 -143
  184. package/src/renderer/src-web/agentProgress.ts +11 -39
  185. package/src/renderer/src-web/calculator.ts +3 -46
  186. package/src/renderer/src-web/components/ChatPanel.tsx +219 -1306
  187. package/src/renderer/src-web/components/MintDashboard.tsx +42 -170
  188. package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
  189. package/src/renderer/src-web/components/Settings/AgentsTab.tsx +381 -0
  190. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
  191. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +254 -3
  192. package/src/renderer/src-web/components/SettingsWindow.tsx +127 -3
  193. package/src/renderer/src-web/css/styles.css +100 -0
  194. package/src/renderer/src-web/tauri.ts +180 -102
  195. package/src-tauri/src/desktop.rs +18 -16
  196. package/src-tauri/src/discord_rpc.rs +1 -1
  197. package/src-tauri/src/lib.rs +168 -40
  198. package/src-tauri/src/webhooks.rs +1 -0
  199. package/src-tauri/src/workflows.rs +1 -0
  200. package/src-tauri/tauri.conf.json +1 -1
@@ -1670,12 +1670,28 @@ h1 {
1670
1670
  width: 15px;
1671
1671
  }
1672
1672
 
1673
+ .agent-activity-icon[data-has-img="true"]::before,
1674
+ .agent-activity-icon[data-has-img="true"]::after {
1675
+ display: none !important;
1676
+ }
1677
+
1678
+ .agent-activity-icon img {
1679
+ width: 14px;
1680
+ height: 14px;
1681
+ display: block;
1682
+ object-fit: contain;
1683
+ filter: drop-shadow(0 1px 0 rgba(0, 0, 0, 0.12));
1684
+ pointer-events: none;
1685
+ user-select: none;
1686
+ }
1687
+
1673
1688
  .agent-activity-icon::before,
1674
1689
  .agent-activity-icon::after {
1675
1690
  content: "";
1676
1691
  position: absolute;
1677
1692
  }
1678
1693
 
1694
+
1679
1695
  .agent-activity-item[data-kind="folder"] .agent-activity-icon::before {
1680
1696
  background: var(--text-muted);
1681
1697
  border-radius: 2px 2px 1px 1px;
@@ -4292,3 +4308,87 @@ input:checked + .slider:before {
4292
4308
  -ms-user-select: text !important;
4293
4309
  }
4294
4310
 
4311
+ /* Stop button styling overrides for ChatPanel */
4312
+ #send-btn.stop-btn {
4313
+ background: #ef4444 !important;
4314
+ color: #ffffff !important;
4315
+ box-shadow: 0 8px 18px rgba(239, 68, 68, 0.28) !important;
4316
+ }
4317
+
4318
+ #send-btn.stop-btn:hover {
4319
+ background: #dc2626 !important;
4320
+ }
4321
+
4322
+ /* Breathing voice-active aura glow */
4323
+ @keyframes aura-breathe-form {
4324
+ 0% {
4325
+ box-shadow: 0 4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
4326
+ }
4327
+ 50% {
4328
+ box-shadow: 0 4px 25px color-mix(in srgb, var(--accent) 42%, transparent);
4329
+ }
4330
+ 100% {
4331
+ box-shadow: 0 4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
4332
+ }
4333
+ }
4334
+
4335
+ @keyframes aura-breathe-bar {
4336
+ 0% {
4337
+ box-shadow: 0 -4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
4338
+ }
4339
+ 50% {
4340
+ box-shadow: 0 -4px 25px color-mix(in srgb, var(--accent) 42%, transparent);
4341
+ }
4342
+ 100% {
4343
+ box-shadow: 0 -4px 15px color-mix(in srgb, var(--accent) 22%, transparent);
4344
+ }
4345
+ }
4346
+
4347
+ .input-area.voice-active #chat-form {
4348
+ border-color: var(--accent) !important;
4349
+ animation: aura-breathe-form 2s infinite ease-in-out;
4350
+ transition: border-color 0.3s ease;
4351
+ }
4352
+
4353
+ .input-area.voice-active .voice-mode-bar {
4354
+ border-color: var(--accent) !important;
4355
+ animation: aura-breathe-bar 2s infinite ease-in-out;
4356
+ transition: border-color 0.3s ease;
4357
+ }
4358
+
4359
+ /* Saved Pictures Gallery Load More styles */
4360
+ .pictures-load-more-container {
4361
+ display: flex;
4362
+ justify-content: center;
4363
+ margin-top: 36px;
4364
+ margin-bottom: 24px;
4365
+ }
4366
+
4367
+ .pictures-load-more-btn {
4368
+ height: 40px;
4369
+ padding: 0 24px;
4370
+ border: 1px solid var(--border);
4371
+ border-radius: 10px;
4372
+ background: var(--card-bg, rgba(255, 255, 255, 0.04));
4373
+ color: var(--text-main);
4374
+ font-size: 0.88rem;
4375
+ font-weight: 500;
4376
+ cursor: pointer;
4377
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
4378
+ display: flex;
4379
+ align-items: center;
4380
+ gap: 8px;
4381
+ }
4382
+
4383
+ .pictures-load-more-btn:hover {
4384
+ background: var(--border);
4385
+ border-color: var(--accent);
4386
+ color: var(--accent);
4387
+ box-shadow: 0 0 12px color-mix(in srgb, var(--accent) 20%, transparent);
4388
+ }
4389
+
4390
+ .pictures-load-more-btn:active {
4391
+ transform: scale(0.98);
4392
+ }
4393
+
4394
+
@@ -1,115 +1,46 @@
1
- export interface RuntimeStatus {
2
- backend: string
3
- configPath: string
4
- activeProvider: string
5
- availableProviders: string[]
6
- integrations: Record<string, unknown>
1
+ /** Returns true when running inside the Tauri webview (desktop app). */
2
+ export const isTauriRuntime = (): boolean =>
3
+ typeof window !== 'undefined' && Boolean((window as any).__TAURI_INTERNALS__)
4
+
5
+ /**
6
+ * Returns the local API base URL.
7
+ * Uses the current hostname so LAN access (e.g. from another device) works correctly.
8
+ * Mirrors the same helper in src-web/tauri.ts.
9
+ */
10
+ export const getLocalApiBase = (): string => {
11
+ const host = typeof window !== 'undefined' ? window.location.hostname : 'localhost'
12
+ return `http://${host}:3000/api`
7
13
  }
8
14
 
9
- export interface ChatResponse {
10
- provider: string
11
- model: string
12
- text: string
13
- fallbackProvider?: string | null
14
- }
15
-
16
- export interface TtsUrl {
17
- shortText: string
18
- url: string
19
- }
15
+ export * from '../shared/types'
16
+ import type { MintPlatformApi } from '../shared/platform'
17
+ import type {
18
+
19
+ RuntimeStatus,
20
+ ChatResponse,
21
+ TtsUrl,
22
+ DocumentAttachment,
23
+ AgentProgress,
24
+ InteractionMemory,
25
+ ChatSession,
26
+ PictureEntry,
27
+ ImageGenRequest,
28
+ ImageGenProviders,
29
+ ImageGenResponse,
30
+ WorkspaceTreeEntry,
31
+ CodeEdit,
32
+ CodeEditProposal,
33
+ } from '../shared/types'
20
34
 
21
- export interface DocumentAttachment {
22
- filename: string
23
- dataUri: string
24
- }
25
-
26
- export type AgentProgress =
27
- | { type: 'Thinking'; data: { elapsed_secs: number } }
28
- | { type: 'Thought'; data: { thought: string } }
29
- | { type: 'ToolStart'; data: { action: string; input: Record<string, unknown> } }
30
- | { type: 'ToolEnd'; data: { action: string; input: Record<string, unknown>; result: string } }
31
35
 
32
36
  type DesktopStreamEvent =
33
37
  | { type: 'chunk'; chunk: string }
34
38
  | { type: 'progress'; progress: AgentProgress }
35
39
 
36
- export interface InteractionMemory {
37
- id: number
38
- chatId: string
39
- userText: string
40
- aiText: string
41
- provider: string
42
- model: string
43
- fallbackProvider?: string | null
44
- createdAt: string
45
- agentActivity?: AgentProgress[] | null
46
- }
47
-
48
- export interface ChatSession {
49
- id: string
50
- title: string
51
- kind: string
52
- createdAt: string
53
- updatedAt: string
54
- }
55
-
56
- export interface PictureEntry {
57
- id: string
58
- filename: string
59
- path: string
60
- mimeType: string
61
- createdAt: string
62
- source: string
63
- message: string
64
- thumbnailPath?: string
65
- url?: string
66
- thumbnailUrl?: string
67
- }
68
-
69
- export interface ImageGenRequest {
70
- prompt: string
71
- negativePrompt?: string
72
- aspectRatio?: '1:1' | '16:9' | '9:16' | '4:3'
73
- numImages?: number
74
- model?: string
75
- /** Which image generation provider to use. Falls back to config default when omitted. */
76
- provider?: string
77
- }
78
-
79
- export interface ImageGenProviders {
80
- active: string
81
- available: string[]
82
- }
83
-
84
- export interface ImageGenResponse {
85
- images: PictureEntry[]
86
- model: string
87
- provider: string
88
- prompt: string
89
- description?: string | null
90
- }
91
-
92
- export interface WorkspaceTreeEntry {
93
- name: string
94
- path: string
95
- kind: 'file' | 'directory'
96
- children: WorkspaceTreeEntry[]
97
- }
98
-
99
- export interface CodeEdit {
100
- path: string
101
- content: string
102
- }
103
-
104
- export interface CodeEditProposal {
105
- approvalRequired: boolean
106
- approvalToken: string
107
- edits: Array<{ path: string; existed: boolean; diff: string }>
108
- }
109
40
 
110
41
  export async function getRuntimeStatus(): Promise<RuntimeStatus> {
111
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
112
- const API_BASE = "http://localhost:3000/api";
42
+ if (!isTauriRuntime()) {
43
+ const API_BASE = getLocalApiBase();
113
44
  try {
114
45
  const res = await fetch(`${API_BASE}/status`);
115
46
  return await res.json();
@@ -136,8 +67,8 @@ export interface DetectedTools {
136
67
  }
137
68
 
138
69
  export async function detectSystemTools(): Promise<DetectedTools> {
139
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
140
- const API_BASE = "http://localhost:3000/api";
70
+ if (!isTauriRuntime()) {
71
+ const API_BASE = getLocalApiBase();
141
72
  try {
142
73
  const res = await fetch(`${API_BASE}/detect-tools`);
143
74
  return await res.json();
@@ -157,15 +88,16 @@ export async function sendChatMessage(
157
88
  documentAttachment?: DocumentAttachment | null,
158
89
  workspacePath?: string | null,
159
90
  chatId?: string | null,
91
+ agentId?: string | null,
160
92
  ): Promise<ChatResponse> {
161
93
  const outgoingMessage = withImagePlaceholder(message, imageDataUri)
162
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
163
- const API_BASE = "http://localhost:3000/api";
94
+ if (!isTauriRuntime()) {
95
+ const API_BASE = getLocalApiBase();
164
96
  try {
165
97
  const res = await fetch(`${API_BASE}/chat`, {
166
98
  method: 'POST',
167
99
  headers: { 'Content-Type': 'application/json' },
168
- body: JSON.stringify({ message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, documentAttachment })
100
+ body: JSON.stringify({ message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, documentAttachment, agentId })
169
101
  });
170
102
  const data = await res.json().catch(() => null);
171
103
  if (!res.ok) {
@@ -186,7 +118,7 @@ export async function sendChatMessage(
186
118
  }
187
119
  const { invoke } = await import('@tauri-apps/api/core')
188
120
  const response = await invoke<ChatResponse>('send_chat_message', {
189
- request: { message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, documentAttachment, workspacePath },
121
+ request: { message: outgoingMessage, systemInstruction: '', chatId, imageDataUri, audioDataUri, documentAttachment, workspacePath, agentId },
190
122
  })
191
123
  if (imageDataUri) {
192
124
  await invoke('save_pictures', {
@@ -208,14 +140,15 @@ export async function streamChatMessage(
208
140
  documentAttachment?: DocumentAttachment | null,
209
141
  workspacePath?: string | null,
210
142
  chatId?: string | null,
143
+ agentId?: string | null,
211
144
  ): Promise<ChatResponse> {
212
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
213
- const API_BASE = "http://localhost:3000/api";
145
+ if (!isTauriRuntime()) {
146
+ const API_BASE = getLocalApiBase();
214
147
  const outgoingMessage = withImagePlaceholder(message, imageDataUri);
215
148
  const res = await fetch(`${API_BASE}/chat-stream`, {
216
149
  method: 'POST',
217
150
  headers: { 'Content-Type': 'application/json' },
218
- body: JSON.stringify({ message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, documentAttachment })
151
+ body: JSON.stringify({ message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, documentAttachment, agentId })
219
152
  });
220
153
  if (!res.ok) {
221
154
  const data = await res.json().catch(() => null);
@@ -261,7 +194,7 @@ export async function streamChatMessage(
261
194
  else onProgress?.(event.progress)
262
195
  }
263
196
  const response = await invoke<ChatResponse>('stream_chat_message', {
264
- request: { message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, documentAttachment, workspacePath },
197
+ request: { message: outgoingMessage, systemInstruction, chatId, imageDataUri, audioDataUri, documentAttachment, workspacePath, agentId },
265
198
  onEvent,
266
199
  })
267
200
  if (imageDataUri) {
@@ -287,9 +220,23 @@ export async function getTtsUrls(text: string): Promise<TtsUrl[]> {
287
220
  return invoke<TtsUrl[]>('get_tts_urls', { text })
288
221
  }
289
222
 
223
+ export async function cancelChatMessage(chatId: string): Promise<void> {
224
+ if (!isTauriRuntime()) {
225
+ const API_BASE = getLocalApiBase();
226
+ await fetch(`${API_BASE}/cancel-chat`, {
227
+ method: 'POST',
228
+ headers: { 'Content-Type': 'application/json' },
229
+ body: JSON.stringify({ chatId })
230
+ });
231
+ return;
232
+ }
233
+ const { invoke } = await import('@tauri-apps/api/core')
234
+ await invoke('cancel_chat_message', { chatId })
235
+ }
236
+
290
237
  export async function getRecentInteractions(limit = 50, chatId?: string | null): Promise<InteractionMemory[]> {
291
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
292
- const API_BASE = "http://localhost:3000/api";
238
+ if (!isTauriRuntime()) {
239
+ const API_BASE = getLocalApiBase();
293
240
  try {
294
241
  const params = new URLSearchParams({ limit: String(limit) });
295
242
  if (chatId) params.set('chatId', chatId);
@@ -310,8 +257,8 @@ export async function saveSystemInteraction(
310
257
  provider: string,
311
258
  model: string,
312
259
  ): Promise<any> {
313
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
314
- const API_BASE = "http://localhost:3000/api";
260
+ if (!isTauriRuntime()) {
261
+ const API_BASE = getLocalApiBase();
315
262
  try {
316
263
  const res = await fetch(`${API_BASE}/interactions`, {
317
264
  method: 'POST',
@@ -332,8 +279,8 @@ export async function saveInteractionAgentActivity(
332
279
  interactionId: number,
333
280
  activity: AgentProgress[],
334
281
  ): Promise<void> {
335
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
336
- const API_BASE = "http://localhost:3000/api";
282
+ if (!isTauriRuntime()) {
283
+ const API_BASE = getLocalApiBase();
337
284
  try {
338
285
  const res = await fetch(`${API_BASE}/interactions/agent-activity`, {
339
286
  method: 'POST',
@@ -353,8 +300,8 @@ export async function saveInteractionAgentActivity(
353
300
  }
354
301
 
355
302
  export async function listChatSessions(): Promise<ChatSession[]> {
356
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
357
- const API_BASE = "http://localhost:3000/api";
303
+ if (!isTauriRuntime()) {
304
+ const API_BASE = getLocalApiBase();
358
305
  try {
359
306
  const res = await fetch(`${API_BASE}/chat-sessions`);
360
307
  const data = await res.json();
@@ -369,8 +316,8 @@ export async function listChatSessions(): Promise<ChatSession[]> {
369
316
  }
370
317
 
371
318
  export async function deleteChatSession(chatId: string): Promise<number> {
372
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
373
- const API_BASE = "http://localhost:3000/api";
319
+ if (!isTauriRuntime()) {
320
+ const API_BASE = getLocalApiBase();
374
321
  try {
375
322
  const params = new URLSearchParams({ chatId });
376
323
  const res = await fetch(`${API_BASE}/chat-sessions/delete?${params.toString()}`, { method: 'POST' });
@@ -386,8 +333,8 @@ export async function deleteChatSession(chatId: string): Promise<number> {
386
333
  }
387
334
 
388
335
  export async function renameChatSession(chatId: string, newTitle: string): Promise<number> {
389
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
390
- const API_BASE = "http://localhost:3000/api";
336
+ if (!isTauriRuntime()) {
337
+ const API_BASE = getLocalApiBase();
391
338
  try {
392
339
  const res = await fetch(`${API_BASE}/chat-sessions/rename`, {
393
340
  method: 'POST',
@@ -406,8 +353,8 @@ export async function renameChatSession(chatId: string, newTitle: string): Promi
406
353
  }
407
354
 
408
355
  export async function getProfileValue(key: string): Promise<string> {
409
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
410
- const API_BASE = "http://localhost:3000/api";
356
+ if (!isTauriRuntime()) {
357
+ const API_BASE = getLocalApiBase();
411
358
  try {
412
359
  const params = new URLSearchParams({ key });
413
360
  const res = await fetch(`${API_BASE}/profile?${params.toString()}`);
@@ -423,8 +370,8 @@ export async function getProfileValue(key: string): Promise<string> {
423
370
  }
424
371
 
425
372
  export async function setProfileValue(key: string, value: string): Promise<boolean> {
426
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
427
- const API_BASE = "http://localhost:3000/api";
373
+ if (!isTauriRuntime()) {
374
+ const API_BASE = getLocalApiBase();
428
375
  try {
429
376
  const res = await fetch(`${API_BASE}/profile`, {
430
377
  method: 'POST',
@@ -509,8 +456,8 @@ export async function deleteLearnedSkill(name: string): Promise<number> {
509
456
  }
510
457
 
511
458
  export async function clearChatHistory(chatId?: string | null): Promise<number> {
512
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
513
- const API_BASE = "http://localhost:3000/api";
459
+ if (!isTauriRuntime()) {
460
+ const API_BASE = getLocalApiBase();
514
461
  try {
515
462
  const params = new URLSearchParams();
516
463
  if (chatId) params.set('chatId', chatId);
@@ -528,14 +475,15 @@ export async function clearChatHistory(chatId?: string | null): Promise<number>
528
475
  }
529
476
 
530
477
  export async function listSavedPictures(): Promise<PictureEntry[]> {
531
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
532
- const API_BASE = "http://localhost:3000/api";
478
+ if (!isTauriRuntime()) {
479
+ const API_BASE = getLocalApiBase();
533
480
  try {
534
- const res = await fetch(`${API_BASE}/pictures`);
481
+ const res = await fetch(`${API_BASE}/pictures?_t=${Date.now()}`);
535
482
  const pictures = await res.json();
483
+ const timestamp = Date.now();
536
484
  return Array.isArray(pictures)
537
485
  ? pictures.map((picture) => {
538
- const pictureUrl = picture.url ? `${API_BASE.replace('/api', '')}${picture.url}` : undefined
486
+ const pictureUrl = picture.url ? `${API_BASE.replace('/api', '')}${picture.url}?_t=${timestamp}` : undefined
539
487
  return {
540
488
  ...picture,
541
489
  path: pictureUrl || picture.path,
@@ -557,8 +505,8 @@ export async function listSavedPictures(): Promise<PictureEntry[]> {
557
505
  export async function generateImages(
558
506
  request: ImageGenRequest
559
507
  ): Promise<ImageGenResponse> {
560
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
561
- const API_BASE = 'http://localhost:3000/api'
508
+ if (!isTauriRuntime()) {
509
+ const API_BASE = getLocalApiBase()
562
510
  const res = await fetch(`${API_BASE}/image-generate`, {
563
511
  method: 'POST',
564
512
  headers: { 'Content-Type': 'application/json' },
@@ -592,8 +540,8 @@ export async function generateImages(
592
540
 
593
541
  /** Fetch which image-generation providers are currently configured on the backend. */
594
542
  export async function getImageGenProviders(): Promise<ImageGenProviders> {
595
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
596
- const API_BASE = 'http://localhost:3000/api'
543
+ if (!isTauriRuntime()) {
544
+ const API_BASE = getLocalApiBase()
597
545
  try {
598
546
  const res = await fetch(`${API_BASE}/image-gen/providers`)
599
547
  if (res.ok) return await res.json()
@@ -622,8 +570,8 @@ export async function getImageGenProviders(): Promise<ImageGenProviders> {
622
570
 
623
571
  /** Updates the default image generation provider in the configuration. */
624
572
  export async function setDefaultImageProvider(provider: string): Promise<boolean> {
625
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
626
- const API_BASE = "http://localhost:3000/api";
573
+ if (!isTauriRuntime()) {
574
+ const API_BASE = getLocalApiBase();
627
575
  try {
628
576
  const getRes = await fetch(`${API_BASE}/config`)
629
577
  if (!getRes.ok) return false
@@ -742,9 +690,9 @@ export function convertFileSrc(filePath: string, protocol = 'asset'): string {
742
690
  }
743
691
 
744
692
  export function installTauriAdapters() {
745
- if (typeof window === 'undefined' || !(window as any).__TAURI_INTERNALS__) {
746
- console.warn("Not running inside Tauri. Connecting to local API server fallback at http://localhost:3000/api.");
747
- const API_BASE = "http://localhost:3000/api";
693
+ if (!isTauriRuntime()) {
694
+ const API_BASE = getLocalApiBase();
695
+ console.warn(`Not running inside Tauri. Connecting to local API server fallback at ${API_BASE}.`);
748
696
 
749
697
  (window as any).settingsApi = {
750
698
  getSettings: async () => {
@@ -1280,3 +1228,40 @@ export async function readClipboardImage(): Promise<string | null> {
1280
1228
  return null
1281
1229
  }
1282
1230
  }
1231
+
1232
+ // Enforce compile-time check against the shared platform interface
1233
+ const _apiCheck: MintPlatformApi = {
1234
+ getRuntimeStatus,
1235
+ detectSystemTools,
1236
+ sendChatMessage,
1237
+ streamChatMessage,
1238
+ getTtsUrls,
1239
+ cancelChatMessage,
1240
+ getRecentInteractions,
1241
+ saveSystemInteraction,
1242
+ saveInteractionAgentActivity,
1243
+ listChatSessions,
1244
+ deleteChatSession,
1245
+ renameChatSession,
1246
+ getProfileValue,
1247
+ setProfileValue,
1248
+ listLearnedSkills,
1249
+ addLearnedSkill,
1250
+ deleteLearnedSkill,
1251
+ clearChatHistory,
1252
+ listSavedPictures,
1253
+ generateImages,
1254
+ getImageGenProviders,
1255
+ setDefaultImageProvider,
1256
+ getWorkspaceTree,
1257
+ createWorkspaceFile,
1258
+ createWorkspaceFolder,
1259
+ deleteWorkspaceItem,
1260
+ selectWorkspaceDirectory,
1261
+ submitToolApproval,
1262
+ proposeCodeEdits,
1263
+ applyCodeEdits,
1264
+ listen,
1265
+ readClipboardImage,
1266
+ }
1267
+
@@ -1,39 +1,11 @@
1
- import type { AgentProgress, InteractionMemory } from './tauri'
2
-
3
- export function thoughtsFrom(progress: AgentProgress[]): string[] {
4
- return progress
5
- .filter((event) => event.type === 'Thought')
6
- .map((event) => (event as Extract<AgentProgress, { type: 'Thought' }>).data.thought)
7
- .filter(Boolean)
8
- }
9
-
10
- export function trimAgentProgress(progress: AgentProgress[], maxNonThought = 20): AgentProgress[] {
11
- if (progress.length === 0) return progress
12
- const keptNonThought = new Set(
13
- progress.filter((event) => event.type !== 'Thought').slice(-maxNonThought),
14
- )
15
- return progress.filter((event) => event.type === 'Thought' || keptNonThought.has(event))
16
- }
17
-
18
- export function hasAgentToolActivity(progress: AgentProgress[]): boolean {
19
- return progress.some((event) => event.type === 'ToolStart' || event.type === 'ToolEnd')
20
- }
21
-
22
- export function mergeActivitySnapshots(
23
- current: Record<string, AgentProgress[]>,
24
- interactions: InteractionMemory[],
25
- ): Record<string, AgentProgress[]> {
26
- const merged = { ...current }
27
- for (const interaction of interactions) {
28
- const key = String(interaction.id)
29
- if (interaction.agentActivity?.length && !merged[key]) {
30
- merged[key] = interaction.agentActivity
31
- }
32
- }
33
- return merged
34
- }
35
-
36
- export function parseAgentActivity(value: unknown): AgentProgress[] | undefined {
37
- if (!Array.isArray(value)) return undefined
38
- return value as AgentProgress[]
39
- }
1
+ // Re-export everything from the shared module — do NOT add logic here.
2
+ // Edit src/renderer/shared/agentProgress.ts instead.
3
+ export type { AgentProgress, InteractionMemory } from '../shared/agentProgress'
4
+ export {
5
+ thoughtsFrom,
6
+ trimAgentProgress,
7
+ hasAgentToolActivity,
8
+ mergeActivitySnapshots,
9
+ parseAgentActivity,
10
+ parseFileChangesFromProgress,
11
+ } from '../shared/agentProgress'
@@ -1,47 +1,4 @@
1
- export function evaluateArithmetic(source: string): number {
2
- const tokens = source.replace(/\s+/g, '')
3
- let index = 0
1
+ // Re-export from the shared module — do NOT add logic here.
2
+ // Edit src/renderer/shared/calculator.ts instead.
3
+ export { evaluateArithmetic } from '../shared/calculator'
4
4
 
5
- function parseExpression(): number {
6
- let value = parseTerm()
7
- while (tokens[index] === '+' || tokens[index] === '-') {
8
- const operator = tokens[index++]
9
- const right = parseTerm()
10
- value = operator === '+' ? value + right : value - right
11
- }
12
- return value
13
- }
14
-
15
- function parseTerm(): number {
16
- let value = parseFactor()
17
- while (tokens[index] === '*' || tokens[index] === '/') {
18
- const operator = tokens[index++]
19
- const right = parseFactor()
20
- value = operator === '*' ? value * right : value / right
21
- }
22
- return value
23
- }
24
-
25
- function parseFactor(): number {
26
- if (tokens[index] === '+' || tokens[index] === '-') {
27
- return tokens[index++] === '-' ? -parseFactor() : parseFactor()
28
- }
29
- if (tokens[index] === '(') {
30
- index += 1
31
- const value = parseExpression()
32
- if (tokens[index++] !== ')') throw new Error('missing closing parenthesis')
33
- return value
34
- }
35
- const match = tokens.slice(index).match(/^(?:\d+(?:\.\d*)?|\.\d+)/)
36
- if (!match) throw new Error('expected a number')
37
- index += match[0].length
38
- return Number(match[0])
39
- }
40
-
41
- if (!tokens) throw new Error('expression is empty')
42
- const result = parseExpression()
43
- if (index !== tokens.length || !Number.isFinite(result)) {
44
- throw new Error('invalid arithmetic expression')
45
- }
46
- return result
47
- }