use anyhow::Result;
use serde_json::Value;
use std::sync::Arc;
use crate::librarian::catalog::Catalog;
use crate::librarian::classify::CompiledRule;
use crate::librarian::workspace::WorkspaceConfig;
pub mod find;
pub mod gather;
pub mod get;
pub mod graph;
pub mod scope;
pub(crate) const HIDDEN_STATUSES: &[&str] = &["archived", "superseded", "retired"];
#[derive(Debug)]
pub struct RecoverableError {
pub message: String,
pub hint: Option<String>,
}
impl std::fmt::Display for RecoverableError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.message)?;
if let Some(h) = &self.hint {
write!(f, " (hint: {h})")?;
}
Ok(())
}
}
impl std::error::Error for RecoverableError {}
impl RecoverableError {
#[allow(clippy::new_ret_no_self)]
pub fn new(msg: impl Into<String>) -> anyhow::Error {
anyhow::Error::new(Self {
message: msg.into(),
hint: None,
})
}
pub fn with_hint(msg: impl Into<String>, hint: impl Into<String>) -> anyhow::Error {
anyhow::Error::new(Self {
message: msg.into(),
hint: Some(hint.into()),
})
}
}
pub struct ToolContext {
pub catalog: Arc<parking_lot::Mutex<Catalog>>,
pub workspace: Arc<WorkspaceConfig>,
pub rules: Arc<Vec<CompiledRule>>,
pub embedding: Option<Arc<crate::librarian::embedding::EmbeddingService>>,
pub artifact_store: Option<Arc<dyn crate::librarian::artifact_store::ArtifactVectorStore>>,
pub current_project: Option<Arc<crate::librarian::current_project::CurrentProject>>,
}
pub(crate) fn managed_roots(ctx: &ToolContext) -> Vec<std::path::PathBuf> {
let mut roots: Vec<std::path::PathBuf> = Vec::new();
if let Some(cp) = ctx.current_project.as_deref() {
for candidate in [&cp.git_root, &cp.abs_path] {
if !roots.iter().any(|r| r == candidate) {
roots.push(candidate.clone());
}
}
}
for r in &ctx.workspace.roots {
if !roots.iter().any(|x| x == &r.path) {
roots.push(r.path.clone());
}
}
roots
}
pub(crate) fn containing_root<'a>(
roots: &'a [std::path::PathBuf],
abs_path: &std::path::Path,
) -> Option<&'a std::path::PathBuf> {
roots.iter().find(|root| abs_path.starts_with(root))
}
#[async_trait::async_trait]
pub trait Tool: Send + Sync {
fn name(&self) -> &'static str;
fn description(&self) -> &'static str;
fn input_schema(&self) -> Value;
async fn call(&self, ctx: &ToolContext, args: Value) -> Result<Value>;
}
pub mod create;
pub mod update;
pub mod link;
pub mod delete;
pub mod mv;
pub mod event_create;
pub mod state_at;
pub mod workspace_state_at;
pub mod timeline;
pub mod reindex;
pub mod context;
pub mod audit_doc_refs;
pub mod legibility_scan;
pub mod doctor;
pub mod augment;
pub mod goal_aggregation;
pub mod refresh;
pub mod refresh_stale;
pub mod render;
pub mod schema_validate;
pub mod tracker_design;
pub mod artifact;
pub mod artifact_event;
pub mod artifact_refresh;
pub mod librarian;
pub fn all_tools() -> Vec<Arc<dyn Tool>> {
vec![
Arc::new(artifact::Artifact),
Arc::new(artifact_event::ArtifactEvent),
Arc::new(augment::ArtifactAugment),
Arc::new(artifact_refresh::ArtifactRefreshTool),
Arc::new(librarian::Librarian),
]
}