~ expansion for read_file and str_replace
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1305,6 +1305,7 @@ dependencies = [
|
|||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"shellexpand",
|
||||||
"thiserror 1.0.69",
|
"thiserror 1.0.69",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
|||||||
@@ -24,3 +24,4 @@ futures-util = "0.3"
|
|||||||
chrono = { version = "0.4", features = ["serde"] }
|
chrono = { version = "0.4", features = ["serde"] }
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
regex = "1.0"
|
regex = "1.0"
|
||||||
|
shellexpand = "3.1"
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ mod fixed_filter_json;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod fixed_filter_tests;
|
mod fixed_filter_tests;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tilde_expansion_tests;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod error_handling_test;
|
mod error_handling_test;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@@ -2211,6 +2214,10 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
debug!("Processing read_file tool call");
|
debug!("Processing read_file tool call");
|
||||||
if let Some(file_path) = tool_call.args.get("file_path") {
|
if let Some(file_path) = tool_call.args.get("file_path") {
|
||||||
if let Some(path_str) = file_path.as_str() {
|
if let Some(path_str) = file_path.as_str() {
|
||||||
|
// Expand tilde (~) to home directory
|
||||||
|
let expanded_path = shellexpand::tilde(path_str);
|
||||||
|
let path_str = expanded_path.as_ref();
|
||||||
|
|
||||||
// Check if this is an image file
|
// Check if this is an image file
|
||||||
let is_image = path_str.to_lowercase().ends_with(".png")
|
let is_image = path_str.to_lowercase().ends_with(".png")
|
||||||
|| path_str.to_lowercase().ends_with(".jpg")
|
|| path_str.to_lowercase().ends_with(".jpg")
|
||||||
@@ -2472,6 +2479,10 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
);
|
);
|
||||||
|
|
||||||
if let (Some(path), Some(content)) = (path_str, content_str) {
|
if let (Some(path), Some(content)) = (path_str, content_str) {
|
||||||
|
// Expand tilde (~) to home directory
|
||||||
|
let expanded_path = shellexpand::tilde(path);
|
||||||
|
let path = expanded_path.as_ref();
|
||||||
|
|
||||||
debug!("Writing to file: {}", path);
|
debug!("Writing to file: {}", path);
|
||||||
|
|
||||||
// Create parent directories if they don't exist
|
// Create parent directories if they don't exist
|
||||||
@@ -2519,7 +2530,11 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
};
|
};
|
||||||
|
|
||||||
let file_path = match args_obj.get("file_path").and_then(|v| v.as_str()) {
|
let file_path = match args_obj.get("file_path").and_then(|v| v.as_str()) {
|
||||||
Some(path) => path,
|
Some(path) => {
|
||||||
|
// Expand tilde (~) to home directory
|
||||||
|
let expanded_path = shellexpand::tilde(path);
|
||||||
|
expanded_path.into_owned()
|
||||||
|
}
|
||||||
None => return Ok("❌ Missing or invalid file_path argument".to_string()),
|
None => return Ok("❌ Missing or invalid file_path argument".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2544,7 +2559,7 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Read the existing file
|
// Read the existing file
|
||||||
let file_content = match std::fs::read_to_string(file_path) {
|
let file_content = match std::fs::read_to_string(&file_path) {
|
||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(e) => return Ok(format!("❌ Failed to read file '{}': {}", file_path, e)),
|
Err(e) => return Ok(format!("❌ Failed to read file '{}': {}", file_path, e)),
|
||||||
};
|
};
|
||||||
@@ -2557,7 +2572,7 @@ The tool will execute immediately and you'll receive the result (success or erro
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Write the result back to the file
|
// Write the result back to the file
|
||||||
match std::fs::write(file_path, &result) {
|
match std::fs::write(&file_path, &result) {
|
||||||
Ok(()) => Ok(format!("✅ Successfully applied unified diff")),
|
Ok(()) => Ok(format!("✅ Successfully applied unified diff")),
|
||||||
Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", file_path, e)),
|
Err(e) => Ok(format!("❌ Failed to write to file '{}': {}", file_path, e)),
|
||||||
}
|
}
|
||||||
|
|||||||
36
crates/g3-core/src/tilde_expansion_tests.rs
Normal file
36
crates/g3-core/src/tilde_expansion_tests.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tilde_expansion_tests {
|
||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tilde_expansion() {
|
||||||
|
// Test that shellexpand works
|
||||||
|
let path_with_tilde = "~/test.txt";
|
||||||
|
let expanded = shellexpand::tilde(path_with_tilde);
|
||||||
|
|
||||||
|
// Get the actual home directory
|
||||||
|
let home = env::var("HOME").expect("HOME environment variable not set");
|
||||||
|
|
||||||
|
// Verify expansion happened
|
||||||
|
assert_eq!(expanded.as_ref(), format!("{}/test.txt", home));
|
||||||
|
assert!(!expanded.contains("~"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tilde_expansion_with_subdirs() {
|
||||||
|
let path_with_tilde = "~/Documents/test.txt";
|
||||||
|
let expanded = shellexpand::tilde(path_with_tilde);
|
||||||
|
|
||||||
|
let home = env::var("HOME").expect("HOME environment variable not set");
|
||||||
|
|
||||||
|
assert_eq!(expanded.as_ref(), format!("{}/Documents/test.txt", home));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_tilde_unchanged() {
|
||||||
|
let path_without_tilde = "/absolute/path/test.txt";
|
||||||
|
let expanded = shellexpand::tilde(path_without_tilde);
|
||||||
|
|
||||||
|
assert_eq!(expanded.as_ref(), path_without_tilde);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user