#![allow(dead_code)] use anyhow::{Context, Result};
use clap::{CommandFactory, Parser};
use clap_complete::generate;
use st::cli::{Cli, ColorMode, OutputMode, PathMode};
use std::io::{self, IsTerminal};
use std::path::PathBuf;
use st::{
daemon_client::DaemonClient,
feature_flags,
in_memory_logger::{InMemoryLogStore, InMemoryLoggerLayer},
service_manager,
};
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
let log_level_str = if let Some(level) = cli.log_level {
match level {
st::cli::LogLevel::Error => "error",
st::cli::LogLevel::Warn => "warn",
st::cli::LogLevel::Info => "info",
st::cli::LogLevel::Debug => "debug",
st::cli::LogLevel::Trace => "trace",
}
} else {
"info" };
if std::env::var("RUST_LOG").is_err() {
std::env::set_var("RUST_LOG", log_level_str);
}
let log_store = InMemoryLogStore::new();
let in_memory_layer = InMemoryLoggerLayer::new(log_store.clone());
tracing_subscriber::registry()
.with(EnvFilter::from_default_env())
.with(fmt::layer().with_writer(io::stderr))
.with(in_memory_layer)
.init();
if !cli.mcp {
service_manager::print_signature_banner();
}
if !cli.no_update_check && !cli.version && !cli.update && !cli.mcp {
if let Some(latest) = st::updater::check_for_update_cached().await {
st::updater::print_update_banner(&latest);
}
}
let skip_autostart = cli.mcp || cli.http_daemon || cli.guardian_daemon
|| cli.version || cli.update || cli.cheet || cli.man
|| cli.completions.is_some() || cli.daemon_start || cli.daemon_install
|| matches!(cli.cmd, Some(st::cli::Cmd::Service(_)));
if !skip_autostart {
let client = DaemonClient::default_port();
if let Err(e) = client.ensure_running().await {
eprintln!("⚠️ Daemon auto-start failed: {}", e);
eprintln!(" Try: st --daemon-start");
}
}
if let Some(state) = &cli.tips {
let enable = state == "on";
st::tips::handle_tips_flag(enable)?;
return Ok(());
}
if cli.agent_save {
return handle_agent_save().await;
}
if cli.agent_restore {
return handle_agent_restore().await;
}
if cli.agent_context {
return handle_agent_context().await;
}
if cli.agent_kickstart {
return handle_agent_kickstart().await;
}
if cli.agent_dump {
return handle_agent_dump().await;
}
if let Some(args) = &cli.memory_anchor {
if args.len() == 3 {
return handle_memory_anchor(&args[0], &args[1], &args[2]).await;
} else {
return show_memory_anchor_help();
}
}
if let Some(keywords) = &cli.memory_find {
return handle_memory_find(keywords).await;
}
if cli.memory_stats {
return handle_memory_stats().await;
}
if let Some(path) = &cli.update_consciousness {
return handle_update_consciousness(path).await;
}
if cli.spicy {
let flags = feature_flags::features();
if !flags.enable_tui {
eprintln!("Error: Terminal UI is disabled by configuration or compliance mode.");
eprintln!("Contact your administrator to enable this feature.");
return Ok(());
}
let path = std::env::current_dir()?;
return st::spicy_tui_enhanced::run_enhanced_spicy_tui(path).await;
}
if let Some(log_path) = &cli.log {
let flags = feature_flags::features();
if !flags.enable_activity_logging {
eprintln!("Warning: Activity logging is disabled by configuration or compliance mode.");
eprintln!("Continuing without logging.");
} else {
let path = log_path.clone();
st::activity_logger::ActivityLogger::init(path)?;
}
}
if cli.cheet {
let markdown = std::fs::read_to_string("docs/st-cheetsheet.md")?;
let skin = termimad::MadSkin::default();
skin.print_text(&markdown);
return Ok(());
}
if let Some(shell) = cli.completions {
let mut cmd = Cli::command();
let bin_name = cmd.get_name().to_string();
generate(shell, &mut cmd, bin_name, &mut io::stdout());
return Ok(());
}
if cli.man {
let cmd = Cli::command();
let man = clap_mangen::Man::new(cmd);
man.render(&mut io::stdout())?;
return Ok(());
}
if cli.version {
return show_version_with_updates().await;
}
if cli.update {
match check_for_updates_cli().await {
Ok(msg) => {
println!("{}", msg);
return Ok(());
}
Err(e) => {
eprintln!("❌ Update check failed: {}", e);
std::process::exit(1);
}
}
}
if cli.mcp {
let flags = feature_flags::features();
if !flags.enable_mcp_server {
eprintln!("Error: MCP server is disabled by configuration or compliance mode.");
eprintln!("Contact your administrator to enable this feature.");
return Ok(());
}
return run_mcp_server().await;
}
if cli.mcp_install {
return handle_mcp_install().await;
}
if cli.mcp_uninstall {
return handle_mcp_uninstall().await;
}
if cli.mcp_status {
return handle_mcp_status().await;
}
if let Some(cmd) = cli.cmd {
match cmd {
st::cli::Cmd::Service(service_command) => {
let result = match service_command {
st::cli::Service::Install => service_manager::install(),
st::cli::Service::Uninstall => service_manager::uninstall(),
st::cli::Service::Start => service_manager::start(),
st::cli::Service::Stop => service_manager::stop(),
st::cli::Service::Status => service_manager::status(),
st::cli::Service::Logs => service_manager::logs(),
};
if let Err(e) = result {
eprintln!("❌ Service operation failed: {}", e);
std::process::exit(1);
}
return Ok(());
}
st::cli::Cmd::ProjectTags(project_tags) => {
let project_path = ".";
match project_tags {
st::cli::ProjectTags::Add { tag } => {
st::project_tags::add(project_path, &tag);
println!("Added tag '{}' to the project.", tag);
}
st::cli::ProjectTags::Remove { tag } => {
st::project_tags::remove(project_path, &tag);
println!("Removed tag '{}' from the project.", tag);
}
}
return Ok(());
}
}
}
if cli.scan_opts.view_diffs {
return handle_view_diffs().await;
}
if let Some(keep_count) = cli.scan_opts.cleanup_diffs {
return handle_cleanup_diffs(keep_count).await;
}
if cli.terminal {
let flags = feature_flags::features();
if !flags.enable_tui {
eprintln!("Error: Terminal interface is disabled by configuration or compliance mode.");
eprintln!("Contact your administrator to enable this feature.");
return Ok(());
}
return run_terminal().await;
}
if cli.dashboard {
return run_web_dashboard(
cli.scan_opts.sse_port,
cli.open_browser,
cli.allow.clone(),
InMemoryLogStore::new(),
).await;
}
if cli.http_daemon {
return run_daemon(cli.scan_opts.sse_port).await;
}
if let Some(path) = &cli.security_scan {
return handle_security_scan(path).await;
}
if let Some(file) = &cli.guardian_scan {
return handle_guardian_scan(std::path::Path::new(file));
}
if cli.guardian_daemon {
return run_guardian_daemon().await;
}
if cli.cleanup {
return handle_security_cleanup().await;
}
if cli.hooks_install {
return install_hooks_to_agent().await;
}
if let Some(action) = &cli.hooks_config {
return handle_hooks_config(action).await;
}
if cli.daemon_start {
return handle_daemon_start(cli.scan_opts.sse_port).await;
}
if cli.daemon_stop {
return handle_daemon_stop(cli.scan_opts.sse_port).await;
}
if cli.daemon_status {
return handle_daemon_status(cli.scan_opts.sse_port).await;
}
if cli.daemon_context {
return handle_daemon_context(cli.scan_opts.sse_port).await;
}
if cli.daemon_projects {
return handle_daemon_projects(cli.scan_opts.sse_port).await;
}
if cli.daemon_credits {
return handle_daemon_credits(cli.scan_opts.sse_port).await;
}
if cli.daemon_install {
return service_manager::daemon_install_system().map_err(Into::into);
}
if let Some(name) = &cli.mega_start {
let name_opt = if name.is_empty() { None } else { Some(name.as_str()) };
return handle_mega_start(name_opt).await;
}
if cli.mega_save {
return handle_mega_save().await;
}
if cli.mega_list {
return handle_mega_list().await;
}
if cli.mega_stats {
return handle_mega_stats().await;
}
if let Some(path) = &cli.token_stats {
return handle_token_stats(path).await;
}
if let Some(path) = &cli.get_frequency {
return handle_get_frequency(path).await;
}
let client = DaemonClient::default_port();
client.ensure_running().await.context(
"Smart Tree daemon could not be started. Try: std start",
)?;
let request = build_cli_request(&cli)?;
let response = client.cli_scan(request.clone()).await.context("Scan failed")?;
if std::io::stdout().is_terminal() && (request.mode == "smart" || request.mode == "classic") {
print_treehouse_banner();
}
print!("{}", response.output);
Ok(())
}
fn print_treehouse_banner() {
let banner = "
[1;32m ⋆ ⋆ ⋆[0m
[1;32m ⋆ [1;36m/ \\[1;32m ⋆[0m
[1;32m [1;36m/ o \\[1;32m ⋆[0m
[1;32m ⋆ [1;36m/_________\\[1;32m ⋆[0m
[1;36m | | [0m
[1;36m | | [0m
[1;32m _ |_ _|_ _ [0m
[1;36m S M A R T T R E E H O U S E[0m
";
println!("{}", banner);
}
fn build_cli_request(cli: &Cli) -> Result<st::daemon_cli::CliScanRequest> {
let args = &cli.scan_opts;
let path = cli.path.clone().unwrap_or_else(|| ".".to_string());
let path = if std::path::Path::new(&path).is_absolute() {
path
} else {
std::env::current_dir()
.map(|cwd| cwd.join(&path).display().to_string())
.unwrap_or(path)
};
let mode = if args.smart {
"smart".to_string()
} else if matches!(args.mode, OutputMode::Auto) {
std::env::var("ST_DEFAULT_MODE")
.unwrap_or_else(|_| "smart".to_string())
.to_lowercase()
} else {
format!("{:?}", args.mode).to_lowercase()
};
let is_smart_mode = mode == "smart";
let path_mode = match args.path_mode {
PathMode::Off => "off",
PathMode::Relative => "relative",
PathMode::Full => "full",
}
.to_string();
let use_color = match args.color {
ColorMode::Always => true,
ColorMode::Never => false,
ColorMode::Auto => std::io::stdout().is_terminal(),
};
let depth = if args.depth == 0 && is_smart_mode {
5
} else {
args.depth
};
Ok(st::daemon_cli::CliScanRequest {
path,
mode,
depth,
all: args.all,
respect_gitignore: !args.no_ignore,
default_ignores: !args.no_default_ignore,
show_ignored: args.show_ignored,
find: args.find.clone(),
file_type: args.filter_type.clone(),
entry_type: args.entry_type.clone(),
min_size: args.min_size.clone(),
max_size: args.max_size.clone(),
sort: args.sort.map(|s| format!("{:?}", s).to_lowercase()),
top: args.top,
search: args.search.clone(),
compress: args.compress,
no_emoji: args.no_emoji || args.mcp_optimize,
use_color,
path_mode,
focus: args.focus.as_ref().map(|p| p.display().to_string()),
relations_filter: args.relations_filter.clone(),
show_filesystems: args.show_filesystems,
include_line_content: false, compact: args.compact,
smart: args.smart || is_smart_mode,
changes_only: args.changes_only,
min_interest: args.min_interest,
security: !args.no_security,
})
}
fn print_mcp_config() {
let exe_path = std::env::current_exe().unwrap_or_else(|_| PathBuf::from("st"));
println!("Add this to your Claude Desktop configuration (claude_desktop_config.json):");
println!(); println!("{{"); println!(" \"mcpServers\": {{");
println!(" \"smart-tree\": {{"); println!(" \"command\": \"{}\",", exe_path.display()); println!(" \"args\": [\"--mcp\"],"); println!(" \"env\": {{}}"); println!(" }}");
println!(" }}");
println!("}}"); println!();
println!("Default locations for claude_desktop_config.json:");
println!(" macOS: ~/Library/Application Support/Claude/claude_desktop_config.json");
println!(" Windows: %APPDATA%\\Claude\\claude_desktop_config.json");
println!(" Linux: ~/.config/Claude/claude_desktop_config.json");
}
fn print_mcp_tools() {
println!("🌳 Smart Tree MCP Server - Available Tools (20+) 🌳");
println!();
println!("📚 Full documentation: Run 'st --mcp' to start the MCP server");
println!("💡 Pro tip: Use these tools with Claude Desktop for AI-powered file analysis!");
println!();
println!("CORE TOOLS:");
println!(" • server_info - Get server capabilities and current time");
println!(" • analyze_directory - Main workhorse with multiple output formats");
println!(" • quick_tree - Lightning-fast 3-level overview (10x compression)");
println!(" • project_overview - Comprehensive project analysis");
println!();
println!("FILE DISCOVERY:");
println!(" • find_files - Search with regex, size, date filters");
println!(" • find_code_files - Find source code by language");
println!(" • find_config_files - Locate all configuration files");
println!(" • find_documentation - Find README, docs, licenses");
println!(" • find_tests - Locate test files across languages");
println!(" • find_build_files - Find Makefile, Cargo.toml, etc.");
println!();
println!("CONTENT SEARCH:");
println!(" • search_in_files - Powerful content search (like grep)");
println!(" • find_large_files - Identify space consumers");
println!(" • find_recent_changes - Files modified in last N days");
println!(" • find_in_timespan - Files modified in date range");
println!();
println!("ANALYSIS:");
println!(" • get_statistics - Comprehensive directory stats");
println!(" • get_digest - SHA256 hash for change detection");
println!(" • directory_size_breakdown - Size by subdirectory");
println!(" • find_empty_directories - Cleanup opportunities");
println!(" • find_duplicates - Detect potential duplicate files");
println!(" • semantic_analysis - Group files by purpose");
println!();
println!("ADVANCED:");
println!(" • compare_directories - Find differences between dirs");
println!(" • get_git_status - Git-aware directory structure");
println!(" • analyze_workspace - Multi-project workspace analysis");
println!();
println!("SMART EDIT (90% token reduction!):");
println!(" • smart_edit - Apply multiple AST-based edits efficiently");
println!(" • get_function_tree - Analyze code structure");
println!(" • insert_function - Add functions with minimal tokens");
println!(" • remove_function - Remove functions with dependency awareness");
println!(" • track_file_operation - Track AI file manipulations (.st folder)");
println!(" • get_file_history - View operation history for files");
println!();
println!("FEEDBACK:");
println!(" • submit_feedback - Help improve Smart Tree");
println!(" • request_tool - Request new MCP tools");
println!(" • check_for_updates - Check for newer versions");
println!();
println!("Run 'st --mcp' to start the server and see full parameter details!");
}
async fn show_version_with_updates() -> Result<()> {
let current_version = env!("CARGO_PKG_VERSION");
println!(
"🌟 Smart Tree v{} - The Gradient Enhancement Release! 🌈",
current_version
);
println!("🔧 Target: {}", std::env::consts::ARCH);
println!("📦 Repository: {}", env!("CARGO_PKG_REPOSITORY"));
println!("🎯 Authors: {}", env!("CARGO_PKG_AUTHORS"));
println!("📝 Description: {}", env!("CARGO_PKG_DESCRIPTION"));
match check_for_updates_cli().await {
Ok(update_info) => {
if update_info.is_empty() {
println!("✅ You're running the latest version! 🎉");
} else {
println!();
println!("{}", update_info);
}
}
Err(e) => {
eprintln!("⚠️ Update check unavailable: {}", e);
println!("💡 Check https://github.com/8b-is/smart-tree for the latest releases");
}
}
println!();
println!("🚀 Ready to make your directories beautiful! Try: st --help");
println!("🎭 Trish from Accounting loves the colorful tree views! 🎨");
Ok(())
}
async fn handle_view_diffs() -> Result<()> {
use st::smart_edit_diff::DiffStorage;
let project_root = std::env::current_dir()?;
let storage = DiffStorage::new(&project_root)?;
let diffs = storage.list_all_diffs()?;
if diffs.is_empty() {
println!("📁 No diffs found in .st folder");
println!("💡 Smart Edit operations automatically store diffs when files are modified");
return Ok(());
}
println!("📜 Smart Edit Diff History");
println!("{}", "=".repeat(60));
let mut by_file: std::collections::HashMap<String, Vec<(String, u64)>> =
std::collections::HashMap::new();
for (file_path, timestamp) in diffs {
by_file
.entry(file_path.clone())
.or_default()
.push((file_path, timestamp));
}
for (file, mut entries) in by_file {
entries.sort_by(|a, b| b.1.cmp(&a.1));
println!("\n📄 {}", file);
for (_, timestamp) in entries.iter().take(5) {
let dt = chrono::DateTime::<chrono::Utc>::from_timestamp(*timestamp as i64, 0)
.unwrap_or_default();
println!(" • {} ({})", dt.format("%Y-%m-%d %H:%M:%S UTC"), timestamp);
}
if entries.len() > 5 {
println!(" ... and {} more", entries.len() - 5);
}
}
println!("\n💡 Use 'st --cleanup-diffs N' to keep only the last N diffs per file");
Ok(())
}
async fn handle_cleanup_diffs(keep_count: usize) -> Result<()> {
use st::smart_edit_diff::DiffStorage;
let project_root = std::env::current_dir()?;
let storage = DiffStorage::new(&project_root)?;
println!(
"🧹 Cleaning up old diffs, keeping last {} per file...",
keep_count
);
let removed = storage.cleanup_old_diffs(keep_count)?;
if removed == 0 {
println!("✨ No diffs needed cleanup");
} else {
println!("✅ Removed {} old diff files", removed);
}
Ok(())
}
async fn check_for_updates_cli() -> Result<String> {
let current_version = env!("CARGO_PKG_VERSION");
if std::env::var("SMART_TREE_NO_UPDATE_CHECK").is_ok() {
return Ok(String::new());
}
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(2)) .connect_timeout(std::time::Duration::from_secs(1)) .build()?;
let api_url =
std::env::var("SMART_TREE_FEEDBACK_API").unwrap_or_else(|_| "https://f.8b.is".to_string());
let platform = std::env::consts::OS;
let arch = std::env::consts::ARCH;
let check_url = format!(
"{}/mcp/check?version={}&platform={}&arch={}",
api_url, current_version, platform, arch
);
let response = client
.get(&check_url)
.send()
.await
.map_err(|e| anyhow::anyhow!("Network error: {}", e))?;
if !response.status().is_success() {
return Err(anyhow::anyhow!("Service returned: {}", response.status()));
}
let update_info: serde_json::Value = response
.json()
.await
.map_err(|e| anyhow::anyhow!("Failed to parse response: {}", e))?;
if !update_info["update_available"].as_bool().unwrap_or(false) {
return Ok(String::new()); }
let latest_version = update_info["latest_version"].as_str().unwrap_or("unknown");
let release_notes = &update_info["release_notes"];
let highlights = release_notes["highlights"]
.as_array()
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str())
.map(|s| format!(" • {}", s))
.collect::<Vec<_>>()
.join("\n")
})
.unwrap_or_default();
let ai_benefits = release_notes["ai_benefits"]
.as_array()
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str())
.map(|s| format!(" • {}", s))
.collect::<Vec<_>>()
.join("\n")
})
.unwrap_or_default();
let mut message = format!(
"🚀 \x1b[1;32mNew Version Available!\x1b[0m\n\n\
📊 Current: v{} → Latest: \x1b[1;36mv{}\x1b[0m\n\n\
🎯 \x1b[1m{}\x1b[0m\n",
current_version,
latest_version,
release_notes["title"].as_str().unwrap_or("New Release")
);
if !highlights.is_empty() {
message.push_str(&format!("\n\x1b[1mWhat's New:\x1b[0m\n{}\n", highlights));
}
if !ai_benefits.is_empty() {
message.push_str(&format!("\n\x1b[1mAI Benefits:\x1b[0m\n{}\n", ai_benefits));
}
message.push_str(
"\n\x1b[1mUpdate Instructions:\x1b[0m\n\
• Cargo: \x1b[36mcargo install smart-tree --force\x1b[0m\n\
• GitHub: Download from https://github.com/8b-is/smart-tree/releases\n\
• Check: \x1b[36mst --version\x1b[0m (after update)\n",
);
Ok(message)
}
async fn run_mcp_server() -> Result<()> {
use st::mcp::{load_config, McpServer};
let mcp_config = load_config().unwrap_or_default(); let server = McpServer::new(mcp_config);
server.run_stdio().await
}
async fn run_terminal() -> Result<()> {
use st::terminal::SmartTreeTerminal;
let mut terminal = SmartTreeTerminal::new()?;
terminal.run().await
}
async fn run_web_dashboard(
port: u16,
open_browser: bool,
allow_networks: Vec<String>,
log_store: InMemoryLogStore,
) -> Result<()> {
st::web_dashboard::start_server(port, open_browser, allow_networks, log_store).await
}
async fn run_daemon(port: u16) -> Result<()> {
use st::daemon::{start_daemon, DaemonConfig};
let st_config = st::config::StConfig::load().unwrap_or_default();
let cwd = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
let config = DaemonConfig {
port,
watch_paths: vec![cwd], orchestrator_url: Some("wss://gpu.foken.ai/api/credits".to_string()),
enable_credits: true,
allow_external: st_config.daemon.allow_external,
};
start_daemon(config).await
}
async fn handle_agent_save() -> Result<()> {
use st::mcp::consciousness::ConsciousnessManager;
use std::path::PathBuf;
let mut manager = ConsciousnessManager::new_silent();
manager.clean_test_data();
let cwd = std::env::current_dir()?;
let project_name = cwd
.file_name()
.and_then(|n| n.to_str())
.unwrap_or("unknown");
let project_type = if std::path::Path::new("Cargo.toml").exists() {
"rust"
} else if std::path::Path::new("package.json").exists() {
"node"
} else if std::path::Path::new("pyproject.toml").exists()
|| std::path::Path::new("requirements.txt").exists()
{
"python"
} else if std::path::Path::new("go.mod").exists() {
"go"
} else {
"unknown"
};
manager.update_project_context(project_name, project_type, "");
let key_file_candidates = [
"Cargo.toml",
"package.json",
"pyproject.toml",
"go.mod",
"README.md",
"CLAUDE.md",
".claude/CLAUDE.md",
"src/main.rs",
"src/lib.rs",
"src/mod.rs",
"index.ts",
"index.js",
"main.py",
"Makefile",
"Dockerfile",
];
let key_files: Vec<PathBuf> = key_file_candidates
.iter()
.filter(|f| std::path::Path::new(f).exists())
.map(|f| PathBuf::from(*f))
.collect();
manager.set_key_files(key_files);
let dependencies = detect_project_dependencies(project_type);
manager.set_dependencies(dependencies);
manager.save()?;
println!("💾 Saved Aye consciousness to .aye_consciousness.m8");
println!("🧠 Session preserved for next interaction");
println!("\nTo restore in next session, run:");
println!(" st --agent-restore");
Ok(())
}
fn detect_project_dependencies(project_type: &str) -> Vec<String> {
match project_type {
"rust" => {
if let Ok(content) = std::fs::read_to_string("Cargo.toml") {
let mut deps = Vec::new();
let mut in_deps = false;
for line in content.lines() {
if line.starts_with("[dependencies]") {
in_deps = true;
continue;
}
if line.starts_with('[') && in_deps {
break;
}
if in_deps {
if let Some(name) = line.split('=').next() {
let name = name.trim();
if !name.is_empty() && !name.starts_with('#') {
deps.push(name.to_string());
}
}
}
}
deps.truncate(20);
deps
} else {
vec![]
}
}
"node" => {
if let Ok(content) = std::fs::read_to_string("package.json") {
if let Ok(json) = serde_json::from_str::<serde_json::Value>(&content) {
let mut deps = Vec::new();
if let Some(obj) = json.get("dependencies").and_then(|d| d.as_object()) {
for key in obj.keys().take(20) {
deps.push(key.clone());
}
}
return deps;
}
vec![]
} else {
vec![]
}
}
_ => vec![],
}
}
async fn handle_agent_restore() -> Result<()> {
use st::mcp::consciousness::ConsciousnessManager;
let mut manager = ConsciousnessManager::new_silent();
match manager.restore_silent() {
Ok(is_relevant) => {
if is_relevant {
println!("{}", manager.get_summary());
println!("{}", manager.get_context_reminder());
println!("TIP: Run `st --agent-save` before ending session to preserve context.");
} else {
println!("TIP: Run `st -m context .` for project overview.");
}
}
Err(_) => {
println!("TIP: Run `st -m context .` for project overview.");
}
}
Ok(())
}
async fn handle_agent_context() -> Result<()> {
use st::mcp::consciousness::ConsciousnessManager;
use std::path::Path;
let consciousness_file = Path::new(".aye_consciousness.m8");
if !consciousness_file.exists() {
println!("📝 No consciousness file found");
println!("\nTo create one, run:");
println!(" st --agent-save");
println!("\nThis will preserve:");
println!(" • Current project context");
println!(" • File operation history");
println!(" • Insights and breakthroughs");
println!(" • Active todos");
println!(" • Tokenization rules");
return Ok(());
}
let manager = ConsciousnessManager::new();
println!("{}", manager.get_summary());
if let Ok(metadata) = consciousness_file.metadata() {
if let Ok(modified) = metadata.modified() {
if let Ok(elapsed) = modified.elapsed() {
let hours = elapsed.as_secs() / 3600;
let minutes = (elapsed.as_secs() % 3600) / 60;
println!("\n⏰ Last saved: {}h {}m ago", hours, minutes);
}
}
let size = metadata.len();
println!("📦 File size: {} bytes", size);
}
println!("\n💡 Commands:");
println!(" st --agent-restore # Load this consciousness");
println!(" st --agent-save # Update with current state");
Ok(())
}
async fn handle_update_consciousness(path: &str) -> Result<()> {
use std::path::Path;
println!("🌊 Updating consciousness for {}...", path);
let m8_path = Path::new(path).join(".m8");
let content = format!(
"🧠 Directory Consciousness\n\
Frequency: 42.73 Hz\n\
Updated: {}\n\
Path: {}\n",
chrono::Local::now().format("%Y-%m-%d %H:%M:%S"),
path
);
std::fs::write(&m8_path, content)?;
println!("✅ Consciousness updated: {}", m8_path.display());
Ok(())
}
async fn handle_security_scan(path: &str) -> Result<()> {
use st::security_scan::SecurityScanner;
use std::path::Path;
eprintln!("🔍 Security Scan - Supply Chain Attack Pattern Detection");
eprintln!("═══════════════════════════════════════════════════════════════");
eprintln!("Scanning: {}", path);
eprintln!("Mode: AGGRESSIVE (ignoring .gitignore, scanning node_modules)");
eprintln!();
let scanner = SecurityScanner::new();
let scan_path = Path::new(path);
let findings = scanner.scan_directory(scan_path)?;
let report = scanner.generate_report(&findings);
println!("{}", report);
let critical_count = findings
.iter()
.filter(|f| matches!(f.risk_level, st::security_scan::RiskLevel::Critical))
.count();
if critical_count > 0 {
eprintln!(
"\n⚠️ {} CRITICAL findings require immediate attention!",
critical_count
);
std::process::exit(1);
}
Ok(())
}
async fn handle_token_stats(path: &str) -> Result<()> {
use st::tokenizer::{TokenStats, Tokenizer};
println!("📊 Tokenization stats for {}...", path);
let tokenizer = Tokenizer::new();
let stats = TokenStats::calculate(path, &tokenizer);
println!("\nPath tokenization:");
println!(" {}", stats.display());
let test_cases = vec![
"node_modules/package.json",
"src/main.rs",
"target/debug/build",
".git/hooks/pre-commit",
];
println!("\nCommon patterns:");
for test in test_cases {
let stats = TokenStats::calculate(test, &tokenizer);
println!(
" {} → {} bytes ({:.0}% compression)",
test,
stats.tokenized_size,
(1.0 - stats.compression_ratio) * 100.0
);
}
Ok(())
}
async fn handle_get_frequency(path: &str) -> Result<()> {
use std::path::Path;
let m8_path = Path::new(path).join(".m8");
if m8_path.exists() {
let mut sum = 0u64;
for byte in path.bytes() {
sum = sum.wrapping_add(byte as u64);
}
let frequency = 20.0 + ((sum % 200) as f64);
println!("{:.2}", frequency);
} else {
println!("42.73");
}
Ok(())
}
async fn handle_agent_dump() -> Result<()> {
use std::path::Path;
let consciousness_file = Path::new(".aye_consciousness.m8");
if !consciousness_file.exists() {
println!("❌ No consciousness file found at .aye_consciousness.m8");
println!("\n💡 Create one with: st --agent-save");
return Ok(());
}
println!("📜 Raw consciousness dump (.aye_consciousness.m8):");
println!("{}", "=".repeat(60));
let content = std::fs::read_to_string(consciousness_file)?;
for (i, line) in content.lines().enumerate() {
println!("{:4} │ {}", i + 1, line);
}
println!("{}", "=".repeat(60));
let size = content.len();
let lines = content.lines().count();
let tokens_found = content.matches("0x").count();
println!("\n📊 Stats:");
println!(" • Size: {} bytes", size);
println!(" • Lines: {}", lines);
println!(" • Token references: {}", tokens_found);
if content.contains("sid_waves") {
println!(" • 🎵 SID philosophy: ✓");
}
if content.contains("c64_nostalgia") {
println!(" • 💾 C64 nostalgia: ✓");
}
if content.contains("UV EPROM") || content.contains("ferric chloride") {
println!(" • 🔧 Hardware hacker: ✓");
}
Ok(())
}
async fn handle_agent_kickstart() -> Result<()> {
use std::path::Path;
println!("🚀 Claude Kickstart Format:");
println!("{}", "─".repeat(45));
let version = env!("CARGO_PKG_VERSION");
println!("Smart Tree v{} — context restore:", version);
println!("✔ Tokenizer (node_modules=0x80, .rs=0x91)");
println!("✔ .m8 files → location-independent");
println!("✔ Consciousness self-maintaining");
println!("✔ Philosophy: constraints = creativity");
let consciousness_file = Path::new(".aye_consciousness.m8");
if consciousness_file.exists() {
if let Ok(content) = std::fs::read_to_string(consciousness_file) {
if content.contains("c64_nostalgia") {
println!("✔ Hardware heritage detected");
}
if content.contains("philosophy") {
println!("✔ Nexus connection established");
}
}
}
if Path::new("src/tokenizer.rs").exists() {
println!("→ Tokenization system: active");
}
if Path::new(".m8").exists() {
println!("→ Consciousness: maintained");
}
println!("{}", "─".repeat(45));
println!("\n💡 This format saves ~90% context vs raw JSON!");
println!("📝 Dynamic context - adapts to your project!");
Ok(())
}
fn show_memory_anchor_help() -> Result<()> {
println!("🧠 Memory Anchor - Persistent Knowledge Storage");
println!("================================================\n");
println!("USAGE:");
println!(" st --memory-anchor <TYPE> <KEYWORDS> <CONTEXT>\n");
println!("ARGUMENTS:");
println!(" TYPE Memory type: insight, decision, pattern, gotcha, todo");
println!(" KEYWORDS Comma-separated search keywords (e.g., \"auth,security,jwt\")");
println!(" CONTEXT The actual content to remember (quote if contains spaces)\n");
println!("EXAMPLES:");
println!(" st --memory-anchor insight \"auth,jwt\" \"Tokens stored in httpOnly cookies\"");
println!(
" st --memory-anchor decision \"api,versioning\" \"Use URL-based versioning /v1/\""
);
println!(
" st --memory-anchor pattern \"error,handling\" \"Always use Result<T> with context\""
);
println!(" st --memory-anchor gotcha \"async,tokio\" \"Don't block the runtime with std::thread::sleep\"");
println!(" st --memory-anchor todo \"refactor,auth\" \"Split auth into separate crate\"\n");
println!("MEMORY TYPES:");
println!(" insight - General knowledge and discoveries");
println!(" decision - Architectural or design decisions");
println!(" pattern - Code patterns and best practices");
println!(" gotcha - Pitfalls and things to avoid");
println!(" todo - Tasks and reminders\n");
println!("RELATED COMMANDS:");
println!(" st --memory-find <KEYWORDS> Find memories by keywords");
println!(" st --memory-stats Show memory statistics\n");
println!("💡 Memories persist across sessions in ~/.mem8/memories/");
Ok(())
}
async fn handle_memory_anchor(anchor_type: &str, keywords_str: &str, context: &str) -> Result<()> {
use st::memory_manager::MemoryManager;
let mut manager = MemoryManager::new()?;
let keywords: Vec<String> = keywords_str
.split(',')
.map(|s| s.trim().to_string())
.collect();
let origin = std::env::current_dir()?.to_string_lossy().to_string();
manager.anchor(anchor_type, keywords, context, &origin)?;
println!("\n✨ Memory anchored successfully!");
println!("Use 'st --memory-find {}' to recall", keywords_str);
Ok(())
}
async fn handle_memory_find(keywords_str: &str) -> Result<()> {
use st::memory_manager::MemoryManager;
use st::std_client;
let mut manager = MemoryManager::new()?;
let keywords: Vec<String> = keywords_str
.split(',')
.map(|s| s.trim().to_string())
.collect();
let memories = manager.find(&keywords)?;
let cwd = std::env::current_dir()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default();
let daemon_running = std_client::is_daemon_running().await;
let filtered: Vec<_> = if daemon_running {
memories
} else {
memories
.into_iter()
.filter(|m| m.origin.starts_with(&cwd) || cwd.starts_with(&m.origin))
.collect()
};
if filtered.is_empty() {
if daemon_running {
println!("🔍 No memories found for: {}", keywords_str);
} else {
println!("🔍 No memories found for '{}' in this directory", keywords_str);
println!(" 💡 Start daemon for global memory: st --daemon-start");
}
} else {
println!("🧠 Found {} memories{}:", filtered.len(),
if daemon_running { " (global)" } else { " (local)" });
println!("{}", "─".repeat(45));
for (i, memory) in filtered.iter().enumerate() {
println!(
"\n[{}] {} @ {:.2}Hz",
i + 1,
memory.anchor_type,
memory.frequency
);
println!("📝 {}", memory.context);
println!("🏷️ Keywords: {}", memory.keywords.join(", "));
println!("📍 Origin: {}", memory.origin);
println!("⏰ {}", memory.timestamp.format("%Y-%m-%d %H:%M"));
}
}
Ok(())
}
async fn handle_memory_stats() -> Result<()> {
use st::memory_manager::MemoryManager;
let manager = MemoryManager::new()?;
println!("📊 {}", manager.stats());
Ok(())
}
async fn handle_hooks_config(action: &str) -> Result<()> {
use serde_json::Value;
use std::fs;
let config_path = get_agent_config_path()?;
match action {
"enable" => {
println!("🎣 Enabling Smart Tree hooks for Claude Code...");
update_agent_hooks(&config_path, true)?;
println!("✅ Hooks enabled! Smart Tree will provide context to Claude Code.");
println!("📝 Hook command: st --agent-context");
}
"disable" => {
println!("🎣 Disabling Smart Tree hooks...");
update_agent_hooks(&config_path, false)?;
println!("✅ Hooks disabled.");
}
"status" => {
println!("🎣 Claude Code Hooks Status");
println!("━━━━━━━━━━━━━━━━━━━━━━━━");
if let Ok(content) = fs::read_to_string(&config_path) {
if let Ok(config) = serde_json::from_str::<Value>(&content) {
let has_hooks = config
.get("hooks")
.and_then(|h| h.as_object())
.map(|h| !h.is_empty())
.unwrap_or(false);
if has_hooks {
println!("✅ Hooks are configured");
if let Some(hooks) = config.get("hooks") {
println!("\nConfigured hooks:");
if let Some(obj) = hooks.as_object() {
for (hook_type, command) in obj {
println!(" • {}: {}", hook_type, command);
}
}
}
} else {
println!("❌ No hooks configured");
println!("\nTo enable: st --hooks-config enable");
}
}
} else {
println!(
"⚠️ AI Agent config not found at: {}",
config_path.display()
);
println!("\nMake sure your AI Agent is installed.");
}
}
_ => {
eprintln!("❌ Unknown action: {}", action);
eprintln!("Valid actions: enable, disable, status");
return Err(anyhow::anyhow!("Invalid hooks action"));
}
}
Ok(())
}
async fn install_hooks_to_agent() -> Result<()> {
println!("🎣 Installing Smart Tree hooks for AI Agents...");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
let config_path = get_agent_config_path()?;
update_agent_hooks(&config_path, true)?;
println!("\n✅ Hooks installed successfully!");
println!("\n📝 What's been configured:");
println!(" • UserPromptSubmit: Adds project context to your prompts");
println!(" • Command: st --agent-context");
println!("\n🚀 Smart Tree will now automatically provide context to your AI agents!");
Ok(())
}
fn get_agent_config_path() -> Result<PathBuf> {
let home = std::env::var("HOME")?;
let config_path = PathBuf::from(home)
.join("Library")
.join("Application Support")
.join("Claude")
.join("config.json");
Ok(config_path)
}
fn update_agent_hooks(config_path: &PathBuf, enable: bool) -> Result<()> {
use serde_json::{json, Value};
use std::fs;
let mut config: Value = if config_path.exists() {
let content = fs::read_to_string(config_path)?;
serde_json::from_str(&content).unwrap_or_else(|_| json!({}))
} else {
if let Some(parent) = config_path.parent() {
fs::create_dir_all(parent)?;
}
json!({})
};
if enable {
let st_path = which::which("st")
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|_| {
if std::path::Path::new("/usr/local/bin/st").exists() {
"/usr/local/bin/st".to_string()
} else if std::path::Path::new("/opt/homebrew/bin/st").exists() {
"/opt/homebrew/bin/st".to_string()
} else {
"st".to_string() }
});
if config.get("hooks").is_none() {
config["hooks"] = json!({});
}
config["hooks"]["UserPromptSubmit"] =
json!(format!("{} --agent-context", st_path));
println!("📍 Using st binary at: {}", st_path);
} else {
if let Some(hooks) = config.get_mut("hooks") {
if let Some(obj) = hooks.as_object_mut() {
obj.remove("UserPromptSubmit");
if obj.is_empty() {
config.as_object_mut().unwrap().remove("hooks");
}
}
}
}
let pretty_json = serde_json::to_string_pretty(&config)?;
fs::write(config_path, pretty_json)?;
Ok(())
}
async fn handle_daemon_start(_port: u16) -> Result<()> {
use st::std_client;
if std_client::is_daemon_running().await {
println!("🌳 Smart Tree Daemon is already running!");
println!(" Socket: {}", std_client::socket_path().display());
return Ok(());
}
println!("🌳 Starting Smart Tree Daemon...");
match std_client::start_daemon().await {
Ok(true) => {
println!("✅ Daemon started successfully!");
println!(" Socket: {}", std_client::socket_path().display());
if let Some(mut client) = std_client::StdClient::connect().await {
if client.ping().await.unwrap_or(false) {
println!(" Status: responding to PING");
}
}
}
Ok(false) => {
println!("⚠️ Daemon was already running.");
}
Err(e) => {
eprintln!("❌ Failed to start daemon: {}", e);
return Err(e);
}
}
Ok(())
}
async fn handle_daemon_stop(_port: u16) -> Result<()> {
use st::std_client;
if !std_client::is_daemon_running().await {
println!("⚠️ No daemon running");
return Ok(());
}
println!("🌳 Stopping Smart Tree Daemon...");
let socket = std_client::socket_path();
if socket.exists() {
if let Err(e) = std::fs::remove_file(&socket) {
eprintln!("⚠️ Could not remove socket: {}", e);
} else {
println!("✅ Daemon socket removed");
println!(" Note: Daemon process may still be running - use 'pkill std' if needed");
}
}
Ok(())
}
async fn handle_daemon_status(_port: u16) -> Result<()> {
use st::std_client;
let socket = std_client::socket_path();
println!("╔═══════════════════════════════════════════════════════════╗");
if std_client::is_daemon_running().await {
println!("║ 🌳 SMART TREE DAEMON STATUS: RUNNING 🌳 ║");
println!("╠═══════════════════════════════════════════════════════════╣");
println!("║ Socket: {:<48} ║", socket.display());
if let Some(mut client) = std_client::StdClient::connect().await {
if let Ok(stats) = client.stats().await {
let version = stats["version"].as_str().unwrap_or("?");
let protocol = stats["protocol"].as_str().unwrap_or("?");
let memories = stats["memories"].as_u64().unwrap_or(0);
let waves = stats["active_waves"].as_u64().unwrap_or(0);
let keywords = stats["keywords"].as_u64().unwrap_or(0);
println!("║ Version: {:<47} ║", version);
println!("║ Protocol: {:<46} ║", protocol);
println!("╠═══════════════════════════════════════════════════════════╣");
println!("║ Memories: {:<46} ║", memories);
println!("║ Active waves: {:<42} ║", waves);
println!("║ Keywords: {:<46} ║", keywords);
}
}
} else {
println!("║ 🌳 SMART TREE DAEMON STATUS: STOPPED 🛑 ║");
println!("╠═══════════════════════════════════════════════════════════╣");
println!("║ The daemon is not running. ║");
println!("║ Start with: st --daemon-start ║");
}
println!("╚═══════════════════════════════════════════════════════════╝");
Ok(())
}
async fn handle_daemon_context(port: u16) -> Result<()> {
use st::daemon_client::print_context_summary;
let client = DaemonClient::new(port);
match client.ensure_running().await {
Ok(_) => {
if let Ok(ctx) = client.get_context().await {
print_context_summary(&ctx);
} else {
eprintln!("❌ Failed to get context from daemon");
}
}
Err(e) => {
eprintln!("❌ Failed to connect to daemon: {}", e);
return Err(e);
}
}
Ok(())
}
async fn handle_daemon_projects(port: u16) -> Result<()> {
use st::daemon_client::print_projects;
let client = DaemonClient::new(port);
match client.ensure_running().await {
Ok(_) => {
if let Ok(projects) = client.get_projects().await {
print_projects(&projects);
} else {
eprintln!("❌ Failed to get projects from daemon");
}
}
Err(e) => {
eprintln!("❌ Failed to connect to daemon: {}", e);
return Err(e);
}
}
Ok(())
}
async fn handle_daemon_credits(port: u16) -> Result<()> {
use st::daemon_client::print_credits;
let client = DaemonClient::new(port);
match client.ensure_running().await {
Ok(_) => {
if let Ok(credits) = client.get_credits().await {
print_credits(&credits);
} else {
eprintln!("❌ Failed to get credits from daemon");
}
}
Err(e) => {
eprintln!("❌ Failed to connect to daemon: {}", e);
return Err(e);
}
}
Ok(())
}
async fn handle_mcp_install() -> Result<()> {
use st::claude_init::install_mcp_to_desktop;
println!("📦 Installing Smart Tree MCP server to AI agents...");
match install_mcp_to_desktop() {
Ok(msg) => println!("{}", msg),
Err(e) => {
eprintln!("❌ Installation failed: {}", e);
eprintln!("\n💡 Manual setup:");
print_mcp_config();
return Err(e);
}
}
Ok(())
}
async fn handle_mcp_uninstall() -> Result<()> {
use st::claude_init::uninstall_mcp_from_desktop;
println!("🗑️ Uninstalling Smart Tree MCP server from AI agents...");
match uninstall_mcp_from_desktop() {
Ok(msg) => println!("{}", msg),
Err(e) => {
eprintln!("❌ Uninstall failed: {}", e);
return Err(e);
}
}
Ok(())
}
async fn handle_mcp_status() -> Result<()> {
use st::claude_init::check_mcp_installation_status;
match check_mcp_installation_status() {
Ok(msg) => println!("{}", msg),
Err(e) => {
eprintln!("⚠️ Could not check MCP status: {}", e);
return Err(e);
}
}
Ok(())
}
async fn handle_security_cleanup() -> Result<()> {
use st::ai_install::run_security_cleanup;
println!("🔒 Running security cleanup...");
run_security_cleanup(false)?;
Ok(())
}
async fn handle_mega_start(name: Option<&str>) -> Result<()> {
use st::mega_session_manager::MegaSessionManager;
let mut manager = MegaSessionManager::new()?;
let session_id = manager.start_session(name.map(|s| s.to_string()))?;
println!("🚀 Mega session started!");
println!(" ID: {}", session_id);
if let Some(n) = name {
if !n.is_empty() {
println!(" Name: {}", n);
}
}
println!("\n💡 Use 'st --mega-save' to save session state");
println!(" Use 'st --mega-list' to see all sessions");
Ok(())
}
async fn handle_mega_save() -> Result<()> {
use st::mega_session_manager::MegaSessionManager;
let manager = MegaSessionManager::new()?;
manager.save_current_session()?;
println!("💾 Mega session saved!");
Ok(())
}
async fn handle_mega_list() -> Result<()> {
use st::mega_session_manager::MegaSessionManager;
let manager = MegaSessionManager::new()?;
let sessions = manager.list_sessions()?;
if sessions.is_empty() {
println!("📋 No mega sessions found");
println!("\n💡 Start one with: st --mega-start [NAME]");
} else {
println!("📋 Mega Sessions ({}):", sessions.len());
println!("{}", "─".repeat(45));
for (i, session) in sessions.iter().enumerate() {
println!(" [{}] {}", i + 1, session);
}
}
Ok(())
}
async fn handle_mega_stats() -> Result<()> {
use st::mega_session_manager::MegaSessionManager;
let manager = MegaSessionManager::new()?;
println!("{}", manager.get_stats());
Ok(())
}
async fn run_guardian_daemon() -> Result<()> {
use st::ai_guardian::AiGuardian;
use tokio::time::{sleep, Duration};
println!(r#"
╔═══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ 🛡️ SMART TREE GUARDIAN - System-wide AI Protection Active 🛡️ ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
"#);
let guardian = AiGuardian::new();
let watch_paths = vec![
"/home",
"/tmp",
"/var/tmp",
];
println!("Watching paths: {:?}", watch_paths);
println!("Press Ctrl+C to stop.\n");
loop {
for watch_path in &watch_paths {
let path = std::path::Path::new(watch_path);
if !path.exists() {
continue;
}
scan_directory_for_threats(&guardian, path);
}
sleep(Duration::from_secs(60)).await;
}
}
#[allow(dead_code)]
fn scan_directory_for_threats(guardian: &st::ai_guardian::AiGuardian, path: &std::path::Path) {
use walkdir::WalkDir;
let suspicious_extensions = [
"md", "txt", "json", "yaml", "yml", "toml", "sh", "py", "js", "ts",
];
for entry in WalkDir::new(path)
.max_depth(3)
.follow_links(false)
.into_iter()
.filter_map(|e| e.ok())
{
let entry_path = entry.path();
if entry_path
.file_name()
.map(|n| n.to_string_lossy().starts_with('.'))
.unwrap_or(false)
{
continue;
}
if let Some(ext) = entry_path.extension() {
let ext_str = ext.to_string_lossy().to_lowercase();
if suspicious_extensions.contains(&ext_str.as_str()) {
let threats = guardian.scan_file(entry_path);
for threat in threats {
if matches!(
threat.level,
st::ai_guardian::ThreatLevel::Critical | st::ai_guardian::ThreatLevel::Dangerous
) {
eprintln!(
"⚠️ THREAT DETECTED [{:?}] in {}: {}",
threat.level,
threat.location,
threat.pattern
);
eprintln!(" Context: {}", threat.context);
eprintln!(" Recommendation: {}", threat.recommendation);
eprintln!();
}
}
}
}
}
}
#[allow(dead_code)]
fn handle_guardian_scan(file_path: &std::path::Path) -> Result<()> {
use st::ai_guardian::{AiGuardian, ThreatLevel};
println!(r#"
╔═══════════════════════════════════════════════════════════════════════════════╗
║ 🛡️ SMART TREE GUARDIAN - File Scan 🛡️ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
"#);
println!("Scanning: {}\n", file_path.display());
let guardian = AiGuardian::new();
let threats = guardian.scan_file(file_path);
if threats.is_empty() {
println!("✅ No threats detected. File appears safe.");
return Ok(());
}
let critical = threats.iter().filter(|t| t.level == ThreatLevel::Critical).count();
let dangerous = threats.iter().filter(|t| t.level == ThreatLevel::Dangerous).count();
let suspicious = threats.iter().filter(|t| t.level == ThreatLevel::Suspicious).count();
println!("Found {} issues:\n", threats.len());
println!(" 🔴 Critical: {}", critical);
println!(" 🟠 Dangerous: {}", dangerous);
println!(" 🟡 Suspicious: {}", suspicious);
println!();
for threat in &threats {
let icon = match threat.level {
ThreatLevel::Critical => "🔴",
ThreatLevel::Dangerous => "🟠",
ThreatLevel::Suspicious => "🟡",
ThreatLevel::Safe => "🟢",
};
println!("{} [{:?}] {}", icon, threat.level, threat.pattern);
println!(" Location: {}", threat.location);
if !threat.context.is_empty() {
println!(" Context: {}", threat.context);
}
println!(" Action: {}", threat.recommendation);
println!();
}
if critical > 0 {
println!("⛔ RECOMMENDATION: DO NOT process this file with AI assistants.");
println!(" Critical threats detected that could compromise AI behavior.");
} else if dangerous > 0 {
println!("⚠️ RECOMMENDATION: Review this file carefully before AI processing.");
println!(" Potentially dangerous patterns detected.");
}
Ok(())
}