pub(crate) mod capture;
mod hook;
mod install;
pub(crate) mod procedure;
pub(crate) mod redaction;
mod replay;
pub use procedure::ProcedureStore;
pub use replay::{StepOutcome, replay_procedure};
pub use capture::{
CorrectionType, LearningSource, capture_correction, capture_failed_command, correct_learning,
list_all_entries, query_all_entries_semantic,
};
#[allow(unused_imports)]
pub use capture::{
CapturedLearning, ImportanceScore, LearningContext, LearningError, annotate_with_entities,
annotate_with_thesaurus, query_all_entries,
};
pub(crate) use capture::{build_kg_thesaurus_from_dir, find_kg_dir};
#[allow(unused_imports)]
pub use redaction::redact_secrets;
pub use hook::{AgentFormat, LearnHookType, process_hook_input_with_type};
pub use install::{AgentType, install_hook};
use std::path::PathBuf;
#[derive(Debug, Clone)]
pub struct LearningCaptureConfig {
pub project_dir: PathBuf,
pub global_dir: PathBuf,
pub enabled: bool,
pub ignore_patterns: Vec<String>,
}
impl Default for LearningCaptureConfig {
fn default() -> Self {
let project_dir = std::env::current_dir()
.unwrap_or_else(|_| PathBuf::from("."))
.join(".terraphim")
.join("learnings");
let global_dir = dirs::data_dir()
.unwrap_or_else(|| PathBuf::from("~/.local/share"))
.join("terraphim")
.join("learnings");
Self {
project_dir,
global_dir,
enabled: true,
ignore_patterns: vec![
"cargo test*".to_string(),
"npm test*".to_string(),
"pytest*".to_string(),
"yarn test*".to_string(),
],
}
}
}
impl LearningCaptureConfig {
#[allow(dead_code)]
pub fn new(project_dir: PathBuf, global_dir: PathBuf) -> Self {
Self {
project_dir,
global_dir,
..Default::default()
}
}
pub fn storage_location(&self) -> PathBuf {
if self.project_dir.exists()
|| self
.project_dir
.parent()
.map(|p| p.exists())
.unwrap_or(false)
{
self.project_dir.clone()
} else {
self.global_dir.clone()
}
}
pub fn should_ignore(&self, command: &str) -> bool {
for pattern in &self.ignore_patterns {
if let Ok(glob) = glob::Pattern::new(pattern) {
if glob.matches(command) {
return true;
}
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = LearningCaptureConfig::default();
assert!(config.enabled);
assert!(!config.ignore_patterns.is_empty());
}
#[test]
fn test_should_ignore_test_commands() {
let config = LearningCaptureConfig::default();
assert!(config.should_ignore("cargo test"));
assert!(config.should_ignore("cargo test --lib"));
assert!(config.should_ignore("npm test"));
assert!(config.should_ignore("pytest tests/"));
assert!(!config.should_ignore("cargo build"));
assert!(!config.should_ignore("git push"));
}
#[test]
fn test_storage_location_prefers_project() {
let config = LearningCaptureConfig::default();
let location = config.storage_location();
assert!(location.ends_with("learnings"));
}
}