@pheem49/mint 1.7.0 → 1.8.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 (55) hide show
  1. package/Cargo.lock +3 -3
  2. package/Cargo.toml +1 -1
  3. package/README.md +9 -0
  4. package/crates/mint-cli/src/agent.rs +1 -1
  5. package/crates/mint-cli/src/main.rs +47 -24
  6. package/crates/mint-cli/src/setup.rs +1 -1
  7. package/crates/mint-core/src/api_server.rs +64 -10
  8. package/crates/mint-core/src/chat.rs +79 -0
  9. package/crates/mint-core/src/lib.rs +1 -1
  10. package/crates/mint-core/src/plugins.rs +4 -1
  11. package/crates/mint-core/src/workflows.rs +8 -0
  12. package/package.json +13 -2
  13. package/src/renderer/src/App.tsx +1 -1
  14. package/src/renderer/src/components/ChatPanel.tsx +27 -14
  15. package/src/renderer/src/components/DashboardSidebar.tsx +71 -12
  16. package/src/renderer/src/components/ImageStudioPanel.tsx +7 -3
  17. package/src/renderer/src/components/MintDashboard.tsx +199 -5
  18. package/src/renderer/src/components/PicturesLibrary.tsx +1 -3
  19. package/src/renderer/src/components/Settings/AudioTab.tsx +97 -0
  20. package/src/renderer/src/components/Settings/AutomationTab.tsx +195 -0
  21. package/src/renderer/src/components/Settings/GeneralTab.tsx +950 -0
  22. package/src/renderer/src/components/Settings/MemoryTab.tsx +60 -0
  23. package/src/renderer/src/components/Settings/PluginsTab.tsx +452 -0
  24. package/src/renderer/src/components/Settings/ShortcutsTab.tsx +30 -0
  25. package/src/renderer/src/components/Settings/ThemeTab.tsx +129 -0
  26. package/src/renderer/src/components/SettingsWindow.tsx +175 -962
  27. package/src/renderer/src/components/WorkflowBuilderPanel.tsx +536 -0
  28. package/src/renderer/src/components/WorkflowsWindow.tsx +46 -0
  29. package/src/renderer/src/css/image-studio.css +9 -4
  30. package/src/renderer/src/css/settings.css +75 -6
  31. package/src/renderer/src/css/styles.css +355 -38
  32. package/src/renderer/src/css/workflows.css +542 -0
  33. package/src/renderer/src/env.d.ts +2 -0
  34. package/src/renderer/src/index.css +1 -0
  35. package/src/renderer/src/tauri.ts +97 -0
  36. package/src/renderer/src-web/components/ChatPanel.tsx +27 -14
  37. package/src/renderer/src-web/components/DashboardSidebar.tsx +17 -1
  38. package/src/renderer/src-web/components/ImageStudioPanel.tsx +7 -3
  39. package/src/renderer/src-web/components/MintDashboard.tsx +189 -0
  40. package/src/renderer/src-web/components/PicturesLibrary.tsx +1 -3
  41. package/src/renderer/src-web/components/Settings/AudioTab.tsx +97 -0
  42. package/src/renderer/src-web/components/Settings/AutomationTab.tsx +196 -0
  43. package/src/renderer/src-web/components/Settings/GeneralTab.tsx +948 -0
  44. package/src/renderer/src-web/components/Settings/MemoryTab.tsx +60 -0
  45. package/src/renderer/src-web/components/Settings/PluginsTab.tsx +452 -0
  46. package/src/renderer/src-web/components/Settings/ShortcutsTab.tsx +30 -0
  47. package/src/renderer/src-web/components/Settings/ThemeTab.tsx +129 -0
  48. package/src/renderer/src-web/components/SettingsWindow.tsx +187 -968
  49. package/src/renderer/src-web/css/image-studio.css +9 -4
  50. package/src/renderer/src-web/css/settings.css +75 -6
  51. package/src/renderer/src-web/css/styles.css +294 -38
  52. package/src/renderer/src-web/env.d.ts +2 -0
  53. package/src/renderer/src-web/tauri.ts +36 -0
  54. package/src-tauri/src/lib.rs +84 -92
  55. package/src-tauri/tauri.conf.json +1 -1
@@ -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 */
@@ -574,7 +574,7 @@ input[type="color"] {
574
574
  color: var(--text-main);
575
575
  }
576
576
 
577
- .toggle-switch {
577
+ .settings-toggle-switch {
578
578
  position: relative;
579
579
  display: inline-block;
580
580
  width: 46px;
@@ -582,13 +582,13 @@ input[type="color"] {
582
582
  height: 26px;
583
583
  }
584
584
 
585
- .toggle-switch input {
585
+ .settings-toggle-switch input {
586
586
  width: 0;
587
587
  height: 0;
588
588
  opacity: 0;
589
589
  }
590
590
 
591
- .toggle-slider {
591
+ .settings-toggle-slider {
592
592
  position: absolute;
593
593
  inset: 0;
594
594
  cursor: pointer;
@@ -598,7 +598,7 @@ input[type="color"] {
598
598
  transition: background 0.18s, border-color 0.18s;
599
599
  }
600
600
 
601
- .toggle-slider::before {
601
+ .settings-toggle-slider::before {
602
602
  position: absolute;
603
603
  content: "";
604
604
  width: 18px;
@@ -610,12 +610,12 @@ input[type="color"] {
610
610
  transition: transform 0.18s, background 0.18s;
611
611
  }
612
612
 
613
- input:checked + .toggle-slider {
613
+ input:checked + .settings-toggle-slider {
614
614
  background: var(--accent);
615
615
  border-color: var(--accent);
616
616
  }
617
617
 
618
- input:checked + .toggle-slider::before {
618
+ input:checked + .settings-toggle-slider::before {
619
619
  transform: translateX(20px);
620
620
  background: #ffffff;
621
621
  }
@@ -1107,4 +1107,73 @@ kbd {
1107
1107
  align-items: flex-start;
1108
1108
  }
1109
1109
 
1110
+ /* Provider Cards styling */
1111
+ .provider-cards-container {
1112
+ padding: 16px;
1113
+ display: flex;
1114
+ flex-direction: column;
1115
+ gap: 16px;
1116
+ }
1117
+
1118
+ .provider-card {
1119
+ border: 1px solid var(--border);
1120
+ border-radius: 12px;
1121
+ background: var(--surface-bg);
1122
+ padding: 16px;
1123
+ transition: border-color 0.2s ease, box-shadow 0.2s ease, background-color 0.2s ease;
1124
+ }
1125
+
1126
+ .provider-card:hover {
1127
+ border-color: var(--border-strong);
1128
+ }
1129
+
1130
+ .provider-card.active-provider {
1131
+ border-color: var(--accent);
1132
+ box-shadow: 0 0 0 1px var(--accent);
1133
+ background: color-mix(in srgb, var(--accent) 2%, var(--surface-bg));
1134
+ }
1135
+
1136
+ .provider-card-header {
1137
+ display: flex;
1138
+ align-items: center;
1139
+ justify-content: space-between;
1140
+ margin-bottom: 12px;
1141
+ padding-bottom: 8px;
1142
+ border-bottom: 1px solid var(--border);
1143
+ }
1144
+
1145
+ .provider-card-title {
1146
+ font-size: 0.92rem;
1147
+ font-weight: 600;
1148
+ color: var(--text-main);
1149
+ display: flex;
1150
+ align-items: center;
1151
+ gap: 8px;
1152
+ }
1153
+
1154
+ .provider-active-badge {
1155
+ background: color-mix(in srgb, var(--accent) 15%, transparent);
1156
+ color: var(--accent-hover);
1157
+ border: 1px solid var(--accent);
1158
+ font-size: 0.7rem;
1159
+ font-weight: 600;
1160
+ padding: 2px 8px;
1161
+ border-radius: 20px;
1162
+ text-transform: uppercase;
1163
+ letter-spacing: 0.05em;
1164
+ }
1165
+
1166
+ .provider-card-body {
1167
+ display: flex;
1168
+ flex-direction: column;
1169
+ gap: 12px;
1170
+ }
1171
+
1172
+ .provider-card-body .setting-row {
1173
+ border-top: none;
1174
+ padding: 6px 0;
1175
+ grid-template-columns: 180px 1fr;
1176
+ }
1177
+
1178
+
1110
1179
 
@@ -409,24 +409,24 @@ h1 {
409
409
  }
410
410
 
411
411
  .picture-refresh-btn {
412
- height: 28px;
413
- min-width: 0;
414
- padding: 0 8px;
412
+ height: 36px;
413
+ width: 36px;
414
+ padding: 0;
415
415
  display: inline-flex;
416
416
  align-items: center;
417
417
  justify-content: center;
418
- gap: 8px;
419
- border-radius: 6px;
420
- background: transparent;
421
- color: var(--text-muted);
422
- border: 1px solid transparent;
418
+ border-radius: 8px;
419
+ background: rgba(255, 255, 255, 0.04);
420
+ color: var(--text-soft);
421
+ border: 1px solid var(--border);
423
422
  cursor: pointer;
423
+ transition: background 0.15s, color 0.15s, border-color 0.15s;
424
424
  }
425
425
 
426
426
  .picture-refresh-btn:hover {
427
- background: color-mix(in srgb, var(--accent) 10%, transparent);
428
- border-color: color-mix(in srgb, var(--accent) 16%, transparent);
429
- color: var(--accent);
427
+ background: rgba(255, 255, 255, 0.08);
428
+ border-color: rgba(255, 255, 255, 0.15);
429
+ color: var(--text-main);
430
430
  }
431
431
 
432
432
  .maximize-btn:hover {
@@ -2150,7 +2150,7 @@ input:checked + .slider:before {
2150
2150
  -webkit-backdrop-filter: var(--glass-blur);
2151
2151
  border-right: 1px solid var(--border);
2152
2152
  color: var(--text-muted);
2153
- overflow: hidden;
2153
+ overflow: visible;
2154
2154
  transition: width 0.22s ease, padding 0.22s ease, opacity 0.18s ease, transform 0.22s ease;
2155
2155
  }
2156
2156
 
@@ -2661,7 +2661,8 @@ input:checked + .slider:before {
2661
2661
  transition: opacity 0.24s ease, transform 0.24s ease;
2662
2662
  }
2663
2663
 
2664
- .app-body.pictures-open .pictures-library {
2664
+ .app-body.pictures-open .pictures-library,
2665
+ .pictures-library.is-visible {
2665
2666
  opacity: 1;
2666
2667
  pointer-events: auto;
2667
2668
  transform: translateY(0);
@@ -2700,19 +2701,34 @@ input:checked + .slider:before {
2700
2701
  }
2701
2702
 
2702
2703
  .pictures-header-actions {
2703
- display: grid;
2704
- gap: 8px;
2705
- width: 130px;
2704
+ display: flex;
2705
+ align-items: center;
2706
+ gap: 10px;
2707
+ }
2708
+
2709
+ .pictures-header-actions .picture-folder-btn {
2710
+ display: none !important;
2706
2711
  }
2707
2712
 
2708
2713
  .pictures-close-btn {
2709
- height: 34px;
2710
- padding: 0 14px;
2714
+ height: 36px;
2715
+ padding: 0 16px;
2711
2716
  border: 1px solid var(--border);
2712
2717
  border-radius: 8px;
2713
- background: var(--surface-strong);
2718
+ background: rgba(255, 255, 255, 0.04);
2714
2719
  color: var(--text-main);
2720
+ font-size: 0.82rem;
2721
+ font-weight: 500;
2715
2722
  cursor: pointer;
2723
+ display: inline-flex;
2724
+ align-items: center;
2725
+ justify-content: center;
2726
+ transition: background 0.15s ease, border-color 0.15s ease;
2727
+ }
2728
+
2729
+ .pictures-close-btn:hover {
2730
+ background: rgba(255, 255, 255, 0.08);
2731
+ border-color: rgba(255, 255, 255, 0.15);
2716
2732
  }
2717
2733
 
2718
2734
  .pictures-grid {
@@ -2765,20 +2781,24 @@ input:checked + .slider:before {
2765
2781
  }
2766
2782
 
2767
2783
  .picture-folder-btn {
2768
- width: 100%;
2769
- height: 34px;
2784
+ height: 36px;
2785
+ padding: 0 16px;
2770
2786
  border: 1px solid var(--border);
2771
2787
  border-radius: 8px;
2772
- background: var(--panel-soft);
2773
- color: var(--text);
2774
- font-size: 0.75rem;
2775
- font-weight: 700;
2788
+ background: rgba(255, 255, 255, 0.04);
2789
+ color: var(--text-main);
2790
+ font-size: 0.82rem;
2791
+ font-weight: 500;
2776
2792
  cursor: pointer;
2793
+ display: inline-flex;
2794
+ align-items: center;
2795
+ justify-content: center;
2796
+ transition: background 0.15s ease, border-color 0.15s ease;
2777
2797
  }
2778
2798
 
2779
2799
  .picture-folder-btn:hover {
2780
- border-color: color-mix(in srgb, var(--accent) 48%, var(--border));
2781
- background: color-mix(in srgb, var(--accent) 12%, var(--panel-soft));
2800
+ background: rgba(255, 255, 255, 0.08);
2801
+ border-color: rgba(255, 255, 255, 0.15);
2782
2802
  }
2783
2803
 
2784
2804
  .picture-folder-btn:disabled {
@@ -3238,23 +3258,20 @@ input:checked + .slider:before {
3238
3258
 
3239
3259
  .mint-image-attachment {
3240
3260
  position: relative;
3241
- display: inline-flex;
3242
- width: auto;
3243
- height: auto;
3244
- max-width: min(360px, 72vw);
3245
- max-height: 196px;
3261
+ display: block;
3262
+ width: 80px;
3263
+ height: 80px;
3246
3264
  overflow: hidden;
3247
3265
  border: 1px solid var(--border);
3248
3266
  border-radius: 8px;
3249
3267
  background: color-mix(in srgb, var(--surface-strong) 78%, rgba(0, 0, 0, 0.22));
3250
3268
  }
3251
3269
 
3252
- .mint-image-preview {
3253
- width: auto;
3254
- height: auto;
3255
- max-width: min(360px, 72vw);
3256
- max-height: 196px;
3257
- display: block;
3270
+ .mint-image-attachment img.mint-image-preview {
3271
+ width: 100% !important;
3272
+ height: 100% !important;
3273
+ object-fit: cover !important;
3274
+ display: block !important;
3258
3275
  }
3259
3276
 
3260
3277
  .mint-attachment-remove {
@@ -3823,3 +3840,242 @@ input:checked + .slider:before {
3823
3840
  display: flex;
3824
3841
  }
3825
3842
  }
3843
+
3844
+ /* System Event Divider with Pill */
3845
+ .system-event-divider {
3846
+ display: flex;
3847
+ align-items: center;
3848
+ justify-content: center;
3849
+ width: 100%;
3850
+ margin: 20px 0;
3851
+ flex-shrink: 0;
3852
+ }
3853
+
3854
+ .system-event-line {
3855
+ flex: 1;
3856
+ height: 1px;
3857
+ border-bottom: 1px dashed rgba(255, 255, 255, 0.1);
3858
+ }
3859
+
3860
+ [data-theme="light"] .system-event-line {
3861
+ border-bottom: 1px dashed rgba(0, 0, 0, 0.1);
3862
+ }
3863
+
3864
+ .system-event-pill {
3865
+ display: flex;
3866
+ align-items: center;
3867
+ gap: 6px;
3868
+ padding: 4px 14px;
3869
+ background: var(--panel-raised, rgba(30, 41, 59, 0.6));
3870
+ border: 1px solid rgba(255, 255, 255, 0.08);
3871
+ border-radius: 9999px;
3872
+ color: var(--text-soft, #94a3b8);
3873
+ font-size: 0.78rem;
3874
+ font-weight: 500;
3875
+ margin: 0 12px;
3876
+ white-space: nowrap;
3877
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
3878
+ }
3879
+
3880
+ [data-theme="light"] .system-event-pill {
3881
+ background: #f1f5f9;
3882
+ border-color: rgba(0, 0, 0, 0.06);
3883
+ color: #475569;
3884
+ }
3885
+
3886
+ .system-event-pill svg {
3887
+ color: var(--accent, #38bdf8);
3888
+ }
3889
+
3890
+ /* Sidebar Search Chats Button */
3891
+ .sidebar-search-btn {
3892
+ margin-top: 4px;
3893
+ }
3894
+
3895
+ /* Sidebar Search Modal Backdrop */
3896
+ .sidebar-search-modal-backdrop {
3897
+ position: fixed;
3898
+ inset: 0;
3899
+ z-index: 10000;
3900
+ background: rgba(0, 0, 0, 0.6);
3901
+ backdrop-filter: blur(8px);
3902
+ -webkit-backdrop-filter: blur(8px);
3903
+ display: flex;
3904
+ align-items: flex-start;
3905
+ justify-content: center;
3906
+ padding-top: 12vh;
3907
+ }
3908
+
3909
+ /* Sidebar Search Modal Box */
3910
+ .sidebar-search-modal {
3911
+ width: 100%;
3912
+ max-width: 520px;
3913
+ background: var(--surface-strong, #1e293b);
3914
+ border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
3915
+ border-radius: 12px;
3916
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
3917
+ display: flex;
3918
+ flex-direction: column;
3919
+ overflow: hidden;
3920
+ animation: modalFadeIn 0.2s cubic-bezier(0.16, 1, 0.3, 1);
3921
+ }
3922
+
3923
+ @keyframes modalFadeIn {
3924
+ from {
3925
+ opacity: 0;
3926
+ transform: translateY(-20px) scale(0.96);
3927
+ }
3928
+ to {
3929
+ opacity: 1;
3930
+ transform: translateY(0) scale(1);
3931
+ }
3932
+ }
3933
+
3934
+ /* Header */
3935
+ .search-modal-header {
3936
+ display: flex;
3937
+ align-items: center;
3938
+ gap: 12px;
3939
+ padding: 14px 16px;
3940
+ border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.08));
3941
+ position: relative;
3942
+ }
3943
+
3944
+ .search-icon-wrapper {
3945
+ color: var(--text-soft, #94a3b8);
3946
+ display: inline-flex;
3947
+ align-items: center;
3948
+ }
3949
+
3950
+ .search-modal-header input {
3951
+ flex: 1;
3952
+ background: transparent;
3953
+ border: 0;
3954
+ color: var(--text-main, #f8fafc);
3955
+ font: inherit;
3956
+ font-size: 0.95rem;
3957
+ outline: none;
3958
+ }
3959
+
3960
+ .search-modal-header input::placeholder {
3961
+ color: var(--text-muted, #64748b);
3962
+ }
3963
+
3964
+ .search-modal-close {
3965
+ background: transparent;
3966
+ border: 0;
3967
+ color: var(--text-muted, #64748b);
3968
+ cursor: pointer;
3969
+ display: inline-flex;
3970
+ align-items: center;
3971
+ justify-content: center;
3972
+ padding: 4px;
3973
+ border-radius: 4px;
3974
+ transition: color 0.15s ease, background 0.15s ease;
3975
+ }
3976
+
3977
+ .search-modal-close:hover {
3978
+ color: var(--text-main, #f8fafc);
3979
+ background: rgba(255, 255, 255, 0.05);
3980
+ }
3981
+
3982
+ /* Body */
3983
+ .search-modal-body {
3984
+ max-height: 480px;
3985
+ overflow-y: auto;
3986
+ padding: 12px;
3987
+ display: flex;
3988
+ flex-direction: column;
3989
+ gap: 14px;
3990
+ }
3991
+
3992
+ .search-new-chat-btn {
3993
+ display: flex;
3994
+ align-items: center;
3995
+ gap: 10px;
3996
+ background: rgba(255, 255, 255, 0.03);
3997
+ border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
3998
+ border-radius: 8px;
3999
+ color: var(--text-main, #f8fafc);
4000
+ padding: 10px 14px;
4001
+ cursor: pointer;
4002
+ text-align: left;
4003
+ font: inherit;
4004
+ font-size: 0.9rem;
4005
+ transition: background 0.15s ease;
4006
+ }
4007
+
4008
+ .search-new-chat-btn:hover {
4009
+ background: rgba(255, 255, 255, 0.08);
4010
+ }
4011
+
4012
+ .search-modal-results {
4013
+ display: flex;
4014
+ flex-direction: column;
4015
+ gap: 14px;
4016
+ }
4017
+
4018
+ .search-results-group {
4019
+ display: flex;
4020
+ flex-direction: column;
4021
+ gap: 4px;
4022
+ }
4023
+
4024
+ .search-group-title {
4025
+ color: var(--accent, #10b981);
4026
+ font-size: 0.72rem;
4027
+ font-weight: 600;
4028
+ text-transform: uppercase;
4029
+ letter-spacing: 0.05em;
4030
+ padding: 4px 10px;
4031
+ }
4032
+
4033
+ .search-result-item {
4034
+ display: flex;
4035
+ align-items: center;
4036
+ gap: 10px;
4037
+ background: transparent;
4038
+ border: 0;
4039
+ border-radius: 6px;
4040
+ color: var(--text-soft, #94a3b8);
4041
+ padding: 8px 12px;
4042
+ cursor: pointer;
4043
+ text-align: left;
4044
+ font: inherit;
4045
+ font-size: 0.88rem;
4046
+ transition: background 0.15s ease, color 0.15s ease;
4047
+ white-space: nowrap;
4048
+ overflow: hidden;
4049
+ text-overflow: ellipsis;
4050
+ width: 100%;
4051
+ }
4052
+
4053
+ .search-result-item svg {
4054
+ color: var(--text-muted, #64748b);
4055
+ flex-shrink: 0;
4056
+ }
4057
+
4058
+ .search-result-item:hover,
4059
+ .search-result-item.active {
4060
+ background: rgba(255, 255, 255, 0.05);
4061
+ color: var(--text-main, #f8fafc);
4062
+ }
4063
+
4064
+ .search-result-item:hover svg,
4065
+ .search-result-item.active svg {
4066
+ color: var(--text-main, #f8fafc);
4067
+ }
4068
+
4069
+ .search-result-title {
4070
+ overflow: hidden;
4071
+ text-overflow: ellipsis;
4072
+ white-space: nowrap;
4073
+ }
4074
+
4075
+ .search-no-results {
4076
+ color: var(--text-muted, #64748b);
4077
+ text-align: center;
4078
+ padding: 30px 0;
4079
+ font-size: 0.9rem;
4080
+ }
4081
+
@@ -11,6 +11,7 @@ interface Window {
11
11
  getChatHistory: () => Promise<any>;
12
12
  listSavedPictures: () => Promise<any>;
13
13
  openSettings: () => Promise<any>;
14
+ openWorkflows: () => Promise<any>;
14
15
  readClipboard: () => Promise<string>;
15
16
  writeClipboard: (text: string) => Promise<void>;
16
17
  getSystemInfo: () => Promise<any>;
@@ -46,6 +47,7 @@ interface Window {
46
47
  openFolder: (path: string) => Promise<void>;
47
48
  openCustomWorkflows: () => Promise<any>;
48
49
  reloadCustomWorkflows: () => Promise<any>;
50
+ saveCustomWorkflows: (workflows: any[]) => Promise<any>;
49
51
  };
50
52
  spotlightAPI: {
51
53
  submit: (query: string) => void;
@@ -293,6 +293,30 @@ export async function getRecentInteractions(limit = 50, chatId?: string | null):
293
293
  return invoke<InteractionMemory[]>('get_recent_interactions', { limit, chatId })
294
294
  }
295
295
 
296
+ export async function saveSystemInteraction(
297
+ chatId: string,
298
+ userText: string,
299
+ provider: string,
300
+ model: string,
301
+ ): Promise<any> {
302
+ if (typeof window === 'undefined' || !isTauriRuntime()) {
303
+ const API_BASE = getApiBase();
304
+ try {
305
+ const res = await fetch(`${API_BASE}/interactions`, {
306
+ method: 'POST',
307
+ headers: { 'Content-Type': 'application/json' },
308
+ body: JSON.stringify({ chatId, userText, provider, model }),
309
+ });
310
+ return await res.json();
311
+ } catch (e) {
312
+ console.error("Failed to save system interaction on local server:", e);
313
+ return { success: false };
314
+ }
315
+ }
316
+ const { invoke } = await import('@tauri-apps/api/core')
317
+ return invoke('save_system_interaction', { chatId, userText, provider, model })
318
+ }
319
+
296
320
  export async function saveInteractionAgentActivity(
297
321
  interactionId: number,
298
322
  activity: AgentProgress[],
@@ -638,6 +662,7 @@ export function installTauriAdapters() {
638
662
  openFolder: async () => ({ success: false, message: 'Opening local folders is only available in the desktop app.' }),
639
663
  openCustomWorkflows: async () => ({ success: false, message: 'Opening workflow files is only available in the desktop app.' }),
640
664
  reloadCustomWorkflows: async () => ({ success: false, message: 'Reloading workflow files is only available in the desktop app.' }),
665
+ saveCustomWorkflows: async () => ({ success: false, message: 'Saving workflow files is only available in the desktop app.' }),
641
666
  };
642
667
 
643
668
  (window as any).spotlightAPI = {
@@ -733,6 +758,9 @@ export function installTauriAdapters() {
733
758
  openSettings: () => {
734
759
  window.location.hash = '#/settings';
735
760
  },
761
+ openWorkflows: () => {
762
+ window.location.hash = '#/workflows';
763
+ },
736
764
  readClipboard: async () => '',
737
765
  writeClipboard: async () => {},
738
766
  getSystemInfo: async () => {
@@ -877,6 +905,10 @@ export function installTauriAdapters() {
877
905
  const { invoke } = await import('@tauri-apps/api/core')
878
906
  return invoke('reload_custom_workflows')
879
907
  },
908
+ saveCustomWorkflows: async (workflows) => {
909
+ const { invoke } = await import('@tauri-apps/api/core')
910
+ return invoke('save_custom_workflows', { workflows })
911
+ },
880
912
  }
881
913
 
882
914
  window.spotlightAPI = {
@@ -1003,6 +1035,10 @@ export function installTauriAdapters() {
1003
1035
  const { invoke } = await import('@tauri-apps/api/core')
1004
1036
  return invoke('open_window', { kind: 'settings' })
1005
1037
  },
1038
+ openWorkflows: async () => {
1039
+ const { invoke } = await import('@tauri-apps/api/core')
1040
+ return invoke('open_window', { kind: 'workflows' })
1041
+ },
1006
1042
  readClipboard: () => navigator.clipboard.readText(),
1007
1043
  writeClipboard: (text) => navigator.clipboard.writeText(text),
1008
1044
  getSystemInfo: async () => ({ backend: 'rust' }),