huskies: merge 1199 story Orphaned build-dir GC: reclaim dead worktree targets without touching warm caches
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
//! MCP tool for the on-demand build-directory GC pass (story 1199).
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::http::context::AppContext;
|
||||
|
||||
/// MCP tool handler for `gc` — runs a build-directory GC pass on demand and
|
||||
/// returns bytes reclaimed, duration, and which directories were reclaimed
|
||||
/// or skipped (raced/errored).
|
||||
pub(crate) async fn tool_gc(ctx: &AppContext) -> Result<String, String> {
|
||||
let project_root = ctx.services.agents.get_project_root(&ctx.state)?;
|
||||
let report = crate::service::gc::io::run_gc_pass(&project_root).await;
|
||||
|
||||
serde_json::to_string_pretty(&json!({
|
||||
"bytes_reclaimed": report.bytes_reclaimed,
|
||||
"reclaimed": report.reclaimed,
|
||||
"skipped": report.skipped,
|
||||
"duration_secs": report.duration.as_secs_f64(),
|
||||
}))
|
||||
.map_err(|e| format!("Serialization error: {e}"))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::http::test_helpers::test_ctx;
|
||||
|
||||
#[tokio::test]
|
||||
async fn tool_gc_returns_zero_bytes_for_empty_project() {
|
||||
let tmp = tempfile::tempdir().unwrap();
|
||||
let ctx = test_ctx(tmp.path());
|
||||
let result = tool_gc(&ctx).await.expect("tool_gc must not fail");
|
||||
let parsed: serde_json::Value = serde_json::from_str(&result).unwrap();
|
||||
assert_eq!(parsed["bytes_reclaimed"].as_u64(), Some(0));
|
||||
assert!(parsed["reclaimed"].as_array().unwrap().is_empty());
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
//! MCP agent tools — start, stop, wait, list, and inspect agents via MCP.
|
||||
|
||||
mod gc;
|
||||
mod inspection;
|
||||
mod lifecycle;
|
||||
mod worktree;
|
||||
|
||||
pub(crate) use gc::tool_gc;
|
||||
pub(crate) use inspection::{
|
||||
tool_get_agent_config, tool_get_agent_output, tool_get_agent_remaining_turns_and_budget,
|
||||
};
|
||||
|
||||
@@ -43,6 +43,7 @@ pub async fn dispatch_tool_call(
|
||||
"list_worktrees" => agent_tools::tool_list_worktrees(ctx),
|
||||
"remove_worktree" => agent_tools::tool_remove_worktree(&args, ctx).await,
|
||||
"cleanup_worktrees" => agent_tools::tool_cleanup_worktrees(&args, ctx).await,
|
||||
"gc" => agent_tools::tool_gc(ctx).await,
|
||||
// Editor tools
|
||||
"get_editor_command" => agent_tools::tool_get_editor_command(&args, ctx),
|
||||
// Lifecycle tools
|
||||
|
||||
@@ -180,6 +180,14 @@ pub(super) fn agent_tools() -> Vec<Value> {
|
||||
}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "gc",
|
||||
"description": "Run a build-directory GC pass on demand (story 1199): reclaims orphaned worktree target/ dirs and a stale merge_workspace, never touching the main project's or any live worktree's target/. Returns bytes reclaimed, duration, and which directories were reclaimed or skipped.",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
}),
|
||||
json!({
|
||||
"name": "get_editor_command",
|
||||
"description": "Get the open-in-editor command for a worktree. Returns a ready-to-paste shell command like 'zed /path/to/worktree'. Requires the editor preference to be configured via PUT /api/settings/editor.",
|
||||
|
||||
@@ -116,7 +116,8 @@ mod tests {
|
||||
assert!(names.contains(&"convert_item_type"));
|
||||
assert!(names.contains(&"edit"));
|
||||
assert!(names.contains(&"write"));
|
||||
assert_eq!(tools.len(), 84);
|
||||
assert!(names.contains(&"gc"));
|
||||
assert_eq!(tools.len(), 85);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user