@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
@@ -0,0 +1,135 @@
1
+ /**
2
+ * shared/utils/fileIcons.ts
3
+ * Utility mapping and resolution functions for Material Icon Theme icons.
4
+ * Extracted from WorkspacePanel to be shared across multiple components (e.g. AgentActivityTable).
5
+ */
6
+
7
+ import folderIcon from 'material-icon-theme/icons/folder.svg?url'
8
+ import folderOpenIcon from 'material-icon-theme/icons/folder-open.svg?url'
9
+ import folderComponentsIcon from 'material-icon-theme/icons/folder-components.svg?url'
10
+ import folderComponentsOpenIcon from 'material-icon-theme/icons/folder-components-open.svg?url'
11
+ import folderConfigIcon from 'material-icon-theme/icons/folder-config.svg?url'
12
+ import folderConfigOpenIcon from 'material-icon-theme/icons/folder-config-open.svg?url'
13
+ import folderDistIcon from 'material-icon-theme/icons/folder-dist.svg?url'
14
+ import folderDistOpenIcon from 'material-icon-theme/icons/folder-dist-open.svg?url'
15
+ import folderDocsIcon from 'material-icon-theme/icons/folder-docs.svg?url'
16
+ import folderDocsOpenIcon from 'material-icon-theme/icons/folder-docs-open.svg?url'
17
+ import folderGitIcon from 'material-icon-theme/icons/folder-git.svg?url'
18
+ import folderGitOpenIcon from 'material-icon-theme/icons/folder-git-open.svg?url'
19
+ import folderGithubIcon from 'material-icon-theme/icons/folder-github.svg?url'
20
+ import folderGithubOpenIcon from 'material-icon-theme/icons/folder-github-open.svg?url'
21
+ import folderImagesIcon from 'material-icon-theme/icons/folder-images.svg?url'
22
+ import folderImagesOpenIcon from 'material-icon-theme/icons/folder-images-open.svg?url'
23
+ import folderLogIcon from 'material-icon-theme/icons/folder-log.svg?url'
24
+ import folderLogOpenIcon from 'material-icon-theme/icons/folder-log-open.svg?url'
25
+ import folderNodeIcon from 'material-icon-theme/icons/folder-node.svg?url'
26
+ import folderNodeOpenIcon from 'material-icon-theme/icons/folder-node-open.svg?url'
27
+ import folderPublicIcon from 'material-icon-theme/icons/folder-public.svg?url'
28
+ import folderPublicOpenIcon from 'material-icon-theme/icons/folder-public-open.svg?url'
29
+ import folderRustIcon from 'material-icon-theme/icons/folder-rust.svg?url'
30
+ import folderRustOpenIcon from 'material-icon-theme/icons/folder-rust-open.svg?url'
31
+ import folderScriptsIcon from 'material-icon-theme/icons/folder-scripts.svg?url'
32
+ import folderScriptsOpenIcon from 'material-icon-theme/icons/folder-scripts-open.svg?url'
33
+ import folderSrcIcon from 'material-icon-theme/icons/folder-src.svg?url'
34
+ import folderSrcOpenIcon from 'material-icon-theme/icons/folder-src-open.svg?url'
35
+ import folderSrcTauriIcon from 'material-icon-theme/icons/folder-src-tauri.svg?url'
36
+ import folderSrcTauriOpenIcon from 'material-icon-theme/icons/folder-src-tauri-open.svg?url'
37
+ import folderTestIcon from 'material-icon-theme/icons/folder-test.svg?url'
38
+ import folderTestOpenIcon from 'material-icon-theme/icons/folder-test-open.svg?url'
39
+ import folderUiIcon from 'material-icon-theme/icons/folder-ui.svg?url'
40
+ import folderUiOpenIcon from 'material-icon-theme/icons/folder-ui-open.svg?url'
41
+ import folderUtilsIcon from 'material-icon-theme/icons/folder-utils.svg?url'
42
+ import folderUtilsOpenIcon from 'material-icon-theme/icons/folder-utils-open.svg?url'
43
+ import cssIcon from 'material-icon-theme/icons/css.svg?url'
44
+ import documentIcon from 'material-icon-theme/icons/document.svg?url'
45
+ import htmlIcon from 'material-icon-theme/icons/html.svg?url'
46
+ import imageIcon from 'material-icon-theme/icons/image.svg?url'
47
+ import javascriptIcon from 'material-icon-theme/icons/javascript.svg?url'
48
+ import jsonIcon from 'material-icon-theme/icons/json.svg?url'
49
+ import lockIcon from 'material-icon-theme/icons/lock.svg?url'
50
+ import logIcon from 'material-icon-theme/icons/log.svg?url'
51
+ import markdownIcon from 'material-icon-theme/icons/markdown.svg?url'
52
+ import npmIcon from 'material-icon-theme/icons/npm.svg?url'
53
+ import reactIcon from 'material-icon-theme/icons/react.svg?url'
54
+ import reactTsIcon from 'material-icon-theme/icons/react_ts.svg?url'
55
+ import rustIcon from 'material-icon-theme/icons/rust.svg?url'
56
+ import settingsIcon from 'material-icon-theme/icons/settings.svg?url'
57
+ import tauriIcon from 'material-icon-theme/icons/tauri.svg?url'
58
+ import tomlIcon from 'material-icon-theme/icons/toml.svg?url'
59
+ import typescriptIcon from 'material-icon-theme/icons/typescript.svg?url'
60
+ import viteIcon from 'material-icon-theme/icons/vite.svg?url'
61
+ import yamlIcon from 'material-icon-theme/icons/yaml.svg?url'
62
+
63
+ export const FOLDER_ICONS: Record<string, { closed: string; open: string }> = {
64
+ '.cargo_home': { closed: folderRustIcon, open: folderRustOpenIcon },
65
+ '.github': { closed: folderGithubIcon, open: folderGithubOpenIcon },
66
+ '.git': { closed: folderGitIcon, open: folderGitOpenIcon },
67
+ '.rustup': { closed: folderRustIcon, open: folderRustOpenIcon },
68
+ '.rustup_copy': { closed: folderRustIcon, open: folderRustOpenIcon },
69
+ '.rustup_home': { closed: folderRustIcon, open: folderRustOpenIcon },
70
+ assets: { closed: folderImagesIcon, open: folderImagesOpenIcon },
71
+ components: { closed: folderComponentsIcon, open: folderComponentsOpenIcon },
72
+ crates: { closed: folderRustIcon, open: folderRustOpenIcon },
73
+ css: { closed: folderUiIcon, open: folderUiOpenIcon },
74
+ dist: { closed: folderDistIcon, open: folderDistOpenIcon },
75
+ docs: { closed: folderDocsIcon, open: folderDocsOpenIcon },
76
+ logs: { closed: folderLogIcon, open: folderLogOpenIcon },
77
+ node_modules: { closed: folderNodeIcon, open: folderNodeOpenIcon },
78
+ out: { closed: folderDistIcon, open: folderDistOpenIcon },
79
+ public: { closed: folderPublicIcon, open: folderPublicOpenIcon },
80
+ renderer: { closed: folderUiIcon, open: folderUiOpenIcon },
81
+ scripts: { closed: folderScriptsIcon, open: folderScriptsOpenIcon },
82
+ src: { closed: folderSrcIcon, open: folderSrcOpenIcon },
83
+ 'src-tauri': { closed: folderSrcTauriIcon, open: folderSrcTauriOpenIcon },
84
+ tests: { closed: folderTestIcon, open: folderTestOpenIcon },
85
+ utils: { closed: folderUtilsIcon, open: folderUtilsOpenIcon },
86
+ }
87
+
88
+ export const FILE_ICONS_BY_EXTENSION: Record<string, string> = {
89
+ css: cssIcon,
90
+ html: htmlIcon,
91
+ jpeg: imageIcon,
92
+ jpg: imageIcon,
93
+ js: javascriptIcon,
94
+ json: jsonIcon,
95
+ lock: lockIcon,
96
+ log: logIcon,
97
+ md: markdownIcon,
98
+ png: imageIcon,
99
+ rs: rustIcon,
100
+ svg: imageIcon,
101
+ toml: tomlIcon,
102
+ ts: typescriptIcon,
103
+ tsx: reactTsIcon,
104
+ yaml: yamlIcon,
105
+ yml: yamlIcon,
106
+ }
107
+
108
+ export const FILE_ICONS_BY_NAME: Record<string, string> = {
109
+ 'package-lock.json': npmIcon,
110
+ 'package.json': npmIcon,
111
+ 'tauri.conf.json': tauriIcon,
112
+ 'vite.config.ts': viteIcon,
113
+ 'vite.config.web.ts': viteIcon,
114
+ }
115
+
116
+ export function getExtension(name: string): string {
117
+ const index = name.lastIndexOf('.')
118
+ return index === -1 ? '' : name.slice(index + 1).toLowerCase()
119
+ }
120
+
121
+ export function materialFolderIcon(name: string, open: boolean): string {
122
+ const icon = FOLDER_ICONS[name] || FOLDER_ICONS[name.toLowerCase()]
123
+ if (!icon) return open ? folderOpenIcon : folderIcon
124
+ return open ? icon.open : icon.closed
125
+ }
126
+
127
+ export function materialFileIcon(name: string, fileExtension: string): string {
128
+ if (name.endsWith('.config.ts') || name.endsWith('.config.js')) return settingsIcon
129
+ if (name.endsWith('.tsx')) return reactTsIcon
130
+ if (name.endsWith('.jsx')) return reactIcon
131
+ return FILE_ICONS_BY_NAME[name.toLowerCase()] || FILE_ICONS_BY_EXTENSION[fileExtension] || documentIcon
132
+ }
133
+
134
+ export { folderIcon, folderOpenIcon }
135
+
@@ -0,0 +1,347 @@
1
+ /**
2
+ * shared/utils/markdown.tsx
3
+ * Custom markdown parsing and rendering engine for message bubbles.
4
+ * Shared by both Desktop and Web ChatPanel — do NOT duplicate this.
5
+ */
6
+ import { Fragment, type ReactNode } from 'react'
7
+ import { ChatCodeBlock } from '../components/ChatCodeBlock'
8
+
9
+ export const isTableLine = (line: string): boolean => {
10
+ const trimmed = line.trim()
11
+ return trimmed.startsWith('|') && trimmed.endsWith('|') && trimmed.length > 1
12
+ }
13
+
14
+ export function readableAssistantText(text: string): string {
15
+ if (typeof text !== 'string') return ''
16
+ const trimmed = text.trim()
17
+ if (!trimmed.startsWith('{')) return sanitizeLatex(text)
18
+ try {
19
+ const value = JSON.parse(trimmed)
20
+ if (value?.action === 'finish' && typeof value?.input?.summary === 'string' && value.input.summary.trim()) {
21
+ return sanitizeLatex(value.input.summary)
22
+ }
23
+ if (typeof value?.finish?.summary === 'string' && value.finish.summary.trim()) {
24
+ return sanitizeLatex(value.finish.summary)
25
+ }
26
+ } catch {
27
+ return sanitizeLatex(text)
28
+ }
29
+ return sanitizeLatex(text)
30
+ }
31
+
32
+ /** Replace common LaTeX math symbols with their Unicode equivalents */
33
+ function sanitizeLatex(text: string): string {
34
+ return text
35
+ // arrows
36
+ .replace(/\$\\rightarrow\$|\\\(\\rightarrow\\\)/g, '→')
37
+ .replace(/\$\\leftarrow\$|\\\(\\leftarrow\\\)/g, '←')
38
+ .replace(/\$\\Rightarrow\$|\\\(\\Rightarrow\\\)/g, '⇒')
39
+ .replace(/\$\\Leftarrow\$|\\\(\\Leftarrow\\\)/g, '⇐')
40
+ .replace(/\$\\leftrightarrow\$|\\\(\\leftrightarrow\\\)/g, '↔')
41
+ // comparison
42
+ .replace(/\$\\leq\$|\\\(\\leq\\\)/g, '≤')
43
+ .replace(/\$\\geq\$|\\\(\\geq\\\)/g, '≥')
44
+ .replace(/\$\\neq\$|\\\(\\neq\\\)/g, '≠')
45
+ .replace(/\$\\approx\$|\\\(\\approx\\\)/g, '≈')
46
+ // math
47
+ .replace(/\$\\times\$|\\\(\\times\\\)/g, '×')
48
+ .replace(/\$\\div\$|\\\(\\div\\\)/g, '÷')
49
+ .replace(/\$\\pm\$|\\\(\\pm\\\)/g, '±')
50
+ .replace(/\$\\infty\$|\\\(\\infty\\\)/g, '∞')
51
+ // other common symbols
52
+ .replace(/\$\\cdot\$|\\\(\\cdot\\\)/g, '·')
53
+ .replace(/\$\\in\$|\\\(\\in\\\)/g, '∈')
54
+ .replace(/\$\\subset\$|\\\(\\subset\\\)/g, '⊂')
55
+ .replace(/\$\\cup\$|\\\(\\cup\\\)/g, '∪')
56
+ .replace(/\$\\cap\$|\\\(\\cap\\\)/g, '∩')
57
+ // strip remaining inline math delimiters $...$ and \(...\) that weren't matched
58
+ .replace(/\$([^$\n]{1,60})\$/g, '$1')
59
+ .replace(/\\\(([^)]{1,60})\\\)/g, '$1')
60
+ }
61
+
62
+
63
+
64
+ export function cleanSpeechText(text: string): string {
65
+ return readableAssistantText(text)
66
+ .replace(/\*\*([\s\S]*?)\*\*/g, '$1')
67
+ .replace(/[*_`#]/g, '')
68
+ .trim()
69
+ }
70
+
71
+ export function renderSpeakerIcon(isSpeaking: boolean): ReactNode {
72
+ if (isSpeaking) {
73
+ return (
74
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ display: 'block' }}>
75
+ <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
76
+ <path d="M15.54 8.46a5 5 0 0 1 0 7.07" />
77
+ <path d="M19.07 4.93a10 10 0 0 1 0 14.14" />
78
+ </svg>
79
+ )
80
+ }
81
+ return (
82
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ display: 'block' }}>
83
+ <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" />
84
+ </svg>
85
+ )
86
+ }
87
+
88
+ export function renderFormattedMessage(text: string): ReactNode {
89
+ const displayText = readableAssistantText(text)
90
+ if (!displayText) return null
91
+
92
+ const formatInline = (str: string) => {
93
+ const codeParts = str.split(/`([\s\S]*?)`/g)
94
+ return codeParts.map((codePart, codeIndex) => {
95
+ if (codeIndex % 2 === 1) {
96
+ return (
97
+ <code key={`code-${codeIndex}`} className="chat-inline-code">
98
+ {codePart}
99
+ </code>
100
+ )
101
+ }
102
+ const boldParts = codePart.split(/\*\*([\s\S]*?)\*\*/g)
103
+ return boldParts.map((boldPart, boldIndex) => {
104
+ if (boldIndex % 2 === 1) {
105
+ return (
106
+ <strong key={`bold-${boldIndex}`} className="chat-bold-highlight">
107
+ {boldPart}
108
+ </strong>
109
+ )
110
+ }
111
+ const mentionParts = boldPart.split(/(@[\w\-\.\/]+)/g)
112
+ return mentionParts.map((mentionPart, mentionIndex) => {
113
+ if (mentionIndex % 2 === 1) {
114
+ return (
115
+ <span key={`mention-${mentionIndex}`} className="chat-mention">
116
+ {mentionPart}
117
+ </span>
118
+ )
119
+ }
120
+ return mentionPart
121
+ })
122
+ })
123
+ })
124
+ }
125
+
126
+ const renderHtmlTable = (tableLines: string[], key: string) => {
127
+ const rows: string[][] = []
128
+ for (const line of tableLines) {
129
+ const trimmed = line.trim()
130
+ if (!trimmed) continue
131
+ const content = trimmed.slice(1, -1)
132
+ const contentEscaped = content.replace(/\\\|/g, '\u0000')
133
+ const cols = contentEscaped.split('|').map(s => s.replace(/\u0000/g, '|').trim())
134
+ rows.push(cols)
135
+ }
136
+
137
+ if (rows.length === 0) return null
138
+
139
+ let hasSeparator = false
140
+ let separatorIdx = -1
141
+ for (let i = 0; i < rows.length; i++) {
142
+ const row = rows[i]
143
+ if (row.length > 0 && row.every(col => /^[-\s:]+$/.test(col))) {
144
+ hasSeparator = true
145
+ separatorIdx = i
146
+ break
147
+ }
148
+ }
149
+
150
+ let headerRow: string[] | null = null
151
+ const dataRows: string[][] = []
152
+
153
+ if (hasSeparator) {
154
+ if (separatorIdx > 0) {
155
+ headerRow = rows[separatorIdx - 1]
156
+ for (let i = 0; i < rows.length; i++) {
157
+ if (i !== separatorIdx && i !== separatorIdx - 1) {
158
+ dataRows.push(rows[i])
159
+ }
160
+ }
161
+ } else {
162
+ for (let i = 0; i < rows.length; i++) {
163
+ if (i !== separatorIdx) {
164
+ dataRows.push(rows[i])
165
+ }
166
+ }
167
+ }
168
+ } else {
169
+ headerRow = rows[0]
170
+ for (let i = 1; i < rows.length; i++) {
171
+ dataRows.push(rows[i])
172
+ }
173
+ }
174
+
175
+ return (
176
+ <div key={key} className="chat-table-container" style={{
177
+ overflowX: 'auto',
178
+ margin: '14px 0',
179
+ width: '100%',
180
+ borderRadius: '8px',
181
+ border: '1px solid rgba(255, 255, 255, 0.12)',
182
+ background: 'rgba(30, 41, 59, 0.35)',
183
+ boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
184
+ }}>
185
+ <table className="chat-table" style={{
186
+ width: '100%',
187
+ borderCollapse: 'collapse',
188
+ fontSize: '0.86rem',
189
+ textAlign: 'left',
190
+ lineHeight: '1.5',
191
+ }}>
192
+ {headerRow && (
193
+ <thead>
194
+ <tr style={{
195
+ background: 'rgba(255, 255, 255, 0.04)',
196
+ borderBottom: '2px solid rgba(255, 255, 255, 0.15)',
197
+ }}>
198
+ {headerRow.map((col, idx) => (
199
+ <th key={`th-${idx}`} style={{
200
+ padding: '12px 16px',
201
+ fontWeight: 700,
202
+ color: 'var(--accent, #38bdf8)',
203
+ fontFamily: 'ui-sans-serif, system-ui, sans-serif',
204
+ }}>
205
+ {formatInline(col)}
206
+ </th>
207
+ ))}
208
+ </tr>
209
+ </thead>
210
+ )}
211
+ <tbody>
212
+ {dataRows.map((row, rIdx) => (
213
+ <tr key={`tr-${rIdx}`} style={{
214
+ background: rIdx % 2 === 1 ? 'rgba(255, 255, 255, 0.015)' : 'transparent',
215
+ borderBottom: rIdx < dataRows.length - 1 ? '1px solid rgba(255, 255, 255, 0.08)' : 'none',
216
+ }}>
217
+ {row.map((col, cIdx) => (
218
+ <td key={`td-${cIdx}`} style={{
219
+ padding: '12px 16px',
220
+ color: 'var(--text-main, #e2e8f0)',
221
+ }}>
222
+ {formatInline(col)}
223
+ </td>
224
+ ))}
225
+ </tr>
226
+ ))}
227
+ </tbody>
228
+ </table>
229
+ </div>
230
+ )
231
+ }
232
+
233
+ const lines = displayText.split('\n')
234
+ const items: ReactNode[] = []
235
+
236
+ let inCodeBlock = false
237
+ let codeBlockLang = ''
238
+ let codeBlockLines: string[] = []
239
+
240
+ let inTable = false
241
+ let tableLines: string[] = []
242
+
243
+ const flushTable = (index: number) => {
244
+ if (tableLines.length > 0) {
245
+ items.push(renderHtmlTable(tableLines, `table-${index}`))
246
+ tableLines = []
247
+ inTable = false
248
+ }
249
+ }
250
+
251
+ for (let i = 0; i < lines.length; i++) {
252
+ const line = lines[i]
253
+
254
+ if (line.trim().startsWith('```')) {
255
+ if (inTable) {
256
+ flushTable(i)
257
+ }
258
+ if (inCodeBlock) {
259
+ const codeText = codeBlockLines.join('\n')
260
+ items.push(
261
+ <ChatCodeBlock
262
+ key={`code-block-${i}`}
263
+ code={codeText}
264
+ language={codeBlockLang}
265
+ />
266
+ )
267
+ inCodeBlock = false
268
+ codeBlockLines = []
269
+ } else {
270
+ inCodeBlock = true
271
+ codeBlockLang = line.trim().slice(3).trim() || 'plaintext'
272
+ }
273
+ continue
274
+ }
275
+
276
+ if (inCodeBlock) {
277
+ codeBlockLines.push(line)
278
+ continue
279
+ }
280
+
281
+ if (isTableLine(line)) {
282
+ inTable = true
283
+ tableLines.push(line)
284
+ } else {
285
+ if (inTable) {
286
+ flushTable(i)
287
+ }
288
+
289
+ const headerMatch = line.match(/^(#{1,6})\s+(.*)$/)
290
+ if (headerMatch) {
291
+ const level = headerMatch[1].length
292
+ const content = headerMatch[2]
293
+
294
+ const style = {
295
+ fontWeight: 'bold',
296
+ display: 'block',
297
+ marginTop: level === 1 ? '16px' : level === 2 ? '14px' : '10px',
298
+ marginBottom: '6px',
299
+ fontSize: level === 1 ? '1.25em' : level === 2 ? '1.15em' : '1.05em',
300
+ color: 'var(--text-main)',
301
+ }
302
+
303
+ items.push(
304
+ <span key={`line-${i}`} style={style}>
305
+ {formatInline(content)}
306
+ </span>
307
+ )
308
+ } else {
309
+ const listMatch = line.match(/^(\s*)([-*+])\s+(.*)$/)
310
+ if (listMatch) {
311
+ const indent = listMatch[1]
312
+ const content = listMatch[3]
313
+ items.push(
314
+ <Fragment key={`line-${i}`}>
315
+ {indent}• {formatInline(content)}
316
+ {i < lines.length - 1 && '\n'}
317
+ </Fragment>
318
+ )
319
+ } else {
320
+ items.push(
321
+ <Fragment key={`line-${i}`}>
322
+ {formatInline(line)}
323
+ {i < lines.length - 1 && '\n'}
324
+ </Fragment>
325
+ )
326
+ }
327
+ }
328
+ }
329
+ }
330
+
331
+ if (inTable) {
332
+ flushTable(lines.length)
333
+ }
334
+
335
+ if (inCodeBlock && codeBlockLines.length > 0) {
336
+ const codeText = codeBlockLines.join('\n')
337
+ items.push(
338
+ <ChatCodeBlock
339
+ key={`code-block-end`}
340
+ code={codeText}
341
+ language={codeBlockLang}
342
+ />
343
+ )
344
+ }
345
+
346
+ return <>{items}</>
347
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * shared/utils/providers.ts
3
+ * Provider label helpers — shared by both Desktop and Web ChatPanel.
4
+ */
5
+
6
+ /** Minimal shape needed — matches the full ChatResponse in both tauri.ts files. */
7
+ interface ProviderResponse {
8
+ provider: string
9
+ fallbackProvider?: string | null
10
+ }
11
+
12
+ export function badge(provider: string, model: string): string {
13
+ return [provider, model].filter(Boolean).join(' / ')
14
+ }
15
+
16
+ export function providerLabel(provider: string): string {
17
+ switch (provider) {
18
+ case 'gemini': return 'Gemini'
19
+ case 'openai': return 'OpenAI'
20
+ case 'openrouter': return 'OpenRouter'
21
+ case 'deepseek': return 'DeepSeek'
22
+ case 'anthropic': return 'Claude'
23
+ case 'huggingface': return 'Hugging Face'
24
+ case 'local_openai': return 'Local OpenAI'
25
+ case 'ollama': return 'Ollama'
26
+ default: return provider || 'Primary provider'
27
+ }
28
+ }
29
+
30
+ export function fallbackNotice(
31
+ response: ProviderResponse | null | undefined,
32
+ ): string {
33
+ if (!response?.fallbackProvider) return ''
34
+ return `${providerLabel(response.fallbackProvider)} unavailable, fell back to ${providerLabel(response.provider)}.`
35
+ }
36
+