DashMap::clone() deep-copies all entries into a new map. The MCP
server's cloned SshService/SftpService/RdpService/ScrollbackRegistry
were snapshots from startup that never saw new sessions.
Fix: wrap all DashMap fields in Arc<DashMap<...>> so clones share
the same underlying map. Sessions added after MCP startup are now
visible to MCP tools.
Affected: SshService, SftpService, RdpService, ScrollbackRegistry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MCP: RdpService had a manual Clone impl that called unreachable!().
Replaced with a real clone that shares the DashMap. MCP server can
now clone all services and start successfully.
RDP: rustls needs CryptoProvider::install_default() before any TLS
operations. ironrdp-tls uses rustls for the RDP TLS handshake.
Added aws_lc_rs provider installation at app startup.
Both panics found via wraith.log debug logging from v1.6.3.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
RDP: wrapped connection thread in catch_unwind so panics are logged
to wraith.log instead of silently killing the channel. Error message
now directs user to check the log.
CWD: changed cd . to cd ~ after OSC 7 hook injection so SFTP starts
at the user's home directory on macOS (where / requires explicit nav).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Auto-inject CLAUDE_MCP_SERVERS env var when copilot PTY spawns,
so Claude Code auto-discovers wraith-mcp-bridge without manual config
- RDP screenshot_png_base64() encodes frame buffer as PNG via png crate
- Bridge binary exposes terminal_screenshot tool returning MCP image
content (base64 PNG with mimeType) for multimodal AI analysis
- MCP session list now includes RDP sessions with dimensions
- /mcp/screenshot HTTP endpoint on the internal server
"Screenshot that RDP session, what's the error?" now works.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: The output reader loop held Arc<TokioMutex<Channel>> while
calling ch.wait().await. After the initial prompt rendered and the server
went idle, wait() blocked indefinitely holding the lock. ssh_write()
could never acquire the mutex to send keystrokes. Permanent deadlock.
Fix: Separated read/write paths. The output loop now owns the Channel
exclusively via tokio::select!, receiving resize/shutdown commands through
an mpsc channel. Writes go through Handle::data(channel_id, data) which
bypasses the Channel entirely — no shared mutex, no deadlock.
Also killed all compiler warnings (unused imports in rdp module).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Clipboard paste (rdp_send_clipboard): simulates typing each character
via scancode key press/release events. Full ASCII coverage including
all symbols, numbers, and shifted characters. Handles 32-char
generated passwords without manual typing.
2. Keyboard grab defaults to ON so RDP sessions accept keyboard input
immediately without requiring the user to click the toolbar toggle.
3. Frame dirty flag: GraphicsUpdate sets an AtomicBool, get_frame only
encodes + returns base64 when dirty (returns empty string otherwise).
Eliminates ~8MB/frame base64 encoding on unchanged frames at 30fps.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove redundant doc comments and section headers across SSH, RDP, and command modules
- Add 10s timeout on SSH connect/auth, 15s timeout on RDP connection
- Fix macOS data directory to use ~/Library/Application Support/Wraith
- Add generic disconnect_session command alongside disconnect_ssh
- Simplify SFTP setup and RDP error handling
- Add explicit label/url to main window config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rust RDP service: ironrdp client with full connection handshake
(TCP -> TLS -> CredSSP -> NLA), pixel buffer frame delivery,
mouse/keyboard input via scancode mapping, graceful disconnect.
Runs in dedicated thread with own tokio runtime to avoid Send
lifetime issues with ironrdp trait objects.
Vue frontend: RdpView canvas renderer with 30fps polling,
mouse/keyboard capture, RdpToolbar with Ctrl+Alt+Del and
clipboard. SessionContainer handles both SSH and RDP tabs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>