@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
|
@@ -110,6 +110,8 @@ enum Command {
|
|
|
110
110
|
},
|
|
111
111
|
/// Run one queued or supplied task through the native CLI agent.
|
|
112
112
|
Agent { task: Option<String> },
|
|
113
|
+
/// Start the browser automation environment and enable browser actions.
|
|
114
|
+
Auto,
|
|
113
115
|
/// Launch the web UI and local API server.
|
|
114
116
|
Web,
|
|
115
117
|
/// Start only the local API server.
|
|
@@ -453,6 +455,21 @@ enum MemoryCommand {
|
|
|
453
455
|
},
|
|
454
456
|
}
|
|
455
457
|
|
|
458
|
+
fn print_mcp_servers(servers: &std::collections::BTreeMap<String, mint_core::mcp::McpServer>) {
|
|
459
|
+
if servers.is_empty() {
|
|
460
|
+
println!("{DIM}(No MCP servers configured.){RESET}\n");
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
for (name, srv) in servers {
|
|
464
|
+
let args_str = srv.args.join(" ");
|
|
465
|
+
println!(
|
|
466
|
+
" {BLUE}●{RESET} {name} {DIM}({} {}){RESET}",
|
|
467
|
+
srv.command, args_str
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
println!();
|
|
471
|
+
}
|
|
472
|
+
|
|
456
473
|
#[tokio::main]
|
|
457
474
|
async fn main() -> Result<()> {
|
|
458
475
|
match Cli::parse().command {
|
|
@@ -523,6 +540,99 @@ async fn main() -> Result<()> {
|
|
|
523
540
|
Command::Agent { task } => {
|
|
524
541
|
run_cli_agent_task(task).await?;
|
|
525
542
|
}
|
|
543
|
+
Command::Auto => {
|
|
544
|
+
println!("🚀 Starting Mint Browser Automation Environment...");
|
|
545
|
+
let config = mint_core::load_config()?;
|
|
546
|
+
mint_core::spawn_automation_browser(&config)
|
|
547
|
+
.await
|
|
548
|
+
.map_err(anyhow::Error::msg)?;
|
|
549
|
+
|
|
550
|
+
// Enable the browser tools if they are disabled
|
|
551
|
+
let mut config_mut = config.clone();
|
|
552
|
+
let mut changed = false;
|
|
553
|
+
for tool in &[
|
|
554
|
+
"browser_open",
|
|
555
|
+
"browser_click",
|
|
556
|
+
"browser_type",
|
|
557
|
+
"browser_read",
|
|
558
|
+
] {
|
|
559
|
+
if config_mut.disabled_tools.contains(&tool.to_string()) {
|
|
560
|
+
config_mut.disabled_tools.retain(|x| x != *tool);
|
|
561
|
+
changed = true;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if changed {
|
|
565
|
+
mint_core::save_config(&config_mut)?;
|
|
566
|
+
println!(
|
|
567
|
+
"✅ Enabled browser automation tools in config: browser_open, browser_click, browser_type, browser_read"
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
println!(
|
|
572
|
+
"🌐 Isolated browser running with remote debugging on http://127.0.0.1:9222"
|
|
573
|
+
);
|
|
574
|
+
println!(
|
|
575
|
+
"💬 Keep this terminal open while you want Mint to automate browser tasks."
|
|
576
|
+
);
|
|
577
|
+
println!("Press Ctrl+C to terminate the automation browser session.");
|
|
578
|
+
println!("----------------------------------------------------------------------");
|
|
579
|
+
|
|
580
|
+
// Start tailing the log file in a background task
|
|
581
|
+
let log_dir = dirs::config_dir()
|
|
582
|
+
.unwrap_or_else(|| std::env::temp_dir())
|
|
583
|
+
.join("mint");
|
|
584
|
+
let log_file = log_dir.join("browser-automation.log");
|
|
585
|
+
|
|
586
|
+
// Clear existing log file on startup
|
|
587
|
+
let _ = std::fs::remove_file(&log_file);
|
|
588
|
+
|
|
589
|
+
let log_file_clone = log_file.clone();
|
|
590
|
+
tokio::spawn(async move {
|
|
591
|
+
use std::io::{BufRead, BufReader, Seek, SeekFrom};
|
|
592
|
+
let mut file_pos = 0;
|
|
593
|
+
loop {
|
|
594
|
+
if log_file_clone.exists() {
|
|
595
|
+
if let Ok(mut file) = std::fs::File::open(&log_file_clone) {
|
|
596
|
+
if let Ok(_) = file.seek(SeekFrom::Start(file_pos)) {
|
|
597
|
+
let reader = BufReader::new(file);
|
|
598
|
+
for line in reader.lines() {
|
|
599
|
+
if let Ok(line_str) = line {
|
|
600
|
+
if line_str.contains("[NAVIGATE]")
|
|
601
|
+
|| line_str.contains("[NAVIGATE_SUCCESS]")
|
|
602
|
+
{
|
|
603
|
+
println!("🌐 {line_str}");
|
|
604
|
+
} else if line_str.contains("[CLICK]")
|
|
605
|
+
|| line_str.contains("[CLICK_SUCCESS]")
|
|
606
|
+
{
|
|
607
|
+
println!("🖱️ {line_str}");
|
|
608
|
+
} else if line_str.contains("[TYPE]")
|
|
609
|
+
|| line_str.contains("[TYPE_SUCCESS]")
|
|
610
|
+
{
|
|
611
|
+
println!("⌨️ {line_str}");
|
|
612
|
+
} else if line_str.contains("[READ]")
|
|
613
|
+
|| line_str.contains("[READ_SUCCESS]")
|
|
614
|
+
{
|
|
615
|
+
println!("📖 {line_str}");
|
|
616
|
+
} else if line_str.contains("_ERROR]") {
|
|
617
|
+
println!("❌ {line_str}");
|
|
618
|
+
} else {
|
|
619
|
+
println!("📝 {line_str}");
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if let Ok(pos) = log_file_clone.metadata().map(|m| m.len()) {
|
|
624
|
+
file_pos = pos;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
tokio::signal::ctrl_c().await.ok();
|
|
634
|
+
println!("\n👋 Terminating Mint Browser Automation Environment...");
|
|
635
|
+
}
|
|
526
636
|
Command::Web => {
|
|
527
637
|
launch_mint_target("web".into()).await?;
|
|
528
638
|
}
|
|
@@ -539,7 +649,10 @@ async fn main() -> Result<()> {
|
|
|
539
649
|
mcp::add(&name, &command, args, env)?;
|
|
540
650
|
println!("Added MCP server: {name}");
|
|
541
651
|
}
|
|
542
|
-
McpCommand::List =>
|
|
652
|
+
McpCommand::List => {
|
|
653
|
+
println!("\n{BLUE}MCP servers:{RESET}");
|
|
654
|
+
print_mcp_servers(&mcp::list()?);
|
|
655
|
+
}
|
|
543
656
|
McpCommand::Remove { name } => {
|
|
544
657
|
println!(
|
|
545
658
|
"{}",
|
|
@@ -585,10 +698,55 @@ async fn main() -> Result<()> {
|
|
|
585
698
|
Command::Learn { path, list, delete } => {
|
|
586
699
|
let memory = MemoryStore::open_default()?;
|
|
587
700
|
if list {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
701
|
+
let mut skills = memory.learned_skills(100)?;
|
|
702
|
+
|
|
703
|
+
if let Some(home) = dirs::home_dir() {
|
|
704
|
+
let global_skills_path =
|
|
705
|
+
home.join(".config").join("mint").join("mint-skills");
|
|
706
|
+
mint_core::skills::load_skills_from_dir(&global_skills_path, &mut skills);
|
|
707
|
+
}
|
|
708
|
+
if let Ok(root) = std::env::current_dir() {
|
|
709
|
+
if let Ok(root) = root.canonicalize() {
|
|
710
|
+
let workspace_skills_path1 = root.join(".agents").join("skills");
|
|
711
|
+
mint_core::skills::load_skills_from_dir(
|
|
712
|
+
&workspace_skills_path1,
|
|
713
|
+
&mut skills,
|
|
714
|
+
);
|
|
715
|
+
|
|
716
|
+
let workspace_skills_path2 = root.join("skills");
|
|
717
|
+
mint_core::skills::load_skills_from_dir(
|
|
718
|
+
&workspace_skills_path2,
|
|
719
|
+
&mut skills,
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
let mut unique_skills = std::collections::BTreeMap::new();
|
|
725
|
+
for skill in skills {
|
|
726
|
+
let loc = if skill.source_path.contains("/.config/mint/mint-skills") {
|
|
727
|
+
"Global"
|
|
728
|
+
} else if skill.source_path.contains("/skills")
|
|
729
|
+
|| skill.source_path.contains("/.agents/skills")
|
|
730
|
+
{
|
|
731
|
+
"Workspace"
|
|
732
|
+
} else {
|
|
733
|
+
"Taught"
|
|
734
|
+
};
|
|
735
|
+
unique_skills.insert(skill.name.clone(), (skill, loc));
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if unique_skills.is_empty() {
|
|
739
|
+
println!("No learned skills found.");
|
|
740
|
+
} else {
|
|
741
|
+
println!("Learned AI Skills:");
|
|
742
|
+
for (name, (skill, loc)) in &unique_skills {
|
|
743
|
+
if *loc == "Taught" {
|
|
744
|
+
println!(" ● [{}] {}", loc, name);
|
|
745
|
+
} else {
|
|
746
|
+
println!(" ● [{}] {} (Source: {})", loc, name, skill.source_path);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
592
750
|
} else if let Some(identifier) = delete {
|
|
593
751
|
println!("{}", memory.delete_learned_skill(&identifier)?);
|
|
594
752
|
} else if let Some(path) = path {
|
|
@@ -645,6 +803,7 @@ async fn main() -> Result<()> {
|
|
|
645
803
|
audio_data_uri: None,
|
|
646
804
|
document_attachment: None,
|
|
647
805
|
workspace_path: None,
|
|
806
|
+
agent_id: None,
|
|
648
807
|
},
|
|
649
808
|
)
|
|
650
809
|
.await?;
|
|
@@ -1315,6 +1474,9 @@ impl CliStreamFormatter {
|
|
|
1315
1474
|
print_fn(ch);
|
|
1316
1475
|
}
|
|
1317
1476
|
print_fn('\n');
|
|
1477
|
+
for ch in " ".chars() {
|
|
1478
|
+
print_fn(ch);
|
|
1479
|
+
}
|
|
1318
1480
|
} else {
|
|
1319
1481
|
if is_table_line(&line) {
|
|
1320
1482
|
self.table_buffer.push(line);
|
|
@@ -1327,6 +1489,9 @@ impl CliStreamFormatter {
|
|
|
1327
1489
|
print_fn(ch);
|
|
1328
1490
|
}
|
|
1329
1491
|
print_fn('\n');
|
|
1492
|
+
for ch in " ".chars() {
|
|
1493
|
+
print_fn(ch);
|
|
1494
|
+
}
|
|
1330
1495
|
}
|
|
1331
1496
|
}
|
|
1332
1497
|
}
|
|
@@ -1597,8 +1762,12 @@ async fn handle_slash_command(
|
|
|
1597
1762
|
("/mcp list", "List configured MCP servers"),
|
|
1598
1763
|
("/mcp allow <server> <tool>", "Allow an MCP tool"),
|
|
1599
1764
|
("/stats", "Show session statistics"),
|
|
1600
|
-
("/exit
|
|
1765
|
+
("/exit", "Exit Mint"),
|
|
1601
1766
|
("/code <task>", "Run in code-agent mode"),
|
|
1767
|
+
(
|
|
1768
|
+
"/multi-agent [on|off]",
|
|
1769
|
+
"Show or toggle Multi-Agent Collaboration system",
|
|
1770
|
+
),
|
|
1602
1771
|
];
|
|
1603
1772
|
for (cmd_name, desc) in &commands {
|
|
1604
1773
|
println!(" {MINT}{:<30}{RESET} {DIM}{}{RESET}", cmd_name, desc);
|
|
@@ -1639,13 +1808,77 @@ async fn handle_slash_command(
|
|
|
1639
1808
|
println!();
|
|
1640
1809
|
} else {
|
|
1641
1810
|
session.config.ai_provider = rest.to_owned();
|
|
1811
|
+
match mint_core::save_config(&session.config) {
|
|
1812
|
+
Ok(()) => {
|
|
1813
|
+
let active_model = active_model(&session.config.ai_provider, &session.config);
|
|
1814
|
+
let display_name = format!("Changed model to {} • {}", session.config.ai_provider, active_model);
|
|
1815
|
+
|
|
1816
|
+
// Save system event interaction in memory
|
|
1817
|
+
if let Ok(memory) = MemoryStore::open_default() {
|
|
1818
|
+
let _ = memory.add_interaction_for_chat_with_fallback(
|
|
1819
|
+
CHAT_CLI_ID,
|
|
1820
|
+
&display_name,
|
|
1821
|
+
"",
|
|
1822
|
+
"system",
|
|
1823
|
+
"provider_change",
|
|
1824
|
+
None,
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
println!(
|
|
1829
|
+
"\n{DIM}───{RESET} {MINT}{}{RESET} {DIM}───{RESET}\n",
|
|
1830
|
+
display_name
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
Err(error) => println!("{ERROR}Config error:{RESET} {error}"),
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
Some(SlashResult::Handled)
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
"/multi-agent" => {
|
|
1840
|
+
if rest == "on" || rest == "off" {
|
|
1841
|
+
session.config.enable_agent_collaboration = rest == "on";
|
|
1642
1842
|
match mint_core::save_config(&session.config) {
|
|
1643
1843
|
Ok(()) => println!(
|
|
1644
|
-
"{DIM}
|
|
1645
|
-
session.config.
|
|
1844
|
+
"{DIM}Multi-Agent collaboration set to: {}{RESET}\n",
|
|
1845
|
+
if session.config.enable_agent_collaboration { "Enabled" } else { "Disabled" }
|
|
1646
1846
|
),
|
|
1647
|
-
Err(error) => println!("{ERROR}Config error:{RESET} {error}"),
|
|
1847
|
+
Err(error) => println!("{ERROR}Config error:{RESET} {error}\n"),
|
|
1648
1848
|
}
|
|
1849
|
+
} else if !rest.is_empty() {
|
|
1850
|
+
println!("{WARN}Usage: /multi-agent [on|off]{RESET}\n");
|
|
1851
|
+
} else {
|
|
1852
|
+
println!("\n{BLUE}Multi-Agent System Settings:{RESET}");
|
|
1853
|
+
let collab_status = if session.config.enable_agent_collaboration {
|
|
1854
|
+
format!("{MINT}Enabled (on){RESET}")
|
|
1855
|
+
} else {
|
|
1856
|
+
format!("{DIM}Disabled (off){RESET}")
|
|
1857
|
+
};
|
|
1858
|
+
println!(" Global Collaboration: {collab_status}");
|
|
1859
|
+
println!("\n{BLUE}Configured Agents:{RESET}");
|
|
1860
|
+
if session.config.agents.is_empty() {
|
|
1861
|
+
println!(" No agents configured.");
|
|
1862
|
+
} else {
|
|
1863
|
+
for agent in &session.config.agents {
|
|
1864
|
+
let status_label = if agent.enabled {
|
|
1865
|
+
format!("{MINT}[Enabled]{RESET}")
|
|
1866
|
+
} else {
|
|
1867
|
+
format!("{DIM}[Disabled]{RESET}")
|
|
1868
|
+
};
|
|
1869
|
+
println!(
|
|
1870
|
+
" {:<15} {} Provider: {:<12} Model: {}",
|
|
1871
|
+
agent.name, status_label, agent.provider, agent.model
|
|
1872
|
+
);
|
|
1873
|
+
let truncated_instruction = if agent.system_instruction.len() > 60 {
|
|
1874
|
+
format!("{}...", &agent.system_instruction[..60].replace('\n', " "))
|
|
1875
|
+
} else {
|
|
1876
|
+
agent.system_instruction.replace('\n', " ")
|
|
1877
|
+
};
|
|
1878
|
+
println!(" {DIM}Instruction: {truncated_instruction}{RESET}");
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
println!();
|
|
1649
1882
|
}
|
|
1650
1883
|
Some(SlashResult::Handled)
|
|
1651
1884
|
}
|
|
@@ -1792,7 +2025,56 @@ async fn handle_slash_command(
|
|
|
1792
2025
|
|
|
1793
2026
|
"/learn" => {
|
|
1794
2027
|
if rest.is_empty() {
|
|
1795
|
-
|
|
2028
|
+
let mut skills = match MemoryStore::open_default() {
|
|
2029
|
+
Ok(m) => match m.learned_skills(100) {
|
|
2030
|
+
Ok(s) => s,
|
|
2031
|
+
Err(e) => {
|
|
2032
|
+
println!("{ERROR}Error loading custom skills: {e}{RESET}\n");
|
|
2033
|
+
return Some(SlashResult::Handled);
|
|
2034
|
+
}
|
|
2035
|
+
},
|
|
2036
|
+
Err(e) => {
|
|
2037
|
+
println!("{ERROR}Memory error: {e}{RESET}\n");
|
|
2038
|
+
return Some(SlashResult::Handled);
|
|
2039
|
+
}
|
|
2040
|
+
};
|
|
2041
|
+
|
|
2042
|
+
if let Some(home) = dirs::home_dir() {
|
|
2043
|
+
let global_skills_path = home.join(".config").join("mint").join("mint-skills");
|
|
2044
|
+
mint_core::skills::load_skills_from_dir(&global_skills_path, &mut skills);
|
|
2045
|
+
}
|
|
2046
|
+
let workspace_skills_path1 = session.current_dir.join(".agents").join("skills");
|
|
2047
|
+
mint_core::skills::load_skills_from_dir(&workspace_skills_path1, &mut skills);
|
|
2048
|
+
let workspace_skills_path2 = session.current_dir.join("skills");
|
|
2049
|
+
mint_core::skills::load_skills_from_dir(&workspace_skills_path2, &mut skills);
|
|
2050
|
+
|
|
2051
|
+
let mut unique_skills = std::collections::BTreeMap::new();
|
|
2052
|
+
for skill in skills {
|
|
2053
|
+
let loc = if skill.source_path.contains("/.config/mint/mint-skills") {
|
|
2054
|
+
"Global"
|
|
2055
|
+
} else if skill.source_path.contains("/skills")
|
|
2056
|
+
|| skill.source_path.contains("/.agents/skills")
|
|
2057
|
+
{
|
|
2058
|
+
"Workspace"
|
|
2059
|
+
} else {
|
|
2060
|
+
"Taught"
|
|
2061
|
+
};
|
|
2062
|
+
unique_skills.insert(skill.name.clone(), (skill, loc));
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
if unique_skills.is_empty() {
|
|
2066
|
+
println!("No learned skills found. Use '/learn <path>' to add one.\n");
|
|
2067
|
+
} else {
|
|
2068
|
+
println!("Learned AI Skills:");
|
|
2069
|
+
for (name, (skill, loc)) in &unique_skills {
|
|
2070
|
+
if *loc == "Taught" {
|
|
2071
|
+
println!(" ● [{}] {}", loc, name);
|
|
2072
|
+
} else {
|
|
2073
|
+
println!(" ● [{}] {} (Source: {})", loc, name, skill.source_path);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
println!();
|
|
2077
|
+
}
|
|
1796
2078
|
} else {
|
|
1797
2079
|
let path = PathBuf::from(rest);
|
|
1798
2080
|
let path = if path.is_absolute() {
|
|
@@ -1834,8 +2116,10 @@ async fn handle_slash_command(
|
|
|
1834
2116
|
println!(
|
|
1835
2117
|
" {DIM}[{}]{RESET} {BLUE}You:{RESET} {}",
|
|
1836
2118
|
&item.created_at[..16.min(item.created_at.len())],
|
|
1837
|
-
if item.user_text.
|
|
1838
|
-
|
|
2119
|
+
if item.user_text.chars().count() > 80 {
|
|
2120
|
+
let short: String =
|
|
2121
|
+
item.user_text.chars().take(80).collect();
|
|
2122
|
+
format!("{}…", short)
|
|
1839
2123
|
} else {
|
|
1840
2124
|
item.user_text.clone()
|
|
1841
2125
|
}
|
|
@@ -1903,15 +2187,9 @@ async fn handle_slash_command(
|
|
|
1903
2187
|
.unwrap_or((rest, ""));
|
|
1904
2188
|
match subcmd {
|
|
1905
2189
|
"list" | "" => match mcp::list() {
|
|
1906
|
-
Ok(servers) if servers.is_empty() => {
|
|
1907
|
-
println!("{DIM}No MCP servers configured.{RESET}\n");
|
|
1908
|
-
}
|
|
1909
2190
|
Ok(servers) => {
|
|
1910
2191
|
println!("\n{BLUE}MCP servers:{RESET}");
|
|
1911
|
-
|
|
1912
|
-
Ok(json) => println!("{json}\n"),
|
|
1913
|
-
Err(e) => println!("{ERROR}Error:{RESET} {e}\n"),
|
|
1914
|
-
}
|
|
2192
|
+
print_mcp_servers(&servers);
|
|
1915
2193
|
}
|
|
1916
2194
|
Err(e) => println!("{ERROR}MCP error:{RESET} {e}\n"),
|
|
1917
2195
|
},
|
|
@@ -2291,7 +2569,7 @@ async fn run_interactive_chat() -> Result<()> {
|
|
|
2291
2569
|
.to_owned();
|
|
2292
2570
|
|
|
2293
2571
|
println!();
|
|
2294
|
-
print!("{MINT}Mint:{RESET} {DIM}Thinking...{RESET}");
|
|
2572
|
+
print!(" {MINT}Mint:{RESET} {DIM}Thinking...{RESET}");
|
|
2295
2573
|
let _ = io::stdout().flush();
|
|
2296
2574
|
|
|
2297
2575
|
let mut system_instruction = format!(
|
|
@@ -2333,11 +2611,12 @@ async fn run_interactive_chat() -> Result<()> {
|
|
|
2333
2611
|
audio_data_uri: None,
|
|
2334
2612
|
document_attachment: None,
|
|
2335
2613
|
workspace_path: None,
|
|
2614
|
+
agent_id: None,
|
|
2336
2615
|
},
|
|
2337
2616
|
|chunk| {
|
|
2338
2617
|
if first_chunk {
|
|
2339
2618
|
first_chunk = false;
|
|
2340
|
-
print!("\r\x1b[2K{MINT}Mint:{RESET} ");
|
|
2619
|
+
print!("\r\x1b[2K {MINT}Mint:{RESET} ");
|
|
2341
2620
|
}
|
|
2342
2621
|
filter.process_chunk(&chunk, |text| {
|
|
2343
2622
|
for c in text.chars() {
|
|
@@ -2426,51 +2705,69 @@ fn print_exit_message(session: &InteractiveSession) {
|
|
|
2426
2705
|
}
|
|
2427
2706
|
|
|
2428
2707
|
const AUTOCOMPLETE_COMMANDS: &[(&str, &str)] = &[
|
|
2429
|
-
("/
|
|
2708
|
+
("/cd", "Change active workspace directory"),
|
|
2709
|
+
("/clear", "Clear conversation history"),
|
|
2710
|
+
("/code", "Run in code-agent mode"),
|
|
2711
|
+
("/exit", "Exit Mint CLI"),
|
|
2430
2712
|
("/fast", "Toggle fast mode (hide thinking traces)"),
|
|
2431
|
-
("/
|
|
2713
|
+
("/help", "Show help menu"),
|
|
2714
|
+
("/image", "Attach image from disk"),
|
|
2432
2715
|
(
|
|
2433
2716
|
"/image-provider",
|
|
2434
2717
|
"List image gen providers or switch default provider",
|
|
2435
2718
|
),
|
|
2436
|
-
("/clear", "Clear conversation history"),
|
|
2437
|
-
("/cd", "Change active workspace directory"),
|
|
2438
|
-
("/image", "Attach image from disk"),
|
|
2439
|
-
("/paste", "Attach image from clipboard"),
|
|
2440
2719
|
("/learn", "Import persistent skill/instruction"),
|
|
2441
|
-
("/plugins", "List or generate plugins/skills"),
|
|
2442
|
-
("/memory", "Manage long-term memory store"),
|
|
2443
2720
|
("/mcp", "List configured MCP servers"),
|
|
2721
|
+
("/memory", "Manage long-term memory store"),
|
|
2722
|
+
("/models", "List AI providers or switch active provider"),
|
|
2723
|
+
("/multi-agent", "Show or toggle Multi-Agent Collaboration system"),
|
|
2724
|
+
("/paste", "Attach image from clipboard"),
|
|
2725
|
+
("/plugins", "List or generate plugins/skills"),
|
|
2444
2726
|
("/stats", "Show session statistics"),
|
|
2445
|
-
("/exit", "Exit Mint CLI"),
|
|
2446
|
-
("/quit", "Exit Mint CLI"),
|
|
2447
|
-
("/code", "Run in code-agent mode"),
|
|
2448
2727
|
];
|
|
2449
2728
|
|
|
2450
2729
|
fn draw_input_box(
|
|
2451
|
-
|
|
2730
|
+
input_chars: &[char],
|
|
2731
|
+
cursor_pos: usize,
|
|
2452
2732
|
placeholder: &str,
|
|
2453
2733
|
model: &str,
|
|
2454
2734
|
path_str: &str,
|
|
2455
2735
|
tab_base_input: Option<&str>,
|
|
2456
2736
|
tab_index: Option<usize>,
|
|
2457
|
-
) -> usize {
|
|
2737
|
+
) -> (usize, usize) {
|
|
2458
2738
|
let (term_width, _) = crossterm::terminal::size().unwrap_or((80, 24));
|
|
2459
2739
|
let width = term_width as usize;
|
|
2460
2740
|
let prefix = "› ";
|
|
2461
2741
|
let input_width = width.saturating_sub(2);
|
|
2462
2742
|
let content_max_len = input_width.saturating_sub(prefix.chars().count());
|
|
2463
2743
|
|
|
2464
|
-
let
|
|
2744
|
+
let mut start_idx = 0;
|
|
2745
|
+
if input_chars.len() > content_max_len {
|
|
2746
|
+
if cursor_pos >= content_max_len {
|
|
2747
|
+
start_idx = (cursor_pos + 5).saturating_sub(content_max_len);
|
|
2748
|
+
if start_idx + content_max_len > input_chars.len() {
|
|
2749
|
+
start_idx = input_chars.len() - content_max_len;
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
let slice_chars = if input_chars.len() > content_max_len {
|
|
2755
|
+
&input_chars[start_idx..std::cmp::min(start_idx + content_max_len, input_chars.len())]
|
|
2756
|
+
} else {
|
|
2757
|
+
input_chars
|
|
2758
|
+
};
|
|
2759
|
+
let displayed_input: String = slice_chars.iter().collect();
|
|
2760
|
+
|
|
2761
|
+
let display_str = if displayed_input.is_empty() {
|
|
2465
2762
|
format!("{DIM}{}\x1b[39m", placeholder)
|
|
2466
2763
|
} else {
|
|
2467
|
-
format_placeholders(
|
|
2764
|
+
format_placeholders(&displayed_input)
|
|
2468
2765
|
};
|
|
2469
2766
|
|
|
2470
|
-
let visible_len = if
|
|
2767
|
+
let visible_len = if displayed_input.is_empty() {
|
|
2471
2768
|
placeholder.chars().count()
|
|
2472
2769
|
} else {
|
|
2473
|
-
string_visual_width(
|
|
2770
|
+
string_visual_width(&displayed_input)
|
|
2474
2771
|
};
|
|
2475
2772
|
|
|
2476
2773
|
let pad_len = content_max_len.saturating_sub(visible_len);
|
|
@@ -2498,7 +2795,8 @@ fn draw_input_box(
|
|
|
2498
2795
|
);
|
|
2499
2796
|
|
|
2500
2797
|
// Compute and draw suggestions
|
|
2501
|
-
let
|
|
2798
|
+
let raw_input: String = input_chars.iter().collect();
|
|
2799
|
+
let search_query = tab_base_input.unwrap_or(&raw_input);
|
|
2502
2800
|
let mut match_count = 0;
|
|
2503
2801
|
if search_query.starts_with('/') {
|
|
2504
2802
|
let matches: Vec<_> = AUTOCOMPLETE_COMMANDS
|
|
@@ -2507,11 +2805,18 @@ fn draw_input_box(
|
|
|
2507
2805
|
.collect();
|
|
2508
2806
|
|
|
2509
2807
|
if !matches.is_empty() {
|
|
2510
|
-
|
|
2511
|
-
println!();
|
|
2512
|
-
println!(" {BLUE}Suggestions{RESET}");
|
|
2808
|
+
let total_pages = (matches.len() + 4) / 5;
|
|
2513
2809
|
let highlight_idx = tab_index.map(|idx| idx % matches.len());
|
|
2514
|
-
|
|
2810
|
+
let selected_idx = highlight_idx.unwrap_or(0);
|
|
2811
|
+
let current_page = selected_idx / 5;
|
|
2812
|
+
let start_idx = current_page * 5;
|
|
2813
|
+
let end_idx = std::cmp::min(start_idx + 5, matches.len());
|
|
2814
|
+
match_count = end_idx - start_idx;
|
|
2815
|
+
|
|
2816
|
+
println!();
|
|
2817
|
+
println!(" {BLUE}Suggestions ({}/{}){RESET}", current_page + 1, total_pages);
|
|
2818
|
+
for i in start_idx..end_idx {
|
|
2819
|
+
let (cmd, desc) = matches[i];
|
|
2515
2820
|
if Some(i) == highlight_idx {
|
|
2516
2821
|
println!(" {BLUE}▶ {:<16}{RESET} {DIM}- {}{RESET}", cmd, desc);
|
|
2517
2822
|
} else {
|
|
@@ -2522,11 +2827,29 @@ fn draw_input_box(
|
|
|
2522
2827
|
}
|
|
2523
2828
|
|
|
2524
2829
|
let _ = io::stdout().flush();
|
|
2525
|
-
match_count
|
|
2830
|
+
(match_count, start_idx)
|
|
2526
2831
|
}
|
|
2527
2832
|
|
|
2528
2833
|
fn input_cursor_column(input_chars: &[char], cursor_pos: usize) -> usize {
|
|
2529
|
-
let
|
|
2834
|
+
let (term_width, _) = crossterm::terminal::size().unwrap_or((80, 24));
|
|
2835
|
+
let width = term_width as usize;
|
|
2836
|
+
let prefix = "› ";
|
|
2837
|
+
let input_width = width.saturating_sub(2);
|
|
2838
|
+
let content_max_len = input_width.saturating_sub(prefix.chars().count());
|
|
2839
|
+
|
|
2840
|
+
let mut start_idx = 0;
|
|
2841
|
+
if input_chars.len() > content_max_len {
|
|
2842
|
+
if cursor_pos >= content_max_len {
|
|
2843
|
+
start_idx = (cursor_pos + 5).saturating_sub(content_max_len);
|
|
2844
|
+
if start_idx + content_max_len > input_chars.len() {
|
|
2845
|
+
start_idx = input_chars.len() - content_max_len;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
let cursor_pos_clamped = std::cmp::min(cursor_pos, input_chars.len());
|
|
2851
|
+
let start_idx_clamped = std::cmp::min(start_idx, cursor_pos_clamped);
|
|
2852
|
+
let visual_cursor_pos: usize = input_chars[start_idx_clamped..cursor_pos_clamped]
|
|
2530
2853
|
.iter()
|
|
2531
2854
|
.copied()
|
|
2532
2855
|
.map(char_visual_width)
|
|
@@ -2557,9 +2880,9 @@ fn redraw_input_box(
|
|
|
2557
2880
|
tab_index: Option<usize>,
|
|
2558
2881
|
) {
|
|
2559
2882
|
clear_input_box();
|
|
2560
|
-
let
|
|
2561
|
-
|
|
2562
|
-
|
|
2883
|
+
let (match_count, _) = draw_input_box(
|
|
2884
|
+
input_chars,
|
|
2885
|
+
cursor_pos,
|
|
2563
2886
|
placeholder,
|
|
2564
2887
|
model,
|
|
2565
2888
|
path_str,
|
|
@@ -2590,7 +2913,7 @@ fn read_line_interactive(
|
|
|
2590
2913
|
let mut tab_base_input: Option<String> = None;
|
|
2591
2914
|
let mut tab_index: Option<usize> = None;
|
|
2592
2915
|
|
|
2593
|
-
let match_count = draw_input_box(
|
|
2916
|
+
let (match_count, _) = draw_input_box(&input_chars, cursor_pos, placeholder, model, path_str, None, None);
|
|
2594
2917
|
position_input_cursor(&input_chars, cursor_pos, match_count);
|
|
2595
2918
|
let _ = io::stdout().flush();
|
|
2596
2919
|
|
|
@@ -2709,12 +3032,7 @@ fn read_line_interactive(
|
|
|
2709
3032
|
}
|
|
2710
3033
|
}
|
|
2711
3034
|
KeyCode::Char(c) => {
|
|
2712
|
-
|
|
2713
|
-
let max_width = (term_width as usize).saturating_sub(4);
|
|
2714
|
-
let current_visual_width: usize =
|
|
2715
|
-
input_chars.iter().copied().map(char_visual_width).sum();
|
|
2716
|
-
|
|
2717
|
-
if current_visual_width < max_width {
|
|
3035
|
+
if input_chars.len() < 10000 {
|
|
2718
3036
|
input_chars.insert(cursor_pos, c);
|
|
2719
3037
|
cursor_pos += 1;
|
|
2720
3038
|
|
|
@@ -2883,13 +3201,15 @@ fn read_line_interactive(
|
|
|
2883
3201
|
}
|
|
2884
3202
|
}
|
|
2885
3203
|
disable_raw_mode()?;
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
3204
|
+
redraw_input_box(
|
|
3205
|
+
&input_chars,
|
|
3206
|
+
cursor_pos,
|
|
3207
|
+
placeholder,
|
|
3208
|
+
model,
|
|
3209
|
+
path_str,
|
|
3210
|
+
None,
|
|
3211
|
+
None,
|
|
3212
|
+
);
|
|
2893
3213
|
enable_raw_mode()?;
|
|
2894
3214
|
}
|
|
2895
3215
|
KeyCode::Right => {
|
|
@@ -2902,13 +3222,15 @@ fn read_line_interactive(
|
|
|
2902
3222
|
}
|
|
2903
3223
|
}
|
|
2904
3224
|
disable_raw_mode()?;
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
3225
|
+
redraw_input_box(
|
|
3226
|
+
&input_chars,
|
|
3227
|
+
cursor_pos,
|
|
3228
|
+
placeholder,
|
|
3229
|
+
model,
|
|
3230
|
+
path_str,
|
|
3231
|
+
None,
|
|
3232
|
+
None,
|
|
3233
|
+
);
|
|
2912
3234
|
enable_raw_mode()?;
|
|
2913
3235
|
}
|
|
2914
3236
|
KeyCode::Enter => {
|
|
@@ -2926,7 +3248,7 @@ fn read_line_interactive(
|
|
|
2926
3248
|
expanded_str = expanded_str.replace(placeholder_str, content);
|
|
2927
3249
|
}
|
|
2928
3250
|
|
|
2929
|
-
println!("{BLUE}You ›{RESET} {}", expanded_str);
|
|
3251
|
+
println!(" {BLUE}You ›{RESET} {}", expanded_str);
|
|
2930
3252
|
let _ = io::stdout().flush();
|
|
2931
3253
|
|
|
2932
3254
|
break Some(InteractiveInput {
|
|
@@ -3157,7 +3479,7 @@ pub fn confirm(prompt: &str) -> Result<bool> {
|
|
|
3157
3479
|
.to_string();
|
|
3158
3480
|
|
|
3159
3481
|
if SESSION_APPROVED.load(std::sync::atomic::Ordering::Relaxed) {
|
|
3160
|
-
println!("{} {MINT}Approve (session-wide){RESET}", clean_prompt);
|
|
3482
|
+
println!(" {} {MINT}Approve (session-wide){RESET}", clean_prompt);
|
|
3161
3483
|
return Ok(true);
|
|
3162
3484
|
}
|
|
3163
3485
|
|
|
@@ -3166,7 +3488,7 @@ pub fn confirm(prompt: &str) -> Result<bool> {
|
|
|
3166
3488
|
use crossterm::tty::IsTty;
|
|
3167
3489
|
|
|
3168
3490
|
if !io::stdout().is_tty() || enable_raw_mode().is_err() {
|
|
3169
|
-
print!("{} [y/N] ", clean_prompt);
|
|
3491
|
+
print!(" {} [y/N] ", clean_prompt);
|
|
3170
3492
|
let _ = io::stdout().flush();
|
|
3171
3493
|
let mut answer = String::new();
|
|
3172
3494
|
io::stdin().read_line(&mut answer)?;
|
|
@@ -3177,7 +3499,7 @@ pub fn confirm(prompt: &str) -> Result<bool> {
|
|
|
3177
3499
|
}
|
|
3178
3500
|
|
|
3179
3501
|
let _ = disable_raw_mode();
|
|
3180
|
-
println!("{}", clean_prompt);
|
|
3502
|
+
println!(" {}", clean_prompt);
|
|
3181
3503
|
|
|
3182
3504
|
let options = ["Approve", "Approve this session", "No"];
|
|
3183
3505
|
let mut selected = 0;
|
|
@@ -3284,7 +3606,7 @@ pub fn confirm(prompt: &str) -> Result<bool> {
|
|
|
3284
3606
|
1 => format!("{MINT}Approve this session{RESET}"),
|
|
3285
3607
|
_ => format!("{ERROR}No{RESET}"),
|
|
3286
3608
|
};
|
|
3287
|
-
println!("{} {}", clean_prompt, result_str);
|
|
3609
|
+
println!(" {} {}", clean_prompt, result_str);
|
|
3288
3610
|
let _ = io::stdout().flush();
|
|
3289
3611
|
|
|
3290
3612
|
match choice {
|
|
@@ -3357,6 +3679,7 @@ async fn run_github_overview(repo: &str, config: &MintConfig) -> Result<()> {
|
|
|
3357
3679
|
audio_data_uri: None,
|
|
3358
3680
|
document_attachment: None,
|
|
3359
3681
|
workspace_path: None,
|
|
3682
|
+
agent_id: None,
|
|
3360
3683
|
},
|
|
3361
3684
|
)
|
|
3362
3685
|
.await?;
|