feat: debug logging macro + MCP tools inject button in copilot
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m58s
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m58s
Debug logging: - wraith_log!() macro available in all modules, writes to wraith.log - SSH connect/auth, PTY spawn, RDP connect all log with session IDs - MCP startup panic now shows the actual error message Copilot "Tools" button: - Shows when a PTY session is active in the copilot panel - Injects a formatted list of all 18 MCP tools into the chat - Groups tools by category: session, terminal, SFTP, network, utilities - Includes parameter signatures so the AI knows how to call them Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5d1aeb5fe3
commit
357491b4e8
@ -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 db;
|
||||||
pub mod vault;
|
pub mod vault;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
|
|||||||
@ -89,6 +89,7 @@ impl PtyService {
|
|||||||
scrollback: &ScrollbackRegistry,
|
scrollback: &ScrollbackRegistry,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let session_id = uuid::Uuid::new_v4().to_string();
|
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 pty_system = native_pty_system();
|
||||||
|
|
||||||
let pair = pty_system
|
let pair = pty_system
|
||||||
|
|||||||
@ -88,6 +88,7 @@ impl RdpService {
|
|||||||
|
|
||||||
pub fn connect(&self, config: RdpConfig) -> Result<String, String> {
|
pub fn connect(&self, config: RdpConfig) -> Result<String, String> {
|
||||||
let session_id = uuid::Uuid::new_v4().to_string();
|
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 width = config.width;
|
||||||
let height = config.height;
|
let height = config.height;
|
||||||
let hostname = config.hostname.clone();
|
let hostname = config.hostname.clone();
|
||||||
|
|||||||
@ -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<String, String> {
|
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<String, String> {
|
||||||
let session_id = uuid::Uuid::new_v4().to_string();
|
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 config = Arc::new(russh::client::Config::default());
|
||||||
let handler = SshClient { host_key_store: HostKeyStore::new(self.db.clone()), hostname: hostname.to_string(), port };
|
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
|
// Create scrollback buffer for MCP terminal_read
|
||||||
let scrollback_buf = scrollback.create(&session_id);
|
let scrollback_buf = scrollback.create(&session_id);
|
||||||
error_watcher.watch(&session_id);
|
error_watcher.watch(&session_id);
|
||||||
|
|||||||
@ -37,6 +37,14 @@
|
|||||||
>
|
>
|
||||||
Kill
|
Kill
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="connected"
|
||||||
|
class="px-2 py-0.5 text-[10px] rounded border border-[var(--wraith-border)] text-[var(--wraith-text-muted)] hover:text-[var(--wraith-text-primary)] cursor-pointer"
|
||||||
|
title="Inject available MCP tools into the chat"
|
||||||
|
@click="injectTools"
|
||||||
|
>
|
||||||
|
Tools
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -226,6 +234,44 @@ async function launch(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
function kill(): void {
|
||||||
if (sessionId) {
|
if (sessionId) {
|
||||||
invoke("disconnect_pty", { sessionId }).catch(() => {});
|
invoke("disconnect_pty", { sessionId }).catch(() => {});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user