@pheem49/mint 1.8.0 → 1.8.2
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/.github/workflows/release.yml +1 -1
- package/Cargo.lock +34 -3
- package/Cargo.toml +2 -2
- package/README.md +20 -6
- package/Release_Note.md +129 -0
- package/assets/Mint_CLI.png +0 -0
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +1 -0
- package/crates/mint-cli/src/agent.rs +242 -54
- package/crates/mint-cli/src/main.rs +397 -74
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +64 -2
- package/crates/mint-core/src/browser.rs +456 -0
- package/crates/mint-core/src/channels.rs +1 -0
- package/crates/mint-core/src/chat.rs +3 -0
- package/crates/mint-core/src/config.rs +130 -1
- package/crates/mint-core/src/lib.rs +19 -0
- package/crates/mint-core/src/orchestration.rs +317 -12
- package/crates/mint-core/src/skills.rs +113 -4
- package/crates/mint-core/src/tts.rs +3 -1
- package/crates/mint-core/src/workflows.rs +1 -22
- 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 +30 -0
- package/shared-modules/linux-audio/fluidsynth2.json +19 -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 +82 -0
- package/shared-modules/linux-audio/lrdf.json +57 -0
- package/shared-modules/linux-audio/lv2.json +21 -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 +66 -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/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 +230 -1202
- package/src/renderer/src/components/ImageStudioPanel.tsx +11 -1
- package/src/renderer/src/components/MintDashboard.tsx +63 -171
- package/src/renderer/src/components/PicturesLibrary.tsx +32 -8
- package/src/renderer/src/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src/components/Settings/PluginsTab.tsx +221 -41
- package/src/renderer/src/components/SettingsWindow.tsx +54 -12
- package/src/renderer/src/components/WorkspacePanel.tsx +66 -9
- package/src/renderer/src/css/image-studio.css +6 -0
- package/src/renderer/src/css/styles.css +148 -11
- package/src/renderer/src/index.css +12 -1
- package/src/renderer/src/tauri.ts +169 -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 +223 -1199
- package/src/renderer/src-web/components/ImageStudioPanel.tsx +11 -1
- package/src/renderer/src-web/components/MintDashboard.tsx +31 -172
- package/src/renderer/src-web/components/PicturesLibrary.tsx +23 -29
- package/src/renderer/src-web/components/Settings/AgentsTab.tsx +362 -0
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +0 -22
- package/src/renderer/src-web/components/Settings/PluginsTab.tsx +221 -41
- package/src/renderer/src-web/components/SettingsWindow.tsx +54 -12
- package/src/renderer/src-web/css/image-studio.css +6 -0
- package/src/renderer/src-web/css/styles.css +184 -12
- package/src/renderer/src-web/index.css +12 -1
- package/src/renderer/src-web/tauri.ts +204 -104
- package/src-tauri/src/browser.rs +1 -141
- package/src-tauri/src/headless.rs +3 -2
- package/src-tauri/src/lib.rs +254 -59
- package/src-tauri/src/webhooks.rs +1 -0
- package/src-tauri/src/workflows.rs +57 -4
- package/src-tauri/tauri.conf.json +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Description: The manpage shows methods that don't work. They have been replaced.
|
|
2
|
+
From: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=447402
|
|
3
|
+
Forwarded: no
|
|
4
|
+
--- a/vorbisgain.1
|
|
5
|
+
+++ b/vorbisgain.1
|
|
6
|
+
@@ -110,7 +110,7 @@
|
|
7
|
+
shell to not do any filename globbing:
|
|
8
|
+
.PP
|
|
9
|
+
.RS
|
|
10
|
+
-vorbisgain \-a \-f \-r "music/*.ogg"
|
|
11
|
+
+vorbisgain \-a \-f \-r music/
|
|
12
|
+
.RE
|
|
13
|
+
.PP
|
|
14
|
+
Calculate the album gain. The files specified before the directory "album"
|
|
15
|
+
@@ -124,7 +124,7 @@
|
|
16
|
+
Remove all replaygain tags from a collection of oggs:
|
|
17
|
+
.PP
|
|
18
|
+
.RS
|
|
19
|
+
-vorbisgain \-c \-r "music/*.ogg"
|
|
20
|
+
+vorbisgain \-c \-r music/
|
|
21
|
+
.RE
|
|
22
|
+
.SH TAG FORMAT
|
|
23
|
+
.B vorbisgain
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Description: Allow build with dh compat level 9 (debian build flags)
|
|
2
|
+
Forwarded: no
|
|
3
|
+
--- a/misc.c
|
|
4
|
+
+++ b/misc.c
|
|
5
|
+
@@ -56,7 +56,7 @@
|
|
6
|
+
vfprintf(stderr, message, args);
|
|
7
|
+
va_end(args);
|
|
8
|
+
|
|
9
|
+
- fprintf(stderr, strerror(err_num));
|
|
10
|
+
+ fputs(strerror(err_num), stderr);
|
|
11
|
+
fprintf(stderr, "\n");
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Solve "too many open files" by closing those which are not compatible with vorbisgain. Thanks to Marcel Rehberg for the patch.
|
|
2
|
+
--- a/vorbis.c
|
|
3
|
+
+++ b/vorbis.c
|
|
4
|
+
@@ -357,7 +357,8 @@
|
|
5
|
+
{
|
|
6
|
+
vorbis_error(result, _("Couldn't process '%s': "), filename);
|
|
7
|
+
}
|
|
8
|
+
-
|
|
9
|
+
+ // make sure file is closed, since ov_open failed we are still responsible
|
|
10
|
+
+ fclose(file);
|
|
11
|
+
return -1;
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Vorbisgain comes in two version;
|
|
2
|
+
- The main source: https://sjeng.org/ftp/vorbis/
|
|
3
|
+
- The Debian version: http://deb.debian.org/debian/pool/main/v/vorbisgain/
|
|
4
|
+
|
|
5
|
+
The catch is... Debian has 10 patches:
|
|
6
|
+
- 0001-temp_files.patch
|
|
7
|
+
- 0002-errno.patch
|
|
8
|
+
- 0003-manpage.patch
|
|
9
|
+
- 0004-vorbisgain_mtime.patch
|
|
10
|
+
- 0005-double_fclose.patch
|
|
11
|
+
- 0006-manpage_hyphens.patch
|
|
12
|
+
- 0007-recursively_spelling.patch
|
|
13
|
+
- 0008-manpage_recursion_mistake.patch
|
|
14
|
+
- 0009-hardening.patch
|
|
15
|
+
- 0010-fclose.patch
|
|
16
|
+
|
|
17
|
+
Of particular concern are 0005, 0009 and 0010 which might have implications for memory-leaks and string inputs.
|
|
18
|
+
|
|
19
|
+
## Other points of concern
|
|
20
|
+
|
|
21
|
+
https://pkgs.org/download/vorbisgain
|
|
22
|
+
|
|
23
|
+
Lots of distributions don't include these patches as well, but I prefer to stick with the tried and tested package from Debian.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vorbisgain",
|
|
3
|
+
"buildsystem": "autotools",
|
|
4
|
+
"cleanup": [
|
|
5
|
+
"/man"
|
|
6
|
+
],
|
|
7
|
+
"sources": [
|
|
8
|
+
{
|
|
9
|
+
"type": "archive",
|
|
10
|
+
"url": "http://deb.debian.org/debian/pool/main/v/vorbisgain/vorbisgain_0.37.orig.tar.gz",
|
|
11
|
+
"sha256": "dd6db051cad972bcac25d47b4a9e40e217bb548a1f16328eddbb4e66613530ec"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "patch",
|
|
15
|
+
"paths": [
|
|
16
|
+
"0001-temp_files.patch",
|
|
17
|
+
"0002-errno.patch",
|
|
18
|
+
"0003-manpage.patch",
|
|
19
|
+
"0004-vorbisgain_mtime.patch",
|
|
20
|
+
"0005-double_fclose.patch",
|
|
21
|
+
"0006-manpage_hyphens.patch",
|
|
22
|
+
"0007-recursively_spelling.patch",
|
|
23
|
+
"0008-manpage_recursion_mistake.patch",
|
|
24
|
+
"0009-hardening.patch",
|
|
25
|
+
"0010-fclose.patch"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared/agentProgress.ts
|
|
3
|
+
* Shared utilities for AgentProgress events — used by both Desktop and Web renderers.
|
|
4
|
+
* Source of truth: import from this file, not from the per-renderer copies.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentProgress, InteractionMemory, DiffHunk, FileChange } from './types'
|
|
7
|
+
export type { AgentProgress, InteractionMemory }
|
|
8
|
+
|
|
9
|
+
export function thoughtsFrom(progress: AgentProgress[]): string[] {
|
|
10
|
+
return progress
|
|
11
|
+
.filter((event) => event.type === 'Thought')
|
|
12
|
+
.map((event) => (event as Extract<AgentProgress, { type: 'Thought' }>).data.thought)
|
|
13
|
+
.filter(Boolean)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function trimAgentProgress(progress: AgentProgress[], maxNonThought = 20): AgentProgress[] {
|
|
17
|
+
if (progress.length === 0) return progress
|
|
18
|
+
const keptNonThought = new Set(
|
|
19
|
+
progress.filter((event) => event.type !== 'Thought').slice(-maxNonThought),
|
|
20
|
+
)
|
|
21
|
+
return progress.filter((event) => event.type === 'Thought' || keptNonThought.has(event))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function hasAgentToolActivity(progress: AgentProgress[]): boolean {
|
|
25
|
+
return progress.some((event) => event.type === 'ToolStart' || event.type === 'ToolEnd')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function mergeActivitySnapshots(
|
|
29
|
+
current: Record<string, AgentProgress[]>,
|
|
30
|
+
interactions: InteractionMemory[],
|
|
31
|
+
): Record<string, AgentProgress[]> {
|
|
32
|
+
const merged = { ...current }
|
|
33
|
+
for (const interaction of interactions) {
|
|
34
|
+
const key = String(interaction.id)
|
|
35
|
+
if (interaction.agentActivity?.length && !merged[key]) {
|
|
36
|
+
merged[key] = interaction.agentActivity
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return merged
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function parseAgentActivity(value: unknown): AgentProgress[] | undefined {
|
|
43
|
+
if (!Array.isArray(value)) return undefined
|
|
44
|
+
return value as AgentProgress[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function parseFileChangesFromProgress(progress: AgentProgress[]): FileChange[] {
|
|
48
|
+
const changes = new Map<string, FileChange>()
|
|
49
|
+
let activeEdit: { action: string; path: string; created: boolean; additions: number; deletions: number; hunks: DiffHunk[] } | null = null
|
|
50
|
+
|
|
51
|
+
for (const event of progress || []) {
|
|
52
|
+
if (event.type === 'ToolStart') {
|
|
53
|
+
if (event.data.action === 'apply_patch') {
|
|
54
|
+
const patch = (event.data.input as any)?.patch
|
|
55
|
+
if (patch && typeof patch.path === 'string') {
|
|
56
|
+
let additions = 0
|
|
57
|
+
let deletions = 0
|
|
58
|
+
const hunksList: DiffHunk[] = []
|
|
59
|
+
const hunks = patch.hunks
|
|
60
|
+
if (Array.isArray(hunks)) {
|
|
61
|
+
for (const hunk of hunks) {
|
|
62
|
+
const oldText = hunk?.oldText || ''
|
|
63
|
+
const newText = hunk?.newText || ''
|
|
64
|
+
const oldLines = oldText ? oldText.split('\n').length : 0
|
|
65
|
+
const newLines = newText ? newText.split('\n').length : 0
|
|
66
|
+
deletions += oldLines
|
|
67
|
+
additions += newLines
|
|
68
|
+
hunksList.push({ oldText, newText })
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
activeEdit = {
|
|
72
|
+
action: 'apply_patch',
|
|
73
|
+
path: patch.path,
|
|
74
|
+
created: false,
|
|
75
|
+
additions,
|
|
76
|
+
deletions,
|
|
77
|
+
hunks: hunksList
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
} else if (event.data.action === 'write_file') {
|
|
81
|
+
const path = (event.data.input as any)?.path
|
|
82
|
+
const fileContent = (event.data.input as any)?.file_content || ''
|
|
83
|
+
if (typeof path === 'string') {
|
|
84
|
+
const additions = fileContent ? fileContent.split('\n').length : 0
|
|
85
|
+
activeEdit = {
|
|
86
|
+
action: 'write_file',
|
|
87
|
+
path,
|
|
88
|
+
created: true,
|
|
89
|
+
additions,
|
|
90
|
+
deletions: 0,
|
|
91
|
+
hunks: [{ oldText: '', newText: fileContent }]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
activeEdit = null
|
|
96
|
+
}
|
|
97
|
+
} else if (event.type === 'ToolEnd') {
|
|
98
|
+
if (activeEdit && (event.data.action === 'apply_patch' || event.data.action === 'write_file')) {
|
|
99
|
+
const isError = typeof event.data.result === 'string' && event.data.result.startsWith('Error:')
|
|
100
|
+
if (!isError) {
|
|
101
|
+
try {
|
|
102
|
+
const applied = JSON.parse(event.data.result)
|
|
103
|
+
const appliedPaths = Array.isArray(applied) ? applied.map(item => item?.path).filter(Boolean) : [activeEdit.path]
|
|
104
|
+
|
|
105
|
+
for (const path of appliedPaths) {
|
|
106
|
+
const existing = changes.get(path)
|
|
107
|
+
if (existing) {
|
|
108
|
+
existing.additions += activeEdit.additions
|
|
109
|
+
existing.deletions += activeEdit.deletions
|
|
110
|
+
existing.hunks.push(...activeEdit.hunks)
|
|
111
|
+
} else {
|
|
112
|
+
changes.set(path, {
|
|
113
|
+
path,
|
|
114
|
+
created: activeEdit.created,
|
|
115
|
+
additions: activeEdit.additions,
|
|
116
|
+
deletions: activeEdit.deletions,
|
|
117
|
+
hunks: [...activeEdit.hunks]
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} catch (e) {
|
|
122
|
+
const path = activeEdit.path
|
|
123
|
+
const existing = changes.get(path)
|
|
124
|
+
if (existing) {
|
|
125
|
+
existing.additions += activeEdit.additions
|
|
126
|
+
existing.deletions += activeEdit.deletions
|
|
127
|
+
existing.hunks.push(...activeEdit.hunks)
|
|
128
|
+
} else {
|
|
129
|
+
changes.set(path, {
|
|
130
|
+
path,
|
|
131
|
+
created: activeEdit.created,
|
|
132
|
+
additions: activeEdit.additions,
|
|
133
|
+
deletions: activeEdit.deletions,
|
|
134
|
+
hunks: [...activeEdit.hunks]
|
|
135
|
+
})
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
activeEdit = null
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return Array.from(changes.values())
|
|
145
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared/calculator.ts
|
|
3
|
+
* Arithmetic expression evaluator — shared by both Desktop and Web renderers.
|
|
4
|
+
* Source of truth: import from this file, not from the per-renderer copies.
|
|
5
|
+
*/
|
|
6
|
+
export function evaluateArithmetic(source: string): number {
|
|
7
|
+
const tokens = source.replace(/\s+/g, '')
|
|
8
|
+
let index = 0
|
|
9
|
+
|
|
10
|
+
function parseExpression(): number {
|
|
11
|
+
let value = parseTerm()
|
|
12
|
+
while (tokens[index] === '+' || tokens[index] === '-') {
|
|
13
|
+
const operator = tokens[index++]
|
|
14
|
+
const right = parseTerm()
|
|
15
|
+
value = operator === '+' ? value + right : value - right
|
|
16
|
+
}
|
|
17
|
+
return value
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parseTerm(): number {
|
|
21
|
+
let value = parseFactor()
|
|
22
|
+
while (tokens[index] === '*' || tokens[index] === '/') {
|
|
23
|
+
const operator = tokens[index++]
|
|
24
|
+
const right = parseFactor()
|
|
25
|
+
value = operator === '*' ? value * right : value / right
|
|
26
|
+
}
|
|
27
|
+
return value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseFactor(): number {
|
|
31
|
+
if (tokens[index] === '+' || tokens[index] === '-') {
|
|
32
|
+
return tokens[index++] === '-' ? -parseFactor() : parseFactor()
|
|
33
|
+
}
|
|
34
|
+
if (tokens[index] === '(') {
|
|
35
|
+
index += 1
|
|
36
|
+
const value = parseExpression()
|
|
37
|
+
if (tokens[index++] !== ')') throw new Error('missing closing parenthesis')
|
|
38
|
+
return value
|
|
39
|
+
}
|
|
40
|
+
const match = tokens.slice(index).match(/^(?:\d+(?:\.\d*)?|\.\d+)/)
|
|
41
|
+
if (!match) throw new Error('expected a number')
|
|
42
|
+
index += match[0].length
|
|
43
|
+
return Number(match[0])
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!tokens) throw new Error('expression is empty')
|
|
47
|
+
const result = parseExpression()
|
|
48
|
+
if (index !== tokens.length || !Number.isFinite(result)) {
|
|
49
|
+
throw new Error('invalid arithmetic expression')
|
|
50
|
+
}
|
|
51
|
+
return result
|
|
52
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared/components/AgentActivityDrawer.tsx
|
|
3
|
+
* Togglable drawer containing the agent activities list/table.
|
|
4
|
+
* Shared by both Desktop and Web ChatPanel — do NOT duplicate this.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react'
|
|
7
|
+
import type { AgentActivityView } from '../utils/agentActivity'
|
|
8
|
+
import { AgentActivityTable } from './AgentActivityTable'
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
activityView: AgentActivityView
|
|
13
|
+
isOpen: boolean
|
|
14
|
+
onToggle: () => void
|
|
15
|
+
isHistorical?: boolean
|
|
16
|
+
pendingApproval?: boolean
|
|
17
|
+
key?: any
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
export function AgentActivityDrawer({
|
|
22
|
+
activityView,
|
|
23
|
+
isOpen,
|
|
24
|
+
onToggle,
|
|
25
|
+
isHistorical = false,
|
|
26
|
+
pendingApproval = false,
|
|
27
|
+
}: Props) {
|
|
28
|
+
if (activityView.items.length === 0) return null
|
|
29
|
+
|
|
30
|
+
if (isHistorical) {
|
|
31
|
+
return (
|
|
32
|
+
<div className="agent-activity-history">
|
|
33
|
+
<button
|
|
34
|
+
type="button"
|
|
35
|
+
className="agent-activity-toggle"
|
|
36
|
+
aria-expanded={isOpen}
|
|
37
|
+
onClick={onToggle}
|
|
38
|
+
>
|
|
39
|
+
<span>{activityView.summary}</span>
|
|
40
|
+
<span aria-hidden="true">{isOpen ? '^' : '>'}</span>
|
|
41
|
+
</button>
|
|
42
|
+
{isOpen && (
|
|
43
|
+
<div className="agent-activity-card agent-activity-card-history">
|
|
44
|
+
<AgentActivityTable activityView={activityView} />
|
|
45
|
+
</div>
|
|
46
|
+
)}
|
|
47
|
+
</div>
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Active / Live view
|
|
52
|
+
return (
|
|
53
|
+
<div className="message ai-message agent-activity-message">
|
|
54
|
+
<div className="agent-activity-card">
|
|
55
|
+
<div className="agent-activity-header" style={{ cursor: 'pointer' }} onClick={onToggle}>
|
|
56
|
+
<span>{activityView.summary}</span>
|
|
57
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
58
|
+
<span className="agent-activity-status" data-state={pendingApproval ? 'approval' : 'active'}>
|
|
59
|
+
{pendingApproval ? 'Waiting for approval' : 'Working'}
|
|
60
|
+
</span>
|
|
61
|
+
<span aria-hidden="true">{isOpen ? '^' : '>'}</span>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{isOpen && (
|
|
65
|
+
<div style={{ marginTop: '8px' }}>
|
|
66
|
+
<AgentActivityTable activityView={activityView} />
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared/components/AgentActivityTable.tsx
|
|
3
|
+
* Renders the "Working through task" activity drawer rows.
|
|
4
|
+
* Shared by both Desktop and Web ChatPanel — do NOT duplicate this.
|
|
5
|
+
*/
|
|
6
|
+
import { useState } from 'react'
|
|
7
|
+
import type { AgentActivityView } from '../utils/agentActivity'
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
activityView: AgentActivityView
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function AgentActivityTable({ activityView }: Props) {
|
|
14
|
+
const [expandedIndices, setExpandedIndices] = useState<Record<number, boolean>>({})
|
|
15
|
+
|
|
16
|
+
const toggleExpand = (index: number) => {
|
|
17
|
+
setExpandedIndices(prev => ({
|
|
18
|
+
...prev,
|
|
19
|
+
[index]: !prev[index],
|
|
20
|
+
}))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div className="agent-activity-list">
|
|
25
|
+
<div className="agent-activity-table-head" aria-hidden="true">
|
|
26
|
+
<span>Tool</span>
|
|
27
|
+
<span />
|
|
28
|
+
<span>Target</span>
|
|
29
|
+
<span />
|
|
30
|
+
</div>
|
|
31
|
+
{activityView.items.map((activity, index) => {
|
|
32
|
+
const isExpanded = !!expandedIndices[index]
|
|
33
|
+
return (
|
|
34
|
+
<div
|
|
35
|
+
className="agent-activity-item"
|
|
36
|
+
data-kind={activity.kind}
|
|
37
|
+
data-state={activity.state}
|
|
38
|
+
key={`${index}-${activity.label}-${activity.target}`}
|
|
39
|
+
style={{ cursor: 'pointer' }}
|
|
40
|
+
onClick={() => toggleExpand(index)}
|
|
41
|
+
>
|
|
42
|
+
<span className="agent-activity-label">{activity.label}</span>
|
|
43
|
+
<span className="agent-activity-icon" aria-hidden="true" />
|
|
44
|
+
<span
|
|
45
|
+
className="agent-activity-text"
|
|
46
|
+
style={isExpanded ? { whiteSpace: 'normal', wordBreak: 'break-all', overflow: 'visible', textOverflow: 'clip' } : undefined}
|
|
47
|
+
>
|
|
48
|
+
{activity.target}
|
|
49
|
+
</span>
|
|
50
|
+
<span
|
|
51
|
+
className="agent-activity-chevron"
|
|
52
|
+
style={{
|
|
53
|
+
transform: isExpanded ? 'rotate(90deg)' : 'none',
|
|
54
|
+
transition: 'transform 0.2s ease',
|
|
55
|
+
display: 'inline-block',
|
|
56
|
+
}}
|
|
57
|
+
aria-hidden="true"
|
|
58
|
+
>
|
|
59
|
+
>
|
|
60
|
+
</span>
|
|
61
|
+
</div>
|
|
62
|
+
)
|
|
63
|
+
})}
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared/components/ApprovalCard.tsx
|
|
3
|
+
* Renders the pending tool/action approval card with diffs and input fields.
|
|
4
|
+
* Shared by both Desktop and Web ChatPanel — do NOT duplicate this.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from 'react'
|
|
7
|
+
import { renderApprovalDetails, renderDiff } from '../utils/approval'
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
pendingApproval: any
|
|
12
|
+
onApproval: (approved: boolean, autoApproveSession?: boolean, answer?: string) => void
|
|
13
|
+
key?: any
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
export function ApprovalCard({ pendingApproval, onApproval }: Props) {
|
|
18
|
+
const [askAnswer, setAskAnswer] = useState('')
|
|
19
|
+
|
|
20
|
+
const details = renderApprovalDetails(pendingApproval.approval)
|
|
21
|
+
const writeFile = pendingApproval.approval?.WriteFile
|
|
22
|
+
const applyPatch = pendingApproval.approval?.ApplyPatch
|
|
23
|
+
const diffText = writeFile?.diff || applyPatch?.diff
|
|
24
|
+
const isAskUser = !!pendingApproval.approval?.AskUser
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="message ai-message" style={{ width: '100%' }}>
|
|
28
|
+
<div className="bubble-wrapper" style={{ width: '100%' }}>
|
|
29
|
+
<div className="action-card approval-card" data-tier={details.isDangerous ? 'dangerous' : undefined} style={{ width: '100%' }}>
|
|
30
|
+
<div className="approval-card-content" style={{ width: '100%' }}>
|
|
31
|
+
<div className="approval-card-title">{details.title}</div>
|
|
32
|
+
<div className="approval-card-body" style={{ whiteSpace: 'pre-wrap', fontFamily: 'monospace' }}>{details.body}</div>
|
|
33
|
+
{diffText ? (
|
|
34
|
+
<div className="approval-card-diff-container" style={{ marginTop: '8px', width: '100%' }}>
|
|
35
|
+
<div style={{ fontSize: '0.8rem', fontWeight: 600, color: 'var(--text-soft, #94a3b8)', marginBottom: '4px' }}>Diff:</div>
|
|
36
|
+
{renderDiff(diffText)}
|
|
37
|
+
</div>
|
|
38
|
+
) : (
|
|
39
|
+
details.reason && <div className="approval-card-reason" style={{ whiteSpace: 'pre-wrap', fontFamily: 'monospace' }}>{details.reason}</div>
|
|
40
|
+
)}
|
|
41
|
+
{isAskUser && (
|
|
42
|
+
<div className="approval-card-input-container" style={{ marginTop: '12px', width: '100%' }}>
|
|
43
|
+
<textarea
|
|
44
|
+
style={{
|
|
45
|
+
width: '100%',
|
|
46
|
+
minHeight: '70px',
|
|
47
|
+
padding: '10px',
|
|
48
|
+
background: 'rgba(0, 0, 0, 0.2)',
|
|
49
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
50
|
+
borderRadius: '6px',
|
|
51
|
+
color: 'var(--text-main, #f8fafc)',
|
|
52
|
+
fontSize: '0.9rem',
|
|
53
|
+
fontFamily: 'inherit',
|
|
54
|
+
resize: 'vertical',
|
|
55
|
+
outline: 'none',
|
|
56
|
+
}}
|
|
57
|
+
placeholder="Type your answer here..."
|
|
58
|
+
value={askAnswer}
|
|
59
|
+
onChange={(e) => setAskAnswer(e.target.value)}
|
|
60
|
+
/>
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
{isAskUser ? (
|
|
65
|
+
<div className="approval-card-actions">
|
|
66
|
+
<button
|
|
67
|
+
type="button"
|
|
68
|
+
className="approval-btn approval-btn-approve"
|
|
69
|
+
disabled={!askAnswer.trim()}
|
|
70
|
+
onClick={() => onApproval(true, false, askAnswer)}
|
|
71
|
+
>
|
|
72
|
+
Submit Answer
|
|
73
|
+
</button>
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
className="approval-btn approval-btn-cancel"
|
|
77
|
+
onClick={() => onApproval(false)}
|
|
78
|
+
>
|
|
79
|
+
Decline
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
) : (
|
|
83
|
+
<div className="approval-card-actions">
|
|
84
|
+
<button type="button" className="approval-btn approval-btn-approve" onClick={() => onApproval(true)}>Approve</button>
|
|
85
|
+
<button type="button" className="approval-btn" style={{ backgroundColor: 'rgba(16, 185, 129, 0.22)', borderColor: 'rgba(16, 185, 129, 0.4)', color: '#a7f3d0' }} onClick={() => onApproval(true, true)}>Approve this session</button>
|
|
86
|
+
<button type="button" className="approval-btn approval-btn-cancel" onClick={() => onApproval(false)}>Cancel</button>
|
|
87
|
+
</div>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shared/components/ChatCodeBlock.tsx
|
|
3
|
+
* Syntax-highlighted code block with copy + download actions.
|
|
4
|
+
* Shared by both Desktop and Web ChatPanel — do NOT duplicate this.
|
|
5
|
+
*/
|
|
6
|
+
import { useState } from 'react'
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
code: string
|
|
10
|
+
language: string
|
|
11
|
+
key?: any
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export function ChatCodeBlock({ code, language }: Props) {
|
|
16
|
+
const [copied, setCopied] = useState(false)
|
|
17
|
+
|
|
18
|
+
const handleCopy = async () => {
|
|
19
|
+
try {
|
|
20
|
+
await navigator.clipboard.writeText(code)
|
|
21
|
+
setCopied(true)
|
|
22
|
+
setTimeout(() => setCopied(false), 2000)
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.error('Failed to copy code: ', err)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const handleDownload = () => {
|
|
29
|
+
try {
|
|
30
|
+
const blob = new Blob([code], { type: 'text/plain;charset=utf-8' })
|
|
31
|
+
const url = URL.createObjectURL(blob)
|
|
32
|
+
const link = document.createElement('a')
|
|
33
|
+
link.href = url
|
|
34
|
+
link.download = `code.${language === 'plaintext' ? 'txt' : language}`
|
|
35
|
+
link.click()
|
|
36
|
+
URL.revokeObjectURL(url)
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error('Failed to download code: ', err)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const displayLang = language.charAt(0).toUpperCase() + language.slice(1).toLowerCase()
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div className="chat-code-block-container" style={{ whiteSpace: 'normal' }}>
|
|
46
|
+
<div className="chat-code-block-header">
|
|
47
|
+
<span className="chat-code-block-lang">{displayLang}</span>
|
|
48
|
+
<div className="chat-code-block-actions">
|
|
49
|
+
<button type="button" onClick={handleDownload} title="Download code" className="chat-code-action-btn">
|
|
50
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
51
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
52
|
+
<polyline points="7 10 12 15 17 10" />
|
|
53
|
+
<line x1="12" y1="15" x2="12" y2="3" />
|
|
54
|
+
</svg>
|
|
55
|
+
</button>
|
|
56
|
+
<button type="button" onClick={handleCopy} title="Copy code" className="chat-code-action-btn">
|
|
57
|
+
{copied ? (
|
|
58
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
|
|
59
|
+
<polyline points="20 6 9 17 4 12" />
|
|
60
|
+
</svg>
|
|
61
|
+
) : (
|
|
62
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
63
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
|
|
64
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
|
|
65
|
+
</svg>
|
|
66
|
+
)}
|
|
67
|
+
</button>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
<pre className="chat-code-block-body">
|
|
71
|
+
<code>{code}</code>
|
|
72
|
+
</pre>
|
|
73
|
+
</div>
|
|
74
|
+
)
|
|
75
|
+
}
|