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::Hermes => normalize_hermes(&lower),
18 CallerKind::Unknown => None,
19 };
20
21 canonical
22 .map(|s| s.to_owned())
23 .unwrap_or_else(|| vendor.to_owned())
24}
25
26fn normalize_claude_code(lower: &str) -> Option<&'static str> {
27 match lower {
28 "bash" => Some("bash"),
29 "read" => Some("read_file"),
30 "write" => Some("write_file"),
31 "edit" => Some("edit_file"),
32 "ls" => Some("list_dir"),
33 "grep" => Some("grep"),
34 "glob" => Some("glob"),
35 "websearch" => Some("web_search"),
36 "webfetch" => Some("web_fetch"),
37 "task" => Some("spawn_agent"),
38 "mcp__ide__getdiagnostics" => Some("diagnostics"),
39 _ => None,
40 }
41}
42
43fn normalize_cursor(lower: &str) -> Option<&'static str> {
44 match lower {
45 "run_terminal_cmd" => Some("bash"),
46 "read_file" => Some("read_file"),
47 "edit_file" => Some("write_file"),
48 "apply_edit" => Some("edit_file"),
49 "list_dir" => Some("list_dir"),
50 "grep_search" => Some("grep"),
51 "file_search" => Some("glob"),
52 "web_search" => Some("web_search"),
53 "fetch_url" => Some("web_fetch"),
54 "spawn_agent" => Some("spawn_agent"),
55 "get_diagnostics" => Some("diagnostics"),
56 "move_file" => Some("move_file"),
57 "delete_file" => Some("delete_file"),
58 "create_dir" => Some("create_dir"),
59 _ => None,
60 }
61}
62
63fn normalize_windsurf(lower: &str) -> Option<&'static str> {
64 match lower {
65 "run_command" => Some("bash"),
66 "read_file" => Some("read_file"),
67 "write_file" => Some("write_file"),
68 "edit_file" => Some("edit_file"),
69 "list_directory" => Some("list_dir"),
70 "search_files" => Some("grep"),
71 "find_files" => Some("glob"),
72 "search_web" => Some("web_search"),
73 "fetch_page" => Some("web_fetch"),
74 "spawn_agent" => Some("spawn_agent"),
75 "get_diagnostics" => Some("diagnostics"),
76 "move_file" => Some("move_file"),
77 "delete_file" => Some("delete_file"),
78 "create_directory" => Some("create_dir"),
79 _ => None,
80 }
81}
82
83fn normalize_cline(lower: &str) -> Option<&'static str> {
84 match lower {
85 "execute_command" => Some("bash"),
86 "read_file" => Some("read_file"),
87 "write_to_file" => Some("write_file"),
88 "apply_diff" => Some("edit_file"),
89 "list_files" => Some("list_dir"),
90 "search_files" => Some("grep"),
91 "search" => Some("web_search"),
92 "fetch" => Some("web_fetch"),
93 "rename_file" => Some("move_file"),
94 "delete_file" => Some("delete_file"),
95 "create_directory" => Some("create_dir"),
96 "get_diagnostics" => Some("diagnostics"),
97 _ => None,
98 }
99}
100
101fn normalize_amp(lower: &str) -> Option<&'static str> {
102 match lower {
103 "shell" => Some("bash"),
104 "file.read" => Some("read_file"),
105 "file.write" => Some("write_file"),
106 "file.edit" => Some("edit_file"),
107 "fs.list" => Some("list_dir"),
108 "search.grep" => Some("grep"),
109 "search.glob" => Some("glob"),
110 "web.search" => Some("web_search"),
111 "web.fetch" => Some("web_fetch"),
112 "agent.spawn" => Some("spawn_agent"),
113 "lsp.diagnostics" => Some("diagnostics"),
114 "fs.move" => Some("move_file"),
115 "fs.delete" => Some("delete_file"),
116 "fs.mkdir" => Some("create_dir"),
117 _ => None,
118 }
119}
120
121fn normalize_gemini_cli(lower: &str) -> Option<&'static str> {
122 match lower {
123 "run_shell_command" => Some("bash"),
124 "read_file" => Some("read_file"),
125 "write_file" => Some("write_file"),
126 "replace" => Some("edit_file"),
127 "list_directory" => Some("list_dir"),
128 "glob" => Some("glob"),
129 "grep" => Some("grep"),
130 "google_web_search" => Some("web_search"),
131 "fetch" => Some("web_fetch"),
132 "move_file" => Some("move_file"),
133 "delete_file" => Some("delete_file"),
134 "make_directory" => Some("create_dir"),
135 _ => None,
136 }
137}
138
139fn normalize_hermes(lower: &str) -> Option<&'static str> {
140 match lower {
141 "terminal" => Some("bash"),
142 "read_file" => Some("read_file"),
143 "write_file" => Some("write_file"),
144 "patch" => Some("edit_file"),
145 "search_files" => Some("grep"),
146 "delegate_task" => Some("spawn_agent"),
147 "browser_back" | "browser_click" | "browser_console" | "browser_get_images"
148 | "browser_navigate" | "browser_press" | "browser_scroll" | "browser_snapshot"
149 | "browser_type" | "browser_vision" => Some("browser"),
150 _ => None,
151 }
152}
153
154#[cfg(test)]
159#[path = "tools_tests.rs"]
160mod tests;