diff --git a/AGENTS.md b/AGENTS.md index 6ecc357d..285478ce 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -159,3 +159,4 @@ Parse: `file:line:col` → location | 💡 → how to fix | Exit 0/1 → pass/fa - ❌ Full scan per edit → ✅ Scope to file - ❌ Fix symptom (`if (x) { x.y }`) → ✅ Root cause (`x?.y`) ```` +Use 'bd' for task tracking diff --git a/crates/terraphim-session-analyzer/tests/filename_target_filtering_tests.rs b/crates/terraphim-session-analyzer/tests/filename_target_filtering_tests.rs index adbaaf20..d5b26915 100644 --- a/crates/terraphim-session-analyzer/tests/filename_target_filtering_tests.rs +++ b/crates/terraphim-session-analyzer/tests/filename_target_filtering_tests.rs @@ -503,11 +503,10 @@ mod collaboration_and_attribution_tests { for analysis in &analyses { for file_op in &analysis.file_operations { total_operations += 1; - if file_op.agent_context.is_some() { + if let Some(agent_context) = &file_op.agent_context { operations_with_context += 1; // Verify the agent context is reasonable - let agent_context = file_op.agent_context.as_ref().unwrap(); assert!( !agent_context.is_empty(), "Agent context should not be empty" diff --git a/crates/terraphim_agent/src/main.rs b/crates/terraphim_agent/src/main.rs index e82fd7f7..452c9e07 100644 --- a/crates/terraphim_agent/src/main.rs +++ b/crates/terraphim_agent/src/main.rs @@ -46,7 +46,8 @@ fn show_usage_info() { println!("Terraphim AI Agent v{}", env!("CARGO_PKG_VERSION")); println!(); println!("Interactive Mode (requires TTY):"); - println!(" terraphim-agent # Start REPL or TUI"); + println!(" terraphim-agent # Start REPL (default)"); + println!(" terraphim-agent --tui # Start TUI (requires server)"); println!(" terraphim-agent repl # Explicit REPL mode"); println!(); println!("Common Commands:"); @@ -392,6 +393,9 @@ struct Cli { /// Output format (human, json, json-compact) #[arg(long, value_enum, default_value_t = OutputFormat::Human)] format: OutputFormat, + /// Force TUI mode (default is REPL) + #[arg(long, default_value_t = false)] + tui: bool, #[command(subcommand)] command: Option, } @@ -568,7 +572,8 @@ fn main() -> Result<()> { }); match cli.command { - Some(Command::Interactive) | None => { + Some(Command::Interactive) => { + // Explicit interactive command - force TUI mode // Check if we're in a TTY for interactive mode (both stdout and stdin required) use atty::Stream; if !atty::is(Stream::Stdout) { @@ -589,6 +594,46 @@ fn main() -> Result<()> { } } + None => { + // No command specified - default to REPL mode or TUI mode if --tui flag is set + if cli.tui { + // Check if we're in a TTY for TUI mode + use atty::Stream; + if !atty::is(Stream::Stdout) { + eprintln!("Error: TUI mode requires a TTY (terminal)"); + std::process::exit(1); + } + + if !atty::is(Stream::Stdin) { + eprintln!("Error: TUI mode requires a TTY (terminal)"); + std::process::exit(1); + } + + if cli.server { + run_tui_server_mode(&cli.server_url, cli.transparent) + } else { + run_tui_offline_mode(cli.transparent) + } + } else { + // Default to REPL mode + #[cfg(feature = "repl")] + { + let rt = Runtime::new()?; + if cli.server { + rt.block_on(repl::run_repl_server_mode(&cli.server_url)) + } else { + rt.block_on(repl::run_repl_offline_mode()) + } + } + + #[cfg(not(feature = "repl"))] + { + // If repl feature is not enabled, show error + anyhow::bail!("REPL mode requires 'repl' feature. Build with: cargo build --features repl"); + } + } + } + #[cfg(feature = "repl")] Some(Command::Repl { server, server_url }) => { let rt = Runtime::new()?; diff --git a/crates/terraphim_agent/src/repl/mcp_tools.rs b/crates/terraphim_agent/src/repl/mcp_tools.rs index 819c46c2..dfd667f4 100644 --- a/crates/terraphim_agent/src/repl/mcp_tools.rs +++ b/crates/terraphim_agent/src/repl/mcp_tools.rs @@ -19,6 +19,7 @@ pub struct McpToolsHandler { } #[cfg(feature = "repl-mcp")] +#[allow(dead_code)] impl McpToolsHandler { /// Create a new McpToolsHandler with a reference to the TuiService pub fn new(service: Arc) -> Self { @@ -52,10 +53,9 @@ impl McpToolsHandler { exclude_term: bool, ) -> anyhow::Result> { let role = self.get_role().await; - Ok(self - .service + self.service .extract_paragraphs(&role, text, exclude_term) - .await?) + .await } /// Find all thesaurus term matches in the given text @@ -80,9 +80,10 @@ impl McpToolsHandler { let role = self.get_role().await; let link_type = match format.as_deref() { Some("html") => LinkType::HTMLLinks, - Some("markdown") | _ => LinkType::MarkdownLinks, + Some("markdown") | None => LinkType::MarkdownLinks, + _ => LinkType::MarkdownLinks, }; - Ok(self.service.replace_matches(&role, text, link_type).await?) + self.service.replace_matches(&role, text, link_type).await } /// Get thesaurus entries for a role diff --git a/crates/terraphim_persistence/src/settings.rs b/crates/terraphim_persistence/src/settings.rs index 2683e9f4..fafe5ec9 100644 --- a/crates/terraphim_persistence/src/settings.rs +++ b/crates/terraphim_persistence/src/settings.rs @@ -252,8 +252,6 @@ pub async fn parse_profile( } #[cfg(feature = "services-redis")] Scheme::Redis => Operator::from_iter::(profile.clone())?.finish(), - #[cfg(feature = "services-rocksdb")] - Scheme::Rocksdb => Operator::from_iter::(profile.clone())?.finish(), #[cfg(feature = "services-redb")] Scheme::Redb => { // Ensure parent directory exists for ReDB database file @@ -468,77 +466,6 @@ mod tests { Ok(()) } - /// Test saving and loading a struct to rocksdb profile - #[cfg(feature = "services-rocksdb")] - #[tokio::test] - #[serial_test::serial] - async fn test_save_and_load_rocksdb() -> Result<()> { - use tempfile::TempDir; - - // Create temporary directory for test - let temp_dir = TempDir::new().unwrap(); - let rocksdb_path = temp_dir.path().join("test_rocksdb"); - - // Create test settings with rocksdb profile - let mut profiles = std::collections::HashMap::new(); - - // DashMap profile (needed as fastest operator fallback) - let mut dashmap_profile = std::collections::HashMap::new(); - dashmap_profile.insert("type".to_string(), "dashmap".to_string()); - dashmap_profile.insert( - "root".to_string(), - temp_dir - .path() - .join("dashmap") - .to_string_lossy() - .to_string(), - ); - profiles.insert("dashmap".to_string(), dashmap_profile); - - // RocksDB profile for testing - let mut rocksdb_profile = std::collections::HashMap::new(); - rocksdb_profile.insert("type".to_string(), "rocksdb".to_string()); - rocksdb_profile.insert( - "datadir".to_string(), - rocksdb_path.to_string_lossy().to_string(), - ); - profiles.insert("rocksdb".to_string(), rocksdb_profile); - - let settings = DeviceSettings { - server_hostname: "localhost:8000".to_string(), - api_endpoint: "http://localhost:8000/api".to_string(), - initialized: false, - default_data_path: temp_dir.path().to_string_lossy().to_string(), - profiles, - }; - - // Initialize storage with custom settings - let storage = crate::init_device_storage_with_settings(settings).await?; - - // Verify rocksdb profile is available - assert!( - storage.ops.contains_key("rocksdb"), - "RocksDB profile should be available. Available profiles: {:?}", - storage.ops.keys().collect::>() - ); - - // Test direct operator write/read - let rocksdb_op = &storage.ops.get("rocksdb").unwrap().0; - let test_key = "test_rocksdb_key.json"; - let test_data = r#"{"name":"Test RocksDB Object","age":30}"#; - - rocksdb_op.write(test_key, test_data).await?; - let read_data = rocksdb_op.read(test_key).await?; - let read_str = String::from_utf8(read_data.to_vec()).unwrap(); - - assert_eq!( - test_data, read_str, - "RocksDB read data should match written data" - ); - - Ok(()) - } - /// Test saving and loading a struct to dashmap profile (if available) #[cfg(feature = "dashmap")] #[tokio::test] diff --git a/crates/terraphim_persistence/src/thesaurus.rs b/crates/terraphim_persistence/src/thesaurus.rs index 15d1ba38..d32d51ca 100644 --- a/crates/terraphim_persistence/src/thesaurus.rs +++ b/crates/terraphim_persistence/src/thesaurus.rs @@ -91,72 +91,6 @@ mod tests { Ok(()) } - /// Test saving and loading a thesaurus to rocksdb profile - #[cfg(feature = "services-rocksdb")] - #[tokio::test] - #[serial_test::serial] - async fn test_save_and_load_thesaurus_rocksdb() -> Result<()> { - use tempfile::TempDir; - use terraphim_settings::DeviceSettings; - - // Create temporary directory for test - let temp_dir = TempDir::new().unwrap(); - let rocksdb_path = temp_dir.path().join("test_thesaurus_rocksdb"); - - // Create test settings with rocksdb profile - let mut profiles = std::collections::HashMap::new(); - - // Memory profile (needed as fastest operator fallback) - let mut memory_profile = std::collections::HashMap::new(); - memory_profile.insert("type".to_string(), "memory".to_string()); - profiles.insert("memory".to_string(), memory_profile); - - // RocksDB profile for testing - let mut rocksdb_profile = std::collections::HashMap::new(); - rocksdb_profile.insert("type".to_string(), "rocksdb".to_string()); - rocksdb_profile.insert( - "datadir".to_string(), - rocksdb_path.to_string_lossy().to_string(), - ); - profiles.insert("rocksdb".to_string(), rocksdb_profile); - - let settings = DeviceSettings { - server_hostname: "localhost:8000".to_string(), - api_endpoint: "http://localhost:8000/api".to_string(), - initialized: false, - default_data_path: temp_dir.path().to_string_lossy().to_string(), - profiles, - }; - - // Initialize storage with custom settings - let storage = crate::init_device_storage_with_settings(settings).await?; - - // Verify rocksdb profile is available - assert!( - storage.ops.contains_key("rocksdb"), - "RocksDB profile should be available. Available profiles: {:?}", - storage.ops.keys().collect::>() - ); - - // Test direct operator write/read with thesaurus data - let rocksdb_op = &storage.ops.get("rocksdb").unwrap().0; - let test_key = "thesaurus_test_rocksdb_thesaurus.json"; - let test_thesaurus = Thesaurus::new("Test RocksDB Thesaurus".to_string()); - let test_data = serde_json::to_string(&test_thesaurus).unwrap(); - - rocksdb_op.write(test_key, test_data.clone()).await?; - let read_data = rocksdb_op.read(test_key).await?; - let read_str = String::from_utf8(read_data.to_vec()).unwrap(); - let loaded_thesaurus: Thesaurus = serde_json::from_str(&read_str).unwrap(); - - assert_eq!( - test_thesaurus, loaded_thesaurus, - "Loaded RocksDB thesaurus does not match the original" - ); - - Ok(()) - } - /// Test saving and loading a thesaurus to memory profile #[tokio::test] #[serial_test::serial] diff --git a/crates/terraphim_update/src/lib.rs b/crates/terraphim_update/src/lib.rs index 82f23b75..3ea85d23 100644 --- a/crates/terraphim_update/src/lib.rs +++ b/crates/terraphim_update/src/lib.rs @@ -164,7 +164,7 @@ impl TerraphimUpdater { builder.show_download_progress(show_progress); // Set custom install path to preserve underscore naming - builder.bin_install_path(&format!("/usr/local/bin/{}", bin_name)); + builder.bin_install_path(format!("/usr/local/bin/{}", bin_name)); match builder.build() { Ok(updater) => { @@ -285,7 +285,7 @@ impl TerraphimUpdater { builder.verifying_keys(vec![key_array]); // Enable signature verification // Set custom install path to preserve underscore naming - builder.bin_install_path(&format!("/usr/local/bin/{}", bin_name)); + builder.bin_install_path(format!("/usr/local/bin/{}", bin_name)); match builder.build() { Ok(updater) => match updater.update() { @@ -540,7 +540,7 @@ impl TerraphimUpdater { builder.current_version(current_version); // Set custom install path to preserve underscore naming - builder.bin_install_path(&format!("/usr/local/bin/{}", bin_name)); + builder.bin_install_path(format!("/usr/local/bin/{}", bin_name)); let updater = builder.build()?; @@ -905,7 +905,7 @@ pub async fn check_for_updates_auto(bin_name: &str, current_version: &str) -> Re builder.current_version(¤t_version); // Set custom install path to preserve underscore naming - builder.bin_install_path(&format!("/usr/local/bin/{}", bin_name)); + builder.bin_install_path(format!("/usr/local/bin/{}", bin_name)); match builder.build() { Ok(updater) => match updater.get_latest_release() {