#[derive(Debug, Deserialize)]
struct TdgArgs {
paths: Vec<String>,
#[serde(default)]
threshold: Option<f64>,
#[serde(default)]
top_files: Option<usize>,
#[serde(default)]
include_components: Option<bool>,
#[serde(default)] with_git_context: Option<bool>,
}
pub struct TdgTool;
impl TdgTool {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self
}
}
impl Default for TdgTool {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl ToolHandler for TdgTool {
async fn handle(&self, args: Value, _extra: RequestHandlerExtra) -> Result<Value> {
debug!("Handling analyze.tdg with args: {}", args);
let params: TdgArgs = serde_json::from_value(args)
.map_err(|e| Error::validation(format!("Invalid arguments: {e}")))?;
let paths: Vec<PathBuf> = params.paths.into_iter().map(PathBuf::from).collect();
let results = tool_functions::analyze_tdg(
&paths,
params.threshold,
params.top_files,
params.include_components,
params.with_git_context, )
.await
.map_err(|e| Error::internal(format!("TDG analysis failed: {e}")))?;
Ok(results)
}
fn metadata(&self) -> Option<ToolInfo> {
let extra = json!({
"threshold": { "type": "number", "description": "Minimum TDG score threshold" },
"top_files": { "type": "integer", "description": "Return only the top N files" },
"include_components": { "type": "boolean", "description": "Include per-metric component breakdown" },
"with_git_context": { "type": "boolean", "description": "Correlate scores with git commit history (Sprint 65)" }
});
Some(build_tool_info(
"analyze_tdg",
"Compute Technical Debt Grading (TDG) scores across orthogonal quality metrics.",
paths_object_schema(extra, vec!["paths"]),
))
}
}
#[derive(Debug, Deserialize)]
struct TdgCompareArgs {
path1: String,
path2: String,
#[serde(default)] with_git_context: Option<bool>,
}
pub struct TdgCompareTool;
impl TdgCompareTool {
#[must_use]
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn new() -> Self {
Self
}
}
impl Default for TdgCompareTool {
fn default() -> Self {
Self::new()
}
}
#[async_trait]
impl ToolHandler for TdgCompareTool {
async fn handle(&self, args: Value, _extra: RequestHandlerExtra) -> Result<Value> {
debug!("Handling analyze.tdg_compare with args: {}", args);
let params: TdgCompareArgs = serde_json::from_value(args)
.map_err(|e| Error::validation(format!("Invalid arguments: {e}")))?;
let path1 = PathBuf::from(params.path1);
let path2 = PathBuf::from(params.path2);
let results = tool_functions::compare_tdg(&path1, &path2, params.with_git_context)
.await
.map_err(|e| Error::internal(format!("TDG comparison failed: {e}")))?;
Ok(results)
}
fn metadata(&self) -> Option<ToolInfo> {
let schema = json!({
"type": "object",
"properties": {
"path1": { "type": "string", "description": "Baseline path to compare" },
"path2": { "type": "string", "description": "Candidate path to compare" },
"with_git_context": { "type": "boolean", "description": "Include git commit correlation (Sprint 65)" }
},
"required": ["path1", "path2"]
});
Some(build_tool_info(
"analyze_tdg_compare",
"Diff TDG scores between two paths (files or directories).",
schema,
))
}
}