Parse allowed tools into a set of tool permissions Claude Code format: "Bash(gh issue view:*), Bash(gh search:*)" Returns patterns like: ["Bash:gh issue view:*", "Bash:gh search:*"]
(&self)
| 181 | /// Claude Code format: "Bash(gh issue view:*), Bash(gh search:*)" |
| 182 | /// Returns patterns like: ["Bash:gh issue view:*", "Bash:gh search:*"] |
| 183 | pub fn parse_allowed_tools(&self) -> HashSet<ToolPermission> { |
| 184 | let mut permissions = HashSet::new(); |
| 185 | |
| 186 | let Some(allowed) = &self.allowed_tools else { |
| 187 | return permissions; |
| 188 | }; |
| 189 | |
| 190 | // Parse Claude-style comma-separated permissions, plus legacy |
| 191 | // whitespace-only tool lists such as "Read Write Edit Bash". |
| 192 | // A single Bash(...) permission may itself contain spaces, so try the |
| 193 | // canonical single-rule form before falling back to legacy splitting. |
| 194 | let parts: Vec<&str> = if allowed.contains(',') { |
| 195 | allowed.split(',').collect() |
| 196 | } else if ToolPermission::parse(allowed).is_some() { |
| 197 | vec![allowed.as_str()] |
| 198 | } else { |
| 199 | let parts: Vec<&str> = allowed.split_whitespace().collect(); |
| 200 | if parts.len() > 1 { |
| 201 | tracing::warn!( |
| 202 | skill = %self.name, |
| 203 | allowed_tools = %allowed, |
| 204 | "Legacy whitespace-separated allowed-tools is deprecated; use comma-separated permissions such as Read(*), Write(*), Bash(*) or a YAML list" |
| 205 | ); |
| 206 | } |
| 207 | parts |
| 208 | }; |
| 209 | for part in parts { |
| 210 | let part = part.trim(); |
| 211 | if part.is_empty() { |
| 212 | continue; |
| 213 | } |
| 214 | if let Some(perm) = ToolPermission::parse(part) { |
| 215 | permissions.insert(perm); |
| 216 | } else { |
| 217 | permissions.insert(ToolPermission { |
| 218 | tool: part.to_string(), |
| 219 | pattern: "*".to_string(), |
| 220 | }); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | permissions |
| 225 | } |
| 226 | |
| 227 | /// True when a skill still uses the legacy whitespace-only tool list. |
| 228 | pub fn uses_legacy_allowed_tools_syntax(&self) -> bool { |