diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index e633c4f..ae73a24 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,3 +1,12 @@ +// Global debug log macro — must be declared before modules that use it +#[macro_export] +macro_rules! wraith_log { + ($($arg:tt)*) => {{ + let msg = format!($($arg)*); + let _ = $crate::write_log(&$crate::data_directory().join("wraith.log"), &msg); + }}; +} + pub mod db; pub mod vault; pub mod settings; diff --git a/src-tauri/src/pty/mod.rs b/src-tauri/src/pty/mod.rs index b7467a3..8341b9d 100644 --- a/src-tauri/src/pty/mod.rs +++ b/src-tauri/src/pty/mod.rs @@ -89,6 +89,7 @@ impl PtyService { scrollback: &ScrollbackRegistry, ) -> Result { let session_id = uuid::Uuid::new_v4().to_string(); + wraith_log!("[PTY] Spawning shell: {} (session {})", shell_path, session_id); let pty_system = native_pty_system(); let pair = pty_system diff --git a/src-tauri/src/rdp/mod.rs b/src-tauri/src/rdp/mod.rs index 11484b7..48c0b13 100644 --- a/src-tauri/src/rdp/mod.rs +++ b/src-tauri/src/rdp/mod.rs @@ -88,6 +88,7 @@ impl RdpService { pub fn connect(&self, config: RdpConfig) -> Result { let session_id = uuid::Uuid::new_v4().to_string(); + wraith_log!("[RDP] Connecting to {}:{} as {} (session {})", config.hostname, config.port, config.username, session_id); let width = config.width; let height = config.height; let hostname = config.hostname.clone(); diff --git a/src-tauri/src/ssh/session.rs b/src-tauri/src/ssh/session.rs index 5e1c29b..1edff66 100644 --- a/src-tauri/src/ssh/session.rs +++ b/src-tauri/src/ssh/session.rs @@ -87,6 +87,7 @@ impl SshService { pub async fn connect(&self, app_handle: AppHandle, hostname: &str, port: u16, username: &str, auth: AuthMethod, cols: u32, rows: u32, sftp_service: &SftpService, scrollback: &ScrollbackRegistry, error_watcher: &ErrorWatcher) -> Result { let session_id = uuid::Uuid::new_v4().to_string(); + wraith_log!("[SSH] Connecting to {}:{} as {} (session {})", hostname, port, username, session_id); let config = Arc::new(russh::client::Config::default()); let handler = SshClient { host_key_store: HostKeyStore::new(self.db.clone()), hostname: hostname.to_string(), port }; @@ -150,6 +151,8 @@ impl SshService { } } + wraith_log!("[SSH] Connected and authenticated: {}", session_id); + // Create scrollback buffer for MCP terminal_read let scrollback_buf = scrollback.create(&session_id); error_watcher.watch(&session_id); diff --git a/src/components/ai/CopilotPanel.vue b/src/components/ai/CopilotPanel.vue index 48a88bd..d6c7735 100644 --- a/src/components/ai/CopilotPanel.vue +++ b/src/components/ai/CopilotPanel.vue @@ -37,6 +37,14 @@ > Kill + @@ -226,6 +234,44 @@ async function launch(): Promise { } } +function injectTools(): void { + if (!sessionId || !connected.value) return; + const toolsPrompt = [ + "You have access to these Wraith MCP tools via the wraith-mcp-bridge:", + "", + "SESSION MANAGEMENT:", + " list_sessions — List all active SSH/RDP/PTY sessions", + "", + "TERMINAL:", + " terminal_read(session_id, lines?) — Read recent terminal output (ANSI stripped)", + " terminal_execute(session_id, command, timeout_ms?) — Run a command and capture output", + " terminal_screenshot(session_id) — Capture RDP session as PNG", + "", + "SFTP:", + " sftp_list(session_id, path) — List remote directory", + " sftp_read(session_id, path) — Read remote file", + " sftp_write(session_id, path, content) — Write remote file", + "", + "NETWORK:", + " network_scan(session_id, subnet) — Discover devices on subnet (ARP + ping sweep)", + " port_scan(session_id, target, ports?) — Scan TCP ports", + " ping(session_id, target) — Ping a host", + " traceroute(session_id, target) — Traceroute to host", + " dns_lookup(session_id, domain, record_type?) — DNS lookup", + " whois(session_id, target) — Whois lookup", + " wake_on_lan(session_id, mac_address) — Send WoL magic packet", + " bandwidth_test(session_id) — Internet speed test", + "", + "UTILITIES (no session needed):", + " subnet_calc(cidr) — Calculate subnet details", + " generate_ssh_key(key_type, comment?) — Generate SSH key pair", + " generate_password(length?, uppercase?, lowercase?, digits?, symbols?) — Generate password", + "", + ].join("\n"); + + invoke("pty_write", { sessionId, data: toolsPrompt + "\r" }).catch(() => {}); +} + function kill(): void { if (sessionId) { invoke("disconnect_pty", { sessionId }).catch(() => {});