Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion crates/goose-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ chrono = "0.4"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json", "time"] }
tracing-appender = "0.2"
once_cell = "1.20.2"
winapi = { version = "0.3", features = ["wincred"], optional = true }

[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3", features = ["wincred"] }
Expand Down
4 changes: 0 additions & 4 deletions crates/goose-mcp/src/computercontroller/platform/macos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ use std::process::Command;

pub struct MacOSAutomation;

// MacOSAutomation is Send + Sync because it contains no shared state
unsafe impl Send for MacOSAutomation {}
unsafe impl Sync for MacOSAutomation {}

impl SystemAutomation for MacOSAutomation {
fn execute_system_script(&self, script: &str) -> std::io::Result<String> {
let output = Command::new("osascript").arg("-e").arg(script).output()?;
Expand Down
4 changes: 0 additions & 4 deletions crates/goose-mcp/src/computercontroller/platform/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@ use std::process::Command;

pub struct WindowsAutomation;

// WindowsAutomation is Send + Sync because it contains no shared state
unsafe impl Send for WindowsAutomation {}
unsafe impl Sync for WindowsAutomation {}

impl SystemAutomation for WindowsAutomation {
fn execute_system_script(&self, script: &str) -> std::io::Result<String> {
let output = Command::new("powershell")
Expand Down
69 changes: 66 additions & 3 deletions crates/goose-mcp/src/developer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,13 @@ impl DeveloperRouter {
Avoid commands that produce a large amount of output, and consider piping those outputs to files.

**Important**: For searching files and code:

Preferred: Use ripgrep (`rg`) when available - it respects .gitignore and is fast:
- To locate a file by name: `rg --files | rg example.py`
- To locate content inside files: `rg 'class Example'`

Alternative Windows commands (if ripgrep is not installed):
- To locate a file by name: `dir /s /b example.py`
- To locate a file by name: `dir /s /b example.py`
- To locate content inside files: `findstr /s /i "class Example" *.py`

Note: Alternative commands may show ignored/hidden files that should be excluded.
Expand Down Expand Up @@ -996,6 +996,69 @@ mod tests {
assert!(result.is_ok());
}

#[tokio::test]
#[serial]
async fn test_text_editor_size_limits() {
// Create temp directory first so it stays in scope for the whole test
let temp_dir = tempfile::tempdir().unwrap();
std::env::set_current_dir(&temp_dir).unwrap();

// Get router after setting current directory
let router = get_router().await;

// Test file size limit
{
let large_file_path = temp_dir.path().join("large.txt");
let large_file_str = large_file_path.to_str().unwrap();

// Create a file larger than 2MB
let content = "x".repeat(3 * 1024 * 1024); // 3MB
std::fs::write(&large_file_path, content).unwrap();

let result = router
.call_tool(
"text_editor",
json!({
"command": "view",
"path": large_file_str
}),
)
.await;

assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ToolError::ExecutionError(_)));
assert!(err.to_string().contains("too large"));
}

// Test character count limit
{
let many_chars_path = temp_dir.path().join("many_chars.txt");
let many_chars_str = many_chars_path.to_str().unwrap();

// Create a file with more than 400K characters but less than 400KB
let content = "x".repeat(405_000);
std::fs::write(&many_chars_path, content).unwrap();

let result = router
.call_tool(
"text_editor",
json!({
"command": "view",
"path": many_chars_str
}),
)
.await;

assert!(result.is_err());
let err = result.err().unwrap();
assert!(matches!(err, ToolError::ExecutionError(_)));
assert!(err.to_string().contains("too many characters"));
}

// Let temp_dir drop naturally at end of scope
}

#[tokio::test]
#[serial]
async fn test_text_editor_write_and_view_file() {
Expand Down
Loading