diff --git a/apps/stage-tamagotchi/src-tauri/src/commands.rs b/apps/stage-tamagotchi/src-tauri/src/commands.rs index 6468d3c3..c7885883 100644 --- a/apps/stage-tamagotchi/src-tauri/src/commands.rs +++ b/apps/stage-tamagotchi/src-tauri/src/commands.rs @@ -18,3 +18,20 @@ pub async fn open_settings_window(app: tauri::AppHandle) { .build() .unwrap(); } + +#[tauri::command] +pub async fn open_chat_window(app: tauri::AppHandle) { + if let Some(window) = app.get_webview_window("chat") { + let _ = window.show(); + return; + } + + let _ = WebviewWindowBuilder::new( + &app, + "chat", + WebviewUrl::App(Path::new("#/chat").to_path_buf()), + ) + .title("chat") + .build() + .unwrap(); +} diff --git a/apps/stage-tamagotchi/src-tauri/src/lib.rs b/apps/stage-tamagotchi/src-tauri/src/lib.rs index 8e0806d9..a4167f38 100644 --- a/apps/stage-tamagotchi/src-tauri/src/lib.rs +++ b/apps/stage-tamagotchi/src-tauri/src/lib.rs @@ -1,6 +1,7 @@ use std::path::Path; use tauri::menu::{Menu, MenuItem}; use tauri::tray::TrayIconBuilder; +use tauri::RunEvent; #[cfg(target_os = "macos")] use tauri::{ActivationPolicy, TitleBarStyle}; use tauri::{Manager, WebviewUrl, WebviewWindowBuilder}; @@ -57,6 +58,7 @@ pub fn run() { .menu(&menu) .on_menu_event(|app, event| match event.id().as_ref() { "quit" => { + app.cleanup_before_exit(); app.exit(0); } "settings" => { @@ -90,10 +92,20 @@ pub fn run() { .show_menu_on_left_click(true) .build(app) .unwrap(); - Ok(()) }) - .invoke_handler(tauri::generate_handler![commands::open_settings_window]) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + .invoke_handler(tauri::generate_handler![ + commands::open_settings_window, + commands::open_chat_window + ]) + .build(tauri::generate_context!()) + .expect("error while building tauri application") + .run(|app_handle, event| match event { + RunEvent::ExitRequested { .. } => { + println!("Exiting app"); + tauri_plugin_mcp::destroy(app_handle); + println!("Exited app"); + } + _ => {} + }); } diff --git a/apps/stage-tamagotchi/vite.config.ts b/apps/stage-tamagotchi/vite.config.ts index 7f5d6b91..2a587237 100644 --- a/apps/stage-tamagotchi/vite.config.ts +++ b/apps/stage-tamagotchi/vite.config.ts @@ -60,4 +60,9 @@ export default defineConfig({ Download('https://dist.ayaka.moe/live2d-models/hiyori_free_zh.zip', 'hiyori_free_zh.zip', 'assets/live2d/models'), Download('https://dist.ayaka.moe/live2d-models/hiyori_pro_zh.zip', 'hiyori_pro_zh.zip', 'assets/live2d/models'), ], + server: { + watch: { + ignored: ['**/src-tauri/**'], + }, + }, }) diff --git a/crates/tauri-plugin-mcp/src/lib.rs b/crates/tauri-plugin-mcp/src/lib.rs index 0a1efe79..2749c027 100644 --- a/crates/tauri-plugin-mcp/src/lib.rs +++ b/crates/tauri-plugin-mcp/src/lib.rs @@ -1,3 +1,5 @@ +use std::process::Stdio; + use rmcp::model::CallToolRequestParam; use rmcp::{ model::{CallToolResult, Tool}, @@ -6,11 +8,11 @@ use rmcp::{ RoleClient, ServiceExt, }; use serde_json::{Map, Value}; -use tauri::State; use tauri::{ plugin::{self, TauriPlugin}, Manager, Runtime, }; +use tauri::{AppHandle, State}; use tokio::process::Command; use tokio::sync::Mutex; @@ -18,6 +20,24 @@ pub struct McpState { pub client: Option>, } +pub fn destroy(app_handle: &AppHandle) { + println!("Destroying MCP plugin"); + tokio::runtime::Runtime::new().unwrap().block_on(async { + let state = app_handle.state::>(); + let mut state = state.lock().await; + if state.client.is_none() { + println!("MCP plugin not connected, no need to disconnect"); + return; + } + + let client = state.client.take().unwrap(); + client.cancel().await.unwrap(); + // client.waiting().await.unwrap(); + state.client = None; + }); + println!("MCP plugin destroyed"); +} + #[tauri::command] async fn connect_server( state: State<'_, Mutex>, @@ -30,7 +50,13 @@ async fn connect_server( return Err("Client already connected".to_string()); } - let child_process = TokioChildProcess::new(Command::new(command).args(args)).unwrap(); + let child_process = TokioChildProcess::new( + Command::new(command) + .args(args) + .stderr(Stdio::inherit()) + .stdout(Stdio::inherit()), + ) + .unwrap(); let service: RunningService = ().serve(child_process).await.unwrap(); @@ -46,9 +72,13 @@ async fn disconnect_server(state: State<'_, Mutex>) -> Result<(), Stri return Err("Client not connected".to_string()); } - state.client.take().unwrap().cancel().await.unwrap(); + let cancel_result = state.client.take().unwrap().cancel().await; + println!("Cancel result: {:?}", cancel_result); + // state.client.take().unwrap().waiting().await.unwrap(); state.client = None; + println!("Disconnected from MCP server"); + Ok(()) } @@ -64,7 +94,7 @@ async fn list_tools(state: State<'_, Mutex>) -> Result, Stri .unwrap() .list_tools(Default::default()) .await - .unwrap(); + .unwrap(); // TODO: handle error let tools = list_tools_result.tools; Ok(tools) @@ -117,6 +147,9 @@ impl Builder { app_handle.manage(Mutex::new(McpState { client: None })); Ok(()) }) + .on_drop(|app_handle: AppHandle| { + destroy(&app_handle); + }) .build() } }