@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.
- package/Cargo.lock +3 -3
- package/Cargo.toml +1 -1
- package/README.md +0 -17
- package/Release_Note.md +137 -58
- package/bin/mint +0 -0
- package/crates/mint-cli/src/agent.rs +150 -45
- package/crates/mint-cli/src/image.rs +8 -8
- package/crates/mint-cli/src/main.rs +929 -412
- package/crates/mint-cli/src/onboard.rs +108 -108
- package/crates/mint-cli/src/setup.rs +143 -143
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +108 -52
- package/crates/mint-core/src/browser.rs +56 -1
- package/crates/mint-core/src/channels.rs +1 -0
- package/crates/mint-core/src/chat.rs +126 -8
- package/crates/mint-core/src/code_tools.rs +18 -20
- package/crates/mint-core/src/config.rs +245 -17
- package/crates/mint-core/src/image_gen.rs +5 -5
- package/crates/mint-core/src/lib.rs +16 -2
- package/crates/mint-core/src/memory.rs +6 -1
- package/crates/mint-core/src/orchestration.rs +260 -72
- package/crates/mint-core/src/pictures.rs +3 -4
- package/crates/mint-core/src/semantic.rs +1 -1
- package/crates/mint-core/src/shell.rs +1 -1
- package/crates/mint-core/src/skills.rs +46 -19
- package/crates/mint-core/src/tts.rs +3 -1
- package/flatpak/com.pheem49.mint.desktop +9 -0
- package/flatpak/com.pheem49.mint.metainfo.xml +35 -0
- package/flatpak/com.pheem49.mint.yaml +52 -0
- package/package.json +1 -1
- package/shared-modules/.github/workflows/ci.yml +120 -0
- package/shared-modules/.github/workflows/update.yaml +28 -0
- package/shared-modules/CODEOWNERS +23 -0
- package/shared-modules/README.md +79 -0
- package/shared-modules/SDL/README.md +3 -0
- package/shared-modules/SDL/SDL-1.2.15.json +51 -0
- package/shared-modules/SDL/SDL_Pango-0.1.2-API-adds.patch +118 -0
- package/shared-modules/SDL/SDL_image-1.2.12.json +25 -0
- package/shared-modules/SDL/SDL_mixer-1.2.12.json +27 -0
- package/shared-modules/SDL/SDL_net-1.2.8.json +19 -0
- package/shared-modules/SDL/SDL_pango-0.1.2.json +26 -0
- package/shared-modules/SDL/SDL_ttf-2.0.11.json +28 -0
- package/shared-modules/SDL/libsdl-1.2.15-strict-prototypes.patch +316 -0
- package/shared-modules/SDL/sdl-check-for-SDL_VIDEO_X11_BACKINGSTORE.patch +24 -0
- package/shared-modules/SDL/sdl-libx11-build.patch +59 -0
- package/shared-modules/SDL/sdl-sysloadso-buffer-length.patch +27 -0
- package/shared-modules/SDL/sdl12-compat.json +22 -0
- package/shared-modules/SDL2/SDL2_image.json +27 -0
- package/shared-modules/SDL2/SDL2_ttf.json +29 -0
- package/shared-modules/cld2/CMakeLists.txt +157 -0
- package/shared-modules/cld2/cld2.json +24 -0
- package/shared-modules/clutter/clutter.json +72 -0
- package/shared-modules/dbus-glib/dbus-glib.json +29 -0
- package/shared-modules/glew/glew.json +36 -0
- package/shared-modules/glu/glu-9.json +12 -0
- package/shared-modules/gtk2/arc-gtk2-theme-Replace-Inkscape-dependency-with-rsvg-convert.patch +180 -0
- package/shared-modules/gtk2/gtk2-common-themes.json +360 -0
- package/shared-modules/gtk2/gtk2-fix-crash-in-show-uri.patch +30 -0
- package/shared-modules/gtk2/gtk2-gcc14.patch +281 -0
- package/shared-modules/gtk2/gtk2-gcc15.patch +250 -0
- package/shared-modules/gtk2/gtk2-murrine-c99.patch +34 -0
- package/shared-modules/gtk2/gtk2-use-adwaita-theme.patch +80 -0
- package/shared-modules/gtk2/gtk2.json +120 -0
- package/shared-modules/gtk2/ibus-gcc15.patch +13 -0
- package/shared-modules/gtk2/murrine-engine-fix-crash.patch +12 -0
- package/shared-modules/gtk2/readme.md +10 -0
- package/shared-modules/intltool/intltool-0.51.json +20 -0
- package/shared-modules/intltool/intltool-perl5.26-regex-fixes.patch +59 -0
- package/shared-modules/lame/0001-Build-xmm_quantize_sub.c-with-msse.patch +34 -0
- package/shared-modules/lame/0002-Include-GTK-1-autoconf-directives-in-build-system.patch +222 -0
- package/shared-modules/lame/0003-Patch-out-remaining-ansi2knr.patch +70 -0
- package/shared-modules/lame/0004-initscr-is-not-used-anywhere-in-lame-sourcetree.patch +41 -0
- package/shared-modules/lame/0005-Update-autoconf.patch +81 -0
- package/shared-modules/lame/lame-3.99.5.json +32 -0
- package/shared-modules/libappindicator/libappindicator-gtk2-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-12.10.json +140 -0
- package/shared-modules/libappindicator/libappindicator-gtk3-introspection-12.10.json +140 -0
- package/shared-modules/libappindicator/patches/0001-libappindicator-ftbfs.patch +20 -0
- package/shared-modules/libappindicator/patches/0002-libappindicator-no-python.patch +888 -0
- package/shared-modules/libappindicator/patches/0003-libappindicator-fix-crash-from-incorrect-signal-emission.patch +74 -0
- package/shared-modules/libappindicator/patches/0004-libappindicator-fix-crash-iterating-icon-themes.patch +11 -0
- package/shared-modules/libayatana-appindicator/0001-Fix-HAVE_VALGRIND-AM_CONDITIONAL.patch +51 -0
- package/shared-modules/libayatana-appindicator/0001-Make-introspection-configurable.patch +44 -0
- package/shared-modules/libayatana-appindicator/libayatana-appindicator-gtk3.json +121 -0
- package/shared-modules/libcanberra/0001-gtk-Don-t-assume-all-GdkDisplays-are-GdkX11Displays-.patch +123 -0
- package/shared-modules/libcanberra/libcanberra.json +44 -0
- package/shared-modules/libmad/libmad.json +19 -0
- package/shared-modules/libsecret/libsecret.json +23 -0
- package/shared-modules/libsoup/libsoup-2.4.json +14 -0
- package/shared-modules/libusb/libusb.json +27 -0
- package/shared-modules/linux-audio/dssi.json +31 -0
- package/shared-modules/linux-audio/fftw3f-static.json +44 -0
- package/shared-modules/linux-audio/fftw3f.json +42 -0
- package/shared-modules/linux-audio/fluidsynth2-static.json +36 -0
- package/shared-modules/linux-audio/fluidsynth2.json +25 -0
- package/shared-modules/linux-audio/ladspa.json +26 -0
- package/shared-modules/linux-audio/lash.json +35 -0
- package/shared-modules/linux-audio/libinstpatch.json +16 -0
- package/shared-modules/linux-audio/liblo-static.json +22 -0
- package/shared-modules/linux-audio/liblo.json +17 -0
- package/shared-modules/linux-audio/lilv-static.json +94 -0
- package/shared-modules/linux-audio/lilv.json +89 -0
- package/shared-modules/linux-audio/lrdf.json +57 -0
- package/shared-modules/linux-audio/lv2.json +20 -0
- package/shared-modules/linux-audio/patches/lash/0001-configure-remove-aclocal-m4.patch +29 -0
- package/shared-modules/linux-audio/patches/lash/0002-Fix-build-with-recent-gcc.patch +73 -0
- package/shared-modules/linux-audio/patches/lash/0003-Fix-linking.patch +136 -0
- package/shared-modules/linux-audio/patches/raptor-libxml.patch +31 -0
- package/shared-modules/linux-audio/patches/stk-install.sh +54 -0
- package/shared-modules/linux-audio/stk.json +28 -0
- package/shared-modules/lua5.1/0004-Fix-stack-overflow-in-vararg-functions.patch +21 -0
- package/shared-modules/lua5.1/lua-5.1.5-so.patch +43 -0
- package/shared-modules/lua5.1/lua-5.1.5.json +42 -0
- package/shared-modules/lua5.3/lua-5.3.5.json +41 -0
- package/shared-modules/lua5.3/lua.pc.in +8 -0
- package/shared-modules/lua5.3/luaconf.patch +47 -0
- package/shared-modules/lua5.3/makefile-add-liblua.so-rule.patch +47 -0
- package/shared-modules/lua5.4/lua-5.4.json +41 -0
- package/shared-modules/lua5.4/lua.pc.in +8 -0
- package/shared-modules/lua5.4/luaconf.patch +34 -0
- package/shared-modules/lua5.4/makefile-add-liblua.so-rule.patch +42 -0
- package/shared-modules/luajit/luajit.json +30 -0
- package/shared-modules/lzo/lzo.json +27 -0
- package/shared-modules/mac/mac.json +18 -0
- package/shared-modules/physfs/physfs.json +26 -0
- package/shared-modules/pygame/audiofile-gcc6.patch +21 -0
- package/shared-modules/pygame/cython-fixes.patch +34 -0
- package/shared-modules/pygame/fluidsynth-no-rawmidi.patch +69 -0
- package/shared-modules/pygame/glib.patch +25 -0
- package/shared-modules/pygame/pygame1-python2.json +157 -0
- package/shared-modules/pygtk/pygtk-c99.patch +15 -0
- package/shared-modules/pygtk/pygtk.json +117 -0
- package/shared-modules/pygtk/pygtk.patch +39 -0
- package/shared-modules/python2.7/python-2.7.json +48 -0
- package/shared-modules/smpeg/smpeg-0.4.5.json +50 -0
- package/shared-modules/smpeg/smpeg-am-prog-as.patch +12 -0
- package/shared-modules/smpeg/smpeg-export-mpegaudio-class.patch +17 -0
- package/shared-modules/smpeg/smpeg-gcc6.patch +40 -0
- package/shared-modules/smpeg/smpeg-no-gtk.patch +37 -0
- package/shared-modules/squashfs-tools/squashfs-tools.json +25 -0
- package/shared-modules/update-checker.sh +50 -0
- package/shared-modules/vorbisgain/0001-temp_files.patch +75 -0
- package/shared-modules/vorbisgain/0002-errno.patch +33 -0
- package/shared-modules/vorbisgain/0003-manpage.patch +248 -0
- package/shared-modules/vorbisgain/0004-vorbisgain_mtime.patch +183 -0
- package/shared-modules/vorbisgain/0005-double_fclose.patch +21 -0
- package/shared-modules/vorbisgain/0006-manpage_hyphens.patch +56 -0
- package/shared-modules/vorbisgain/0007-recursively_spelling.patch +14 -0
- package/shared-modules/vorbisgain/0008-manpage_recursion_mistake.patch +23 -0
- package/shared-modules/vorbisgain/0009-hardening.patch +13 -0
- package/shared-modules/vorbisgain/0010-fclose.patch +13 -0
- package/shared-modules/vorbisgain/README.md +23 -0
- package/shared-modules/vorbisgain/vorbisgain_0.37-2.json +29 -0
- package/src/renderer/shared/agentProgress.ts +145 -0
- package/src/renderer/shared/calculator.ts +52 -0
- package/src/renderer/shared/components/AgentActivityDrawer.tsx +72 -0
- package/src/renderer/shared/components/AgentActivityTable.tsx +85 -0
- package/src/renderer/shared/components/ApprovalCard.tsx +93 -0
- package/src/renderer/shared/components/ChatCodeBlock.tsx +75 -0
- package/src/renderer/shared/components/ThinkingBlock.tsx +101 -0
- package/src/renderer/shared/constants/models.ts +91 -0
- package/src/renderer/shared/platform.ts +82 -0
- package/src/renderer/shared/types.ts +140 -0
- package/src/renderer/shared/utils/agentActivity.ts +187 -0
- package/src/renderer/shared/utils/approval.ts +1 -0
- package/src/renderer/shared/utils/approval.tsx +64 -0
- package/src/renderer/shared/utils/fileIcons.ts +135 -0
- package/src/renderer/shared/utils/markdown.tsx +347 -0
- package/src/renderer/shared/utils/providers.ts +36 -0
- package/src/renderer/shared/utils/speech.ts +216 -0
- package/src/renderer/shared/utils/ui.ts +147 -0
- package/src/renderer/src/agentProgress.ts +11 -39
- package/src/renderer/src/calculator.ts +3 -46
- package/src/renderer/src/components/ChatPanel.tsx +219 -1308
- package/src/renderer/src/components/MintDashboard.tsx +67 -170
- package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
- package/src/renderer/src/components/Settings/AgentsTab.tsx +381 -0
- package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src/components/Settings/GeneralTab.tsx +256 -2
- package/src/renderer/src/components/SettingsWindow.tsx +120 -3
- package/src/renderer/src/components/WorkspacePanel.tsx +7 -125
- package/src/renderer/src/css/styles.css +100 -0
- package/src/renderer/src/tauri.ts +128 -143
- package/src/renderer/src-web/agentProgress.ts +11 -39
- package/src/renderer/src-web/calculator.ts +3 -46
- package/src/renderer/src-web/components/ChatPanel.tsx +219 -1306
- package/src/renderer/src-web/components/MintDashboard.tsx +42 -170
- package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +381 -0
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src-web/components/Settings/GeneralTab.tsx +254 -3
- package/src/renderer/src-web/components/SettingsWindow.tsx +127 -3
- package/src/renderer/src-web/css/styles.css +100 -0
- package/src/renderer/src-web/tauri.ts +180 -102
- package/src-tauri/src/desktop.rs +18 -16
- package/src-tauri/src/discord_rpc.rs +1 -1
- package/src-tauri/src/lib.rs +168 -40
- package/src-tauri/src/webhooks.rs +1 -0
- package/src-tauri/src/workflows.rs +1 -0
- 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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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 (
|
|
112
|
-
const API_BASE =
|
|
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 (
|
|
140
|
-
const API_BASE =
|
|
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 (
|
|
163
|
-
const API_BASE =
|
|
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 (
|
|
213
|
-
const API_BASE =
|
|
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 (
|
|
292
|
-
const API_BASE =
|
|
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 (
|
|
314
|
-
const API_BASE =
|
|
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 (
|
|
336
|
-
const API_BASE =
|
|
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 (
|
|
357
|
-
const API_BASE =
|
|
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 (
|
|
373
|
-
const API_BASE =
|
|
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 (
|
|
390
|
-
const API_BASE =
|
|
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 (
|
|
410
|
-
const API_BASE =
|
|
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 (
|
|
427
|
-
const API_BASE =
|
|
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 (
|
|
513
|
-
const API_BASE =
|
|
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 (
|
|
532
|
-
const API_BASE =
|
|
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 (
|
|
561
|
-
const API_BASE =
|
|
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 (
|
|
596
|
-
const API_BASE =
|
|
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 (
|
|
626
|
-
const API_BASE =
|
|
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 (
|
|
746
|
-
|
|
747
|
-
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
}
|