refactor: eradicate deprecated tools (sticky_notes, pinned_files, context_workspaces, pr_checklist, preferences) and dead code

This commit is contained in:
Riz Ashraf committed 2026-10-07 11:12:42 +01:00
1 parent d80915635f
commit 79209da711
31 files changed
+1230 -3920

No files matched your search

+201 -213
View File
@@ -1,6 +1,6 @@
use crate::router::McpTool;
use crate::state::MemoryState;
use crate::tools::{ReadClipboardTool, WriteClipboardTool};
use crate::tools::{ClipboardAction, ClipboardTool};
use arboard::{Clipboard, ImageData};
use async_trait::async_trait;
use image::{ImageBuffer, imageops::FilterType};
@@ -8,104 +8,6 @@ use serde_json::{Value, json};
use std::borrow::Cow;
use std::sync::Arc;
pub struct WriteClipboardHandler;
#[async_trait]
impl McpTool for WriteClipboardHandler {
fn name(&self) -> &'static str {
"write_clipboard"
}
fn schema(&self) -> Value {
crate::mcp::tool_def::<WriteClipboardTool>(
"write_clipboard",
"Write text, HTML, files, and/or images directly to the OS clipboard.",
)
}
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let tool_args: WriteClipboardTool = serde_json::from_value(args)
.map_err(|e| crate::error::AppError::Internal(format!("Invalid args: {}", e)))?;
let res = tokio::task::spawn_blocking(move || {
let mut msgs = Vec::new();
if let Some(text) = &tool_args.text {
let mut written = false;
if let Ok(mut clipboard) = Clipboard::new() {
for _ in 0..3 {
if clipboard.set_text(text).is_ok() {
written = true;
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
}
if written {
msgs.push("Wrote text");
}
}
// Handle arboard for image
if let Some(image_path) = &tool_args.image_path {
match image::open(image_path) {
Ok(img) => {
let img = if img.width() > 2048 || img.height() > 2048 {
img.resize(2048, 2048, FilterType::Triangle)
} else {
img
};
let rgba = img.into_rgba8();
let (w, h) = rgba.dimensions();
let raw_bytes = rgba.into_raw();
let mut written = false;
if let Ok(mut clipboard) = arboard::Clipboard::new() {
for _ in 0..3 {
let img_data = ImageData {
width: w as usize,
height: h as usize,
bytes: Cow::Borrowed(&raw_bytes),
};
if clipboard.set_image(img_data).is_ok() {
written = true;
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
}
if written {
msgs.push("Wrote image");
} else {
return Err(crate::error::AppError::Internal(
"Failed to write image to clipboard".to_string(),
));
}
}
Err(e) => {
return Err(crate::error::AppError::Internal(format!(
"Failed to open image {}: {}",
image_path, e
)));
}
}
}
if msgs.is_empty() {
Ok("No valid clipboard data provided or failed to write.".to_string())
} else {
Ok(format!(
"Successfully populated clipboard: {}",
msgs.join(", ")
))
}
})
.await
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
state.record_activity("clipboard", &res, None);
Ok(res)
}
}
pub fn get_native_clipboard_text() -> Option<String> {
for _ in 0..3 {
@@ -121,7 +23,53 @@ pub fn get_native_clipboard_text() -> Option<String> {
None
}
#[cfg(target_os = "windows")]
fn get_windows_png_clipboard_image() -> Option<image::DynamicImage> {
use windows_sys::Win32::System::DataExchange::{
CloseClipboard, GetClipboardData, IsClipboardFormatAvailable, OpenClipboard,
RegisterClipboardFormatW,
};
use windows_sys::Win32::System::Memory::{GlobalLock, GlobalSize, GlobalUnlock};
let format_name: Vec<u16> = "PNG\0".encode_utf16().collect();
unsafe {
let format_id = RegisterClipboardFormatW(format_name.as_ptr());
if format_id == 0 {
return None;
}
for _ in 0..3 {
if OpenClipboard(std::ptr::null_mut()) != 0 {
let has_format = IsClipboardFormatAvailable(format_id) != 0;
let mut img_opt = None;
if has_format {
let handle = GetClipboardData(format_id);
if !handle.is_null() {
let size = GlobalSize(handle as _);
if size > 0 {
let ptr = GlobalLock(handle as _);
if !ptr.is_null() {
let slice = std::slice::from_raw_parts(ptr as *const u8, size);
img_opt = image::load_from_memory(slice).ok();
GlobalUnlock(handle as _);
}
}
}
}
CloseClipboard();
if img_opt.is_some() {
return img_opt;
}
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
}
None
}
pub fn get_native_clipboard_image() -> Option<image::DynamicImage> {
#[cfg(target_os = "windows")]
if let Some(img) = get_windows_png_clipboard_image() {
return Some(img);
}
for _ in 0..3 {
if let Ok(mut clipboard) = arboard::Clipboard::new() {
if let Ok(image_data) = clipboard.get_image() {
@@ -139,105 +87,6 @@ pub fn get_native_clipboard_image() -> Option<image::DynamicImage> {
None
}
pub struct ReadClipboardHandler;
#[async_trait]
impl McpTool for ReadClipboardHandler {
fn name(&self) -> &'static str {
"read_clipboard"
}
fn schema(&self) -> Value {
crate::mcp::tool_def::<ReadClipboardTool>(
"read_clipboard",
"Read the current OS clipboard. Extracts text, HTML, file paths, and/or an image if available.",
)
}
async fn execute(&self, _args: Value, state: Arc<MemoryState>) -> crate::error::Result<String> {
let result =
tokio::task::spawn_blocking(move || -> crate::error::Result<serde_json::Value> {
let mut out = serde_json::Map::new();
if let Some(text) = get_native_clipboard_text() {
out.insert("text".into(), json!(text));
}
if let Some(dynamic_img) = get_native_clipboard_image() {
let mut img = dynamic_img;
let max_dim = 1024;
if img.width() > max_dim || img.height() > max_dim {
img = img.resize(max_dim, max_dim, FilterType::Lanczos3);
}
let rgb_img = img.into_rgb8();
let cache_dir = dirs::home_dir()
.unwrap_or_default()
.join(".gemini/mcp_memory/clipboard");
let _ = std::fs::create_dir_all(&cache_dir);
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let file_path = cache_dir.join(format!("clipboard_{}.jpg", timestamp));
if rgb_img
.save_with_format(&file_path, image::ImageFormat::Jpeg)
.is_ok()
{
let path_str = file_path.to_string_lossy().to_string();
out.insert("image_path".into(), json!(path_str));
#[cfg(target_os = "windows")]
if let Some(rest) = path_str.strip_prefix("C:\\") {
let wsl_path = format!("/mnt/c/{}", rest.replace('\\', "/"));
out.insert("image_path_wsl".into(), json!(wsl_path));
} else if let Some(rest) = path_str.strip_prefix("c:\\") {
let wsl_path = format!("/mnt/c/{}", rest.replace('\\', "/"));
out.insert("image_path_wsl".into(), json!(wsl_path));
}
if let Ok(bytes) = std::fs::read(&file_path) {
use base64::Engine;
let b64 = base64::engine::general_purpose::STANDARD.encode(&bytes);
out.insert("image_base64".into(), json!(b64));
}
}
}
Ok(Value::Object(out))
})
.await
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
let mut final_obj = result;
if let Some(b64) = final_obj.get("image_base64").and_then(|v| v.as_str()) {
let b64_str = b64.to_string();
if let Some(obj) = final_obj.as_object_mut() {
obj.remove("image_base64");
}
if state.ollama.is_available().await
&& let Ok(analysis) = state
.ollama
.generate_vision(
"Describe the content, text, or UI layout of this image concisely:",
&b64_str,
)
.await
&& let Some(obj) = final_obj.as_object_mut()
{
obj.insert("image_analysis".to_string(), json!(analysis.trim()));
}
}
state.record_activity("clipboard", "Read contents from OS clipboard", None);
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&final_obj)?)
}
}
use crate::tools::{ClipboardAction, ClipboardTool};
pub struct ClipboardHandler;
#[async_trait]
@@ -257,23 +106,161 @@ impl McpTool for ClipboardHandler {
let req: ClipboardTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
match req.action {
ClipboardAction::Read => {
ReadClipboardHandler.execute(serde_json::json!({}), state).await
let result =
tokio::task::spawn_blocking(move || -> crate::error::Result<serde_json::Value> {
let mut out = serde_json::Map::new();
if let Some(text) = get_native_clipboard_text() {
out.insert("text".into(), json!(text));
}
if let Some(dynamic_img) = get_native_clipboard_image() {
let mut img = dynamic_img;
let max_dim = 1024;
if img.width() > max_dim || img.height() > max_dim {
img = img.resize(max_dim, max_dim, FilterType::Lanczos3);
}
let rgb_img = img.into_rgb8();
let mut jpeg_bytes = std::io::Cursor::new(Vec::new());
if rgb_img.write_to(&mut jpeg_bytes, image::ImageFormat::Jpeg).is_ok() {
let bytes = jpeg_bytes.into_inner();
use base64::Engine;
let b64 = base64::engine::general_purpose::STANDARD.encode(&bytes);
out.insert("image_base64".into(), json!(b64));
let cache_dir = dirs::home_dir()
.unwrap_or_default()
.join(".gemini/mcp_memory/clipboard");
let _ = std::fs::create_dir_all(&cache_dir);
let file_path = cache_dir.join("clipboard_latest.jpg");
if std::fs::write(&file_path, &bytes).is_ok() {
let path_str = file_path.to_string_lossy().to_string();
out.insert("image_path".into(), json!(path_str));
#[cfg(target_os = "windows")]
if let Some(rest) = path_str.strip_prefix("C:\\") {
let wsl_path = format!("/mnt/c/{}", rest.replace('\\', "/"));
out.insert("image_path_wsl".into(), json!(wsl_path));
} else if let Some(rest) = path_str.strip_prefix("c:\\") {
let wsl_path = format!("/mnt/c/{}", rest.replace('\\', "/"));
out.insert("image_path_wsl".into(), json!(wsl_path));
}
}
}
}
Ok(Value::Object(out))
})
.await
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
let mut final_obj = result;
if let Some(b64) = final_obj.get("image_base64").and_then(|v| v.as_str()) {
let b64_str = b64.to_string();
if let Some(obj) = final_obj.as_object_mut() {
obj.remove("image_base64");
}
if state.ollama.is_available().await
&& let Ok(analysis) = state
.ollama
.generate_vision(
"Describe the content, text, or UI layout of this image concisely:",
&b64_str,
)
.await
&& let Some(obj) = final_obj.as_object_mut()
{
obj.insert("image_analysis".to_string(), json!(analysis.trim()));
}
}
state.record_activity("clipboard", "Read contents from OS clipboard", None);
Ok::<String, crate::error::AppError>(serde_json::to_string_pretty(&final_obj)?)
}
ClipboardAction::Write => {
WriteClipboardHandler.execute(
serde_json::json!({
"text": req.text,
"html": req.html,
"files": req.files,
"image_path": req.image_path
}),
state,
).await
let text_opt = req.text;
let image_path_opt = req.image_path;
let res = tokio::task::spawn_blocking(move || {
let mut msgs = Vec::new();
if let Some(text) = &text_opt {
let mut written = false;
if let Ok(mut clipboard) = Clipboard::new() {
for _ in 0..3 {
if clipboard.set_text(text).is_ok() {
written = true;
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
}
if written {
msgs.push("Wrote text");
}
}
if let Some(image_path) = &image_path_opt {
match image::open(image_path) {
Ok(img) => {
let img = if img.width() > 2048 || img.height() > 2048 {
img.resize(2048, 2048, FilterType::Triangle)
} else {
img
};
let rgba = img.into_rgba8();
let (w, h) = rgba.dimensions();
let raw_bytes = rgba.into_raw();
let mut written = false;
if let Ok(mut clipboard) = arboard::Clipboard::new() {
for _ in 0..3 {
let img_data = ImageData {
width: w as usize,
height: h as usize,
bytes: Cow::Borrowed(&raw_bytes),
};
if clipboard.set_image(img_data).is_ok() {
written = true;
break;
}
std::thread::sleep(std::time::Duration::from_millis(20));
}
}
if written {
msgs.push("Wrote image");
} else {
return Err(crate::error::AppError::Internal(
"Failed to write image to clipboard".to_string(),
));
}
}
Err(e) => {
return Err(crate::error::AppError::Internal(format!(
"Failed to open image {}: {}",
image_path, e
)));
}
}
}
if msgs.is_empty() {
Ok("No valid clipboard data provided or failed to write.".to_string())
} else {
Ok(format!(
"Successfully populated clipboard: {}",
msgs.join(", ")
))
}
})
.await
.map_err(|e| crate::error::AppError::Internal(format!("Task panic: {}", e)))??;
state.record_activity("clipboard", &res, None);
Ok(res)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -286,9 +273,10 @@ mod tests {
async fn test_write_clipboard() {
let dir = tempdir().unwrap();
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
let handler = WriteClipboardHandler;
let handler = ClipboardHandler;
let args = json!({
"action": "write",
"text": "test_text"
});
@@ -310,10 +298,10 @@ mod tests {
async fn test_read_clipboard() {
let dir = tempdir().unwrap();
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
let handler = ReadClipboardHandler;
let handler = ClipboardHandler;
let result = handler
.execute(json!({}), state)
.execute(json!({"action": "read"}), state)
.await
.map_err(|e| format!("Failed to read clipboard: {}", e))
.unwrap();
@@ -327,10 +315,10 @@ mod tests {
async fn test_read_clipboard_empty() {
let dir = tempfile::tempdir().unwrap();
let state = Arc::new(MemoryState::new(dir.path().to_str().unwrap()));
let handler = ReadClipboardHandler;
let handler = ClipboardHandler;
let result = handler
.execute(serde_json::json!({}), state)
.execute(serde_json::json!({"action": "read"}), state)
.await
.map_err(|e| format!("Failed to read clipboard: {}", e))
.unwrap();