1use crate::types::CallerKind;
2
3pub fn normalize_tool(vendor: &str, caller: &CallerKind) -> String {
8 let lower = vendor.to_lowercase();
9
10 let canonical = match caller {
11 CallerKind::ClaudeCode => normalize_claude_code(&lower),
12 CallerKind::Cursor => normalize_cursor(&lower),
13 CallerKind::Windsurf => normalize_windsurf(&lower),
14 CallerKind::Cline => normalize_cline(&lower),
15 CallerKind::Amp => normalize_amp(&lower),
16 CallerKind::GeminiCli => normalize_gemini_cli(&lower),
17 CallerKind::Unknown => None,
18 };
19
20 canonical
21 .map(|s| s.to_owned())
22 .unwrap_or_else(|| vendor.to_owned())
23}
24
25fn normalize_claude_code(lower: &str) -> Option<&'static str> {
26 match lower {
27 "bash" => Some("bash"),
28 "read" => Some("read_file"),
29 "write" => Some("write_file"),
30 "edit" => Some("edit_file"),
31 "ls" => Some("list_dir"),
32 "grep" => Some("grep"),
33 "glob" => Some("glob"),
34 "websearch" => Some("web_search"),
35 "webfetch" => Some("web_fetch"),
36 "task" => Some("spawn_agent"),
37 "mcp__ide__getdiagnostics" => Some("diagnostics"),
38 _ => None,
39 }
40}
41
42fn normalize_cursor(lower: &str) -> Option<&'static str> {
43 match lower {
44 "run_terminal_cmd" => Some("bash"),
45 "read_file" => Some("read_file"),
46 "edit_file" => Some("write_file"),
47 "apply_edit" => Some("edit_file"),
48 "list_dir" => Some("list_dir"),
49 "grep_search" => Some("grep"),
50 "file_search" => Some("glob"),
51 "web_search" => Some("web_search"),
52 "fetch_url" => Some("web_fetch"),
53 "spawn_agent" => Some("spawn_agent"),
54 "get_diagnostics" => Some("diagnostics"),
55 "move_file" => Some("move_file"),
56 "delete_file" => Some("delete_file"),
57 "create_dir" => Some("create_dir"),
58 _ => None,
59 }
60}
61
62fn normalize_windsurf(lower: &str) -> Option<&'static str> {
63 match lower {
64 "run_command" => Some("bash"),
65 "read_file" => Some("read_file"),
66 "write_file" => Some("write_file"),
67 "edit_file" => Some("edit_file"),
68 "list_directory" => Some("list_dir"),
69 "search_files" => Some("grep"),
70 "find_files" => Some("glob"),
71 "search_web" => Some("web_search"),
72 "fetch_page" => Some("web_fetch"),
73 "spawn_agent" => Some("spawn_agent"),
74 "get_diagnostics" => Some("diagnostics"),
75 "move_file" => Some("move_file"),
76 "delete_file" => Some("delete_file"),
77 "create_directory" => Some("create_dir"),
78 _ => None,
79 }
80}
81
82fn normalize_cline(lower: &str) -> Option<&'static str> {
83 match lower {
84 "execute_command" => Some("bash"),
85 "read_file" => Some("read_file"),
86 "write_to_file" => Some("write_file"),
87 "apply_diff" => Some("edit_file"),
88 "list_files" => Some("list_dir"),
89 "search_files" => Some("grep"),
90 "search" => Some("web_search"),
91 "fetch" => Some("web_fetch"),
92 "rename_file" => Some("move_file"),
93 "delete_file" => Some("delete_file"),
94 "create_directory" => Some("create_dir"),
95 "get_diagnostics" => Some("diagnostics"),
96 _ => None,
97 }
98}
99
100fn normalize_amp(lower: &str) -> Option<&'static str> {
101 match lower {
102 "shell" => Some("bash"),
103 "file.read" => Some("read_file"),
104 "file.write" => Some("write_file"),
105 "file.edit" => Some("edit_file"),
106 "fs.list" => Some("list_dir"),
107 "search.grep" => Some("grep"),
108 "search.glob" => Some("glob"),
109 "web.search" => Some("web_search"),
110 "web.fetch" => Some("web_fetch"),
111 "agent.spawn" => Some("spawn_agent"),
112 "lsp.diagnostics" => Some("diagnostics"),
113 "fs.move" => Some("move_file"),
114 "fs.delete" => Some("delete_file"),
115 "fs.mkdir" => Some("create_dir"),
116 _ => None,
117 }
118}
119
120fn normalize_gemini_cli(lower: &str) -> Option<&'static str> {
121 match lower {
122 "run_shell_command" => Some("bash"),
123 "read_file" => Some("read_file"),
124 "write_file" => Some("write_file"),
125 "replace" => Some("edit_file"),
126 "list_directory" => Some("list_dir"),
127 "glob" => Some("glob"),
128 "grep" => Some("grep"),
129 "google_web_search" => Some("web_search"),
130 "fetch" => Some("web_fetch"),
131 "move_file" => Some("move_file"),
132 "delete_file" => Some("delete_file"),
133 "make_directory" => Some("create_dir"),
134 _ => None,
135 }
136}
137
138#[cfg(test)]
143#[path = "tools_tests.rs"]
144mod tests;