use anyhow::Result;
use clap::{Args, Subcommand};
use agentstatedeveloper_core::{
AsgIndexStore, Engine, FtsFilters, SearchFtsDb,
recipes::{classify_test_migration, migrate_stale_tests},
};
use crate::config::Config;
#[derive(Debug, Subcommand)]
pub enum RecipeCmd {
#[command(name = "classify-test-migration")]
ClassifyTestMigration(ClassifyArgs),
#[command(name = "migrate-stale-tests")]
MigrateStaleTests(ClassifyArgs),
}
#[derive(Debug, Args)]
pub struct ClassifyArgs {
#[arg(required = true, num_args = 1..)]
pub query: Vec<String>,
#[arg(long, default_value = "50")]
pub limit: usize,
}
pub fn run(cfg: &Config, cmd: RecipeCmd) -> Result<()> {
match cmd {
RecipeCmd::ClassifyTestMigration(args) => run_recipe(cfg, args, |e, i, q, query| {
classify_test_migration(e, i, q, query)
}),
RecipeCmd::MigrateStaleTests(args) => run_recipe(cfg, args, |e, i, q, query| {
migrate_stale_tests(e, i, q, query)
}),
}
}
fn run_recipe<F>(cfg: &Config, args: ClassifyArgs, build: F) -> Result<()>
where
F: FnOnce(
&Engine,
&AsgIndexStore,
&[String],
&str,
) -> agentstatedeveloper_core::recipes::Recipe,
{
let query = args.query.join(" ");
let engine = Engine::open_sqlite(&cfg.db_path)?;
let index = AsgIndexStore::from_engine(&engine);
let fts = SearchFtsDb::open(&cfg.db_path).ok();
let candidate_qnames: Vec<String> = if let Some(fts) = fts {
let filters = FtsFilters {
kind: None,
language: None,
include_tests: true,
tests_only: true,
exclude_terms: vec![],
paths_filter: vec![],
exclude_paths: vec![],
exclude_languages: vec![],
};
fts.search(&query, &filters, args.limit)
.unwrap_or_default()
.into_iter()
.map(|h| h.qname)
.collect()
} else {
Vec::new()
};
let recipe = build(&engine, &index, &candidate_qnames, &query);
println!("{}", serde_json::to_string_pretty(&recipe)?);
Ok(())
}