use crate::protocol::{AnalysisSource, Freshness, ToolResponseMeta};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum Authority {
NativeOnly,
NativeFirst,
LspFirst,
LspOnly,
Hybrid,
}
#[allow(dead_code)]
pub fn feature_authority(feature: &str) -> Authority {
match feature {
"symbols" | "search" | "dead_code" | "blast_radius" | "callers" | "callees" | "imports"
| "complexity" | "annotations" | "tests" => Authority::NativeOnly,
"rename" => Authority::NativeFirst,
"references" => Authority::Hybrid,
"type_hierarchy" => Authority::LspFirst,
"diagnostics" | "workspace_symbols" | "rename_plan" => Authority::LspOnly,
_ => Authority::NativeOnly,
}
}
pub fn meta_for_backend(backend: &str, confidence: f64) -> ToolResponseMeta {
let source = match backend {
"lsp_pooled" | "lsp" => AnalysisSource::Lsp,
"text_search" | "text_fallback" | "tree-sitter-native" | "filesystem" | "watcher"
| "session" | "noop" | "capability-check" | "memory" => AnalysisSource::Native,
"composite-onboard" | "composite" => AnalysisSource::Hybrid,
"semantic-embedding" => AnalysisSource::Native,
_ => AnalysisSource::Native,
};
let freshness = match backend {
"text_search" | "text_fallback" | "tree-sitter-native" | "filesystem" => Freshness::Live,
_ => Freshness::Indexed,
};
ToolResponseMeta {
backend_used: backend.to_owned(),
confidence,
degraded_reason: None,
source,
partial: false,
freshness,
staleness_ms: None,
}
}
pub fn meta_degraded(backend: &str, confidence: f64, reason: &str) -> ToolResponseMeta {
let mut meta = meta_for_backend(backend, confidence);
meta.degraded_reason = Some(reason.to_owned());
meta
}
#[allow(dead_code)]
pub fn check_lsp_required(feature: &str, lsp_available: bool) -> Option<String> {
let auth = feature_authority(feature);
if matches!(auth, Authority::LspOnly) && !lsp_available {
Some(format!(
"Feature '{feature}' requires an LSP server but none is attached. \
Use check_lsp_status to see available servers, or get_lsp_recipe for installation."
))
} else {
None
}
}