2 files changed
+81
-36
src/main.rs
+5
-1
@@ -40,11 +40,14 @@
40
//! }
41
//! ```
42
43
+#[cfg(unix)]
44
mod chat;
45
mod setup;
46
mod tools;
47
47
-use std::io::{BufWriter, IsTerminal, Write};
48
+use std::io::IsTerminal;
49
+#[cfg(unix)]
50
+use std::io::{BufWriter, Write};
51
use std::sync::Arc;
52
53
use onde::inference::SamplingConfig;
@@ -383,6 +386,7 @@ fn init_logging(is_tty: bool) {
386
/// terminal, used for `LeaveAlternateScreen` and restoring stdout/stderr
387
/// (we cannot access the backend's writer because `writer_mut()` is private
388
/// in ratatui 0.29).
389
+#[cfg(unix)]
390
async fn run_interactive(tty: std::fs::File, mut cleanup_tty: std::fs::File) -> anyhow::Result<()> {
391
let engine = Arc::new(ChatEngine::new());
392
let config = GgufModelConfig::platform_default();
src/tools.rs
+76
-35
@@ -725,7 +725,7 @@ mod tests {
725
let file_path = dir.join("hello.txt");
726
fs::write(&file_path, "hello world").unwrap();
727
728
- let args = format!(r#"{{"path": "{}"}}"#, file_path.display());
728
+ let args = serde_json::json!({ "path": file_path }).to_string();
729
let result = exec_read_file(&args);
730
assert_eq!(result, "hello world");
731
@@ -746,7 +746,7 @@ mod tests {
746
fs::write(dir.join("aaa.txt"), "").unwrap();
747
fs::write(dir.join("bbb.rs"), "").unwrap();
748
749
- let args = format!(r#"{{"path": "{}"}}"#, dir.display());
749
+ let args = serde_json::json!({ "path": dir }).to_string();
750
let result = exec_list_directory(&args);
751
752
assert!(result.contains("[DIR] subdir"));
@@ -779,7 +779,11 @@ mod tests {
779
.unwrap();
780
fs::write(dir.join("other.txt"), "no match here\n").unwrap();
781
782
- let args = format!(r#"{{"pattern": "println", "path": "{}"}}"#, dir.display());
782
+ let args = serde_json::json!({
783
+ "pattern": "println",
784
+ "path": dir
785
+ })
786
+ .to_string();
787
let result = exec_search_files(&args);
788
789
assert!(result.contains("code.rs:2:"));
@@ -796,10 +800,11 @@ mod tests {
800
fs::create_dir_all(&dir).unwrap();
801
fs::write(dir.join("empty.txt"), "nothing special").unwrap();
802
799
- let args = format!(
800
- r#"{{"pattern": "zzz_will_not_match_42", "path": "{}"}}"#,
801
- dir.display()
802
- );
803
+ let args = serde_json::json!({
804
+ "pattern": "zzz_will_not_match_42",
805
+ "path": dir
806
+ })
807
+ .to_string();
808
let result = exec_search_files(&args);
809
assert!(result.contains("No matches found"));
810
@@ -854,10 +859,11 @@ mod tests {
859
let _ = fs::remove_dir_all(&dir);
860
861
let file_path = dir.join("sub").join("new_file.txt");
857
- let args = format!(
858
- r#"{{"path": "{}", "content": "hello world"}}"#,
859
- file_path.display()
860
- );
862
+ let args = serde_json::json!({
863
+ "path": file_path,
864
+ "content": "hello world"
865
+ })
866
+ .to_string();
867
868
let result = exec_create_file(&args);
869
assert!(result.starts_with("Created file:"), "got: {result}");
@@ -876,10 +882,11 @@ mod tests {
882
let file_path = dir.join("existing.txt");
883
fs::write(&file_path, "original").unwrap();
884
879
- let args = format!(
880
- r#"{{"path": "{}", "content": "overwrite attempt"}}"#,
881
- file_path.display()
882
- );
885
+ let args = serde_json::json!({
886
+ "path": file_path,
887
+ "content": "overwrite attempt"
888
+ })
889
+ .to_string();
890
891
let result = exec_create_file(&args);
892
assert!(result.contains("already exists"), "got: {result}");
@@ -917,10 +924,12 @@ mod tests {
924
let file_path = dir.join("code.rs");
925
fs::write(&file_path, "fn main() {\n println!(\"hello\");\n}\n").unwrap();
926
920
- let args = format!(
921
- r#"{{"path": "{}", "old_text": "println!(\"hello\")", "new_text": "println!(\"world\")"}}"#,
922
- file_path.display()
923
- );
927
+ let args = serde_json::json!({
928
+ "path": file_path,
929
+ "old_text": "println!(\"hello\")",
930
+ "new_text": "println!(\"world\")"
931
+ })
932
+ .to_string();
933
934
let result = exec_edit_file(&args);
935
assert!(result.starts_with("Edited file:"), "got: {result}");
@@ -941,10 +950,12 @@ mod tests {
950
let file_path = dir.join("data.txt");
951
fs::write(&file_path, "aaa bbb ccc").unwrap();
952
944
- let args = format!(
945
- r#"{{"path": "{}", "old_text": "zzz", "new_text": "yyy"}}"#,
946
- file_path.display()
947
- );
953
+ let args = serde_json::json!({
954
+ "path": file_path,
955
+ "old_text": "zzz",
956
+ "new_text": "yyy"
957
+ })
958
+ .to_string();
959
960
let result = exec_edit_file(&args);
961
assert!(result.contains("old_text not found"), "got: {result}");
@@ -961,10 +972,12 @@ mod tests {
972
let file_path = dir.join("repeat.txt");
973
fs::write(&file_path, "foo bar foo bar foo").unwrap();
974
964
- let args = format!(
965
- r#"{{"path": "{}", "old_text": "foo", "new_text": "baz"}}"#,
966
- file_path.display()
967
- );
975
+ let args = serde_json::json!({
976
+ "path": file_path,
977
+ "old_text": "foo",
978
+ "new_text": "baz"
979
+ })
980
+ .to_string();
981
982
let result = exec_edit_file(&args);
983
assert!(result.contains("appears 3 times"), "got: {result}");
@@ -1004,7 +1017,7 @@ mod tests {
1017
fs::write(&file_path, "bye").unwrap();
1018
assert!(file_path.exists());
1019
1007
- let args = format!(r#"{{"path": "{}"}}"#, file_path.display());
1020
+ let args = serde_json::json!({ "path": file_path }).to_string();
1021
let result = exec_delete_file(&args);
1022
assert!(result.contains("Deleted file"), "got: {result}");
1023
assert!(!file_path.exists());
@@ -1018,7 +1031,7 @@ mod tests {
1031
let _ = fs::remove_dir_all(&dir);
1032
fs::create_dir_all(&dir).unwrap();
1033
1021
- let args = format!(r#"{{"path": "{}"}}"#, dir.display());
1034
+ let args = serde_json::json!({ "path": dir }).to_string();
1035
let result = exec_delete_file(&args);
1036
assert!(result.contains("Deleted empty directory"), "got: {result}");
1037
assert!(!dir.exists());
@@ -1031,7 +1044,7 @@ mod tests {
1044
fs::create_dir_all(&dir).unwrap();
1045
fs::write(dir.join("child.txt"), "content").unwrap();
1046
1034
- let args = format!(r#"{{"path": "{}"}}"#, dir.display());
1047
+ let args = serde_json::json!({ "path": dir }).to_string();
1048
let result = exec_delete_file(&args);
1049
assert!(result.contains("Error"), "got: {result}");
1050
assert!(dir.exists(), "directory should not have been deleted");
@@ -1059,7 +1072,13 @@ mod tests {
1072
1073
#[test]
1074
fn test_run_command_failure() {
1062
- let result = exec_run_command(r#"{"command": "false"}"#);
1075
+ #[cfg(unix)]
1076
+ let command = "false";
1077
+ #[cfg(windows)]
1078
+ let command = "exit /b 1";
1079
+
1080
+ let args = serde_json::json!({ "command": command }).to_string();
1081
+ let result = exec_run_command(&args);
1082
assert!(result.contains("failed"), "got: {result}");
1083
}
1084
@@ -1069,7 +1088,16 @@ mod tests {
1088
let _ = fs::remove_dir_all(&dir);
1089
fs::create_dir_all(&dir).unwrap();
1090
1072
- let args = format!(r#"{{"command": "pwd", "cwd": "{}"}}"#, dir.display());
1091
+ #[cfg(unix)]
1092
+ let command = "pwd";
1093
+ #[cfg(windows)]
1094
+ let command = "cd";
1095
+
1096
+ let args = serde_json::json!({
1097
+ "command": command,
1098
+ "cwd": dir
1099
+ })
1100
+ .to_string();
1101
let result = exec_run_command(&args);
1102
// The output should contain the temp dir path.
1103
assert!(
@@ -1082,14 +1110,27 @@ mod tests {
1110
1111
#[test]
1112
fn test_run_command_bad_cwd() {
1085
- let result =
1086
- exec_run_command(r#"{"command": "echo hi", "cwd": "/tmp/sigit_no_such_dir_xyz"}"#);
1113
+ let missing_dir = std::env::temp_dir().join("sigit_no_such_dir_xyz");
1114
+ let _ = fs::remove_dir_all(&missing_dir);
1115
+
1116
+ let args = serde_json::json!({
1117
+ "command": "echo hi",
1118
+ "cwd": missing_dir
1119
+ })
1120
+ .to_string();
1121
+ let result = exec_run_command(&args);
1122
assert!(result.contains("does not exist"), "got: {result}");
1123
}
1124
1125
#[test]
1126
fn test_run_command_captures_stderr() {
1092
- let result = exec_run_command(r#"{"command": "echo err >&2"}"#);
1127
+ #[cfg(unix)]
1128
+ let command = "echo err >&2";
1129
+ #[cfg(windows)]
1130
+ let command = "echo err 1>&2";
1131
+
1132
+ let args = serde_json::json!({ "command": command }).to_string();
1133
+ let result = exec_run_command(&args);
1134
assert!(result.contains("err"), "got: {result}");
1135
}
1136
}