use super::dynamic_tools::{categorize_tool, ToolCategory};
use crate::core::tool_profiles::ToolProfile;
pub const INVOKER: &str = "ctx_call";
#[must_use]
pub fn is_tool_visible(
name: &str,
profile: &ToolProfile,
disabled: &[String],
is_zed: bool,
role_allows: bool,
) -> bool {
if categorize_tool(name) == ToolCategory::Internal {
return false;
}
if !profile.is_tool_enabled(name) {
return false;
}
if disabled.iter().any(|d| d == name) {
return false;
}
if is_zed && name == "ctx_edit" {
return false;
}
role_allows
}
#[must_use]
pub fn category_gate_applies(supports_list_changed: bool, explicit_profile: bool) -> bool {
supports_list_changed && !explicit_profile
}
#[must_use]
pub fn needs_invoker(
full_mode: bool,
already_present: bool,
invoker_role_allowed: bool,
disabled: &[String],
) -> bool {
!full_mode && !already_present && invoker_role_allowed && !disabled.iter().any(|d| d == INVOKER)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn internal_tools_never_visible_even_in_power() {
let p = ToolProfile::Power;
assert!(!is_tool_visible("ctx_metrics", &p, &[], false, true));
assert!(!is_tool_visible("ctx_cost", &p, &[], false, true));
assert!(!is_tool_visible("ctx_discover_tools", &p, &[], false, true));
}
#[test]
fn core_tool_visible_under_power() {
assert!(is_tool_visible(
"ctx_read",
&ToolProfile::Power,
&[],
false,
true
));
}
#[test]
fn standard_exposes_its_advertised_tools() {
let p = ToolProfile::Standard;
assert!(is_tool_visible("ctx_architecture", &p, &[], false, true));
assert!(is_tool_visible("ctx_semantic_search", &p, &[], false, true));
assert!(is_tool_visible("ctx_callgraph", &p, &[], false, true));
}
#[test]
fn minimal_hides_non_minimal_tools() {
let p = ToolProfile::Minimal;
assert!(is_tool_visible("ctx_read", &p, &[], false, true));
assert!(!is_tool_visible("ctx_architecture", &p, &[], false, true));
}
#[test]
fn disabled_list_filters() {
let disabled = vec!["ctx_read".to_string()];
assert!(!is_tool_visible(
"ctx_read",
&ToolProfile::Power,
&disabled,
false,
true
));
}
#[test]
fn zed_hides_ctx_edit_only() {
let p = ToolProfile::Power;
assert!(!is_tool_visible("ctx_edit", &p, &[], true, true));
assert!(is_tool_visible("ctx_read", &p, &[], true, true));
}
#[test]
fn role_block_hides_tool() {
assert!(!is_tool_visible(
"ctx_read",
&ToolProfile::Power,
&[],
false,
false
));
}
#[test]
fn category_gate_only_in_default_lean_mode() {
assert!(category_gate_applies(true, false));
assert!(!category_gate_applies(true, true));
assert!(!category_gate_applies(false, false));
assert!(!category_gate_applies(false, true));
}
#[test]
fn invoker_added_when_missing_in_lazy_mode() {
assert!(needs_invoker(false, false, true, &[]));
}
#[test]
fn invoker_not_added_in_full_mode() {
assert!(!needs_invoker(true, false, true, &[]));
}
#[test]
fn invoker_not_duplicated_when_present() {
assert!(!needs_invoker(false, true, true, &[]));
}
#[test]
fn invoker_respects_role_and_disabled() {
assert!(!needs_invoker(false, false, false, &[]));
assert!(!needs_invoker(
false,
false,
true,
&["ctx_call".to_string()]
));
}
}