Commit Graph

75 Commits

Author SHA1 Message Date
Vantz Stockwell
da2dd5bbfc fix: SEC-3/CONC-1/2/3 vault zeroize + async mutex + cancellation tokens
- Vault key uses Zeroizing<[u8; 32]>, passwords zeroized after use
- vault/credentials Mutex upgraded to tokio::sync::Mutex
- CWD tracker + monitor use CancellationToken for clean shutdown
- Monitor exec_command has 10s timeout, 3-strike dead connection heuristic

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:40:10 -04:00
Vantz Stockwell
1b7b1a0051 fix: rdp_type now actually types — clipboard + Ctrl+V keystroke sim
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m44s
Was only setting the remote clipboard without pasting. Now sends
clipboard content then simulates Ctrl+V (scancode 0x001D + 0x002F)
with 50ms delay for clipboard propagation. Works for any text
including special characters and multi-line content.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:06:47 -04:00
Vantz Stockwell
f578c434df feat: 31 MCP tools — ssh_connect for autonomous AI operation
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m12s
The AI can now open its own SSH sessions without the Commander
pre-opening them:

- ssh_connect(hostname, username, password?, private_key_path?, port?)
  Returns session_id for use with all other tools
  Supports password auth and SSH key file auth

Also added app_handle and error_watcher to MCP server state so
new sessions get full scrollback, monitoring, and CWD tracking.

This completes the autonomy loop: the AI discovers what's available
(list_sessions), connects to what it needs (ssh_connect), operates
(terminal_execute, docker_ps, sftp_read), and disconnects when done.

Total MCP tools: 31.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:04:53 -04:00
Vantz Stockwell
5aaedbe4a5 feat: 30 MCP tools — RDP click, type, clipboard interaction
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m5s
3 new MCP tools completing the RDP interaction loop:

- rdp_click — click at x,y coordinates (left/right/middle button)
  Use terminal_screenshot first to identify coordinates
- rdp_type — type text into RDP session via clipboard paste
- rdp_clipboard — set clipboard content on remote desktop

The AI can now screenshot an RDP session, analyze it visually,
click buttons, type text, and read clipboard content. Full GUI
automation through the MCP bridge.

Total MCP tools: 30.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 17:01:22 -04:00
Vantz Stockwell
3c2dc435ff feat: 27 MCP tools — Docker, Git, service, process management
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m3s
8 new MCP tools exposed through the bridge:

Docker:
- docker_ps — list all containers with status/image/ports
- docker_action — start/stop/restart/remove/logs/builder-prune/system-prune
- docker_exec — execute command inside a running container

System:
- service_status — check systemd service status
- process_list — ps aux with optional name filter

Git (remote repos):
- git_status — branch, dirty files, ahead/behind
- git_pull — pull latest changes
- git_log — recent 20 commits

Total MCP tools: 27. All accessible through the wraith-mcp-bridge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:56:10 -04:00
Vantz Stockwell
661490e925 perf: RDP event-driven frames + MCP terminal \r fix
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m28s
RDP performance overhaul:
- Switched from polling (rAF loop calling rdp_get_frame every tick)
  to event-driven rendering (backend emits rdp:frame:{id} when
  frame buffer updates, frontend fetches on demand)
- Eliminates thousands of empty IPC round-trips per second when
  the screen is idle
- Backend passes AppHandle into run_active_session for event emission
- Frontend uses listen() instead of requestAnimationFrame polling

MCP terminal fix:
- terminal_type and terminal_execute now send \r (carriage return)
  instead of \n (newline) — PTY terminals expect CR to submit
- Fixes commands not auto-sending, requiring manual Enter press

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:44:53 -04:00
Vantz Stockwell
d78cafba93 feat: terminal_type MCP tool + tab resize fix + close confirmation
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m54s
terminal_type MCP tool (19 tools total):
- Fire-and-forget text input to any session
- Optional press_enter flag (default: true)
- No marker wrapping, no output capture
- Use case: AI sends messages/commands without needing output back

Tab resize fix:
- Double requestAnimationFrame before fitAddon.fit() on tab switch
- Container has real dimensions after browser layout pass
- Also sends ssh_resize/pty_resize to backend with correct cols/rows
- Fixes 6-8 char wide terminals after switching tabs

Close confirmation:
- beforeunload event shows browser "Leave page?" dialog
- Only triggers if sessions are active
- Synchronous — cannot hang the close like onCloseRequested did

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 16:21:53 -04:00
Vantz Stockwell
037c76384b feat: migrate all artifacts to SeaweedFS — single source of truth
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m59s
All build artifacts now upload to files.command.vigilcyber.com/wraith/:
- Installer: /wraith/{ver}/Wraith_{ver}_x64-setup.exe + /wraith/latest/
- MCP bridge: /wraith/{ver}/wraith-mcp-bridge.exe + /wraith/latest/
- Update bundle: /wraith/{ver}/*.nsis.zip
- Update manifest: /wraith/update.json (Tauri updater endpoint)
- Version metadata: /wraith/{ver}/version.json + /wraith/latest/

Removed: Gitea package uploads, Gitea release creation/attachment.
Updated: tauri.conf.json updater endpoint, bridge auto-download URL,
manual update checker download URL.

CI is now: build -> sign -> upload to SeaweedFS. Done.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 15:52:10 -04:00
Vantz Stockwell
9f6085d251 perf: RDP optimizations — binary IPC, frame throttle, fast PNG
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 4m8s
1. Binary IPC: get_frame returns Vec<u8> directly instead of base64
   string. Eliminates 33% encoding overhead + string allocation +
   atob() decode on frontend. Frontend receives number[] from Tauri.

2. Frame throttle: reduced from ~30fps to ~20fps (every 3rd rAF tick).
   20% fewer frames with negligible visual difference for remote desktop.

3. Fast PNG compression: screenshot_png_base64 uses Compression::Fast
   for MCP screenshots, reducing encode time.

4. Dirty flag: already existed but documented — empty Vec returned when
   frame hasn't changed, frontend skips rendering.

Net effect: ~45% reduction in IPC bandwidth (no base64 overhead) +
20% fewer frame fetches + faster screenshot encoding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:54:25 -04:00
Vantz Stockwell
58df4ac5c8 fix: MCP sees live sessions — wrap DashMap in Arc for shared state
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>
2026-03-26 14:28:13 -04:00
Vantz Stockwell
9c3afa39bd feat: Help menu + fix tab detach rendering
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m48s
Help menu (File → Help):
- Getting Started guide (connections, SFTP, copilot, tabs)
- Keyboard Shortcuts reference table
- MCP Integration page (setup command, all 18 tools documented,
  bridge path auto-populated, architecture explanation)
- About page with version and tech stack
- Opens as a tabbed popup window

Tab detach fixes:
- Added detached-*, editor-*, help-* to capabilities window list
  (detached windows had no event permissions — silent failure)
- SessionContainer filters out detached sessions (active=false)
  so the main window stops rendering the terminal when detached
- Terminal now only renders in the detached popup window

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 14:07:45 -04:00
Vantz Stockwell
f22f85ac00 feat: MCP bridge auto-download — Wraith manages its own companion binary
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m53s
On startup, Wraith checks if wraith-mcp-bridge exists in the data
directory. If missing or version mismatch, downloads the correct
version from Gitea packages automatically. No installer changes needed.

Flow:
1. Check data_dir/wraith-mcp-bridge.exe exists
2. Check data_dir/mcp-bridge-version matches app version
3. If not, download from packages/vstockwell/generic/wraith/{ver}/
4. Set execute permissions on Unix
5. Write version marker

Also exposes mcp_bridge_path command so the frontend can show the
path in settings for users to add to PATH or configure Claude Code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:58:34 -04:00
Vantz Stockwell
d98600a319 fix: MCP bridge built, signed, and shipped in CI releases
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 3m39s
- Removed useless CLAUDE_MCP_SERVERS env var injection (doesn't work)
- CI builds wraith-mcp-bridge.exe as a separate cargo --bin step
- Bridge binary signed with EV cert alongside the installer
- Uploaded to Gitea packages per version
- Attached to Gitea release as a downloadable asset
- Users add to PATH then: claude mcp add wraith -- wraith-mcp-bridge

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:55:17 -04:00
Vantz Stockwell
0c6a4b8109 feat: Tauri auto-updater + RDP vault credentials + sidebar persist
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 2m55s
Tauri auto-updater:
- Signing pubkey in tauri.conf.json
- tauri-plugin-updater initialized in lib.rs
- CI workflow passes TAURI_SIGNING_PRIVATE_KEY env vars to cargo tauri build
- CI generates update.json manifest with signature and uploads to
  packages/latest/update.json endpoint
- Frontend checks for updates on startup via @tauri-apps/plugin-updater
- Downloads, installs, and relaunches seamlessly
- Settings → About button uses native updater too

RDP vault credentials:
- RDP connections now resolve credentials from vault via credentialId
- Same path as SSH: list_credentials → find by ID → decrypt_password
- Falls back to conn.options JSON if no vault credential linked
- Fixes blank username in RDP connect

Sidebar drag persist:
- reorder_connections and reorder_groups Tauri commands
- Batch-update sort_order in database on drop
- Order survives app restart

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:42:01 -04:00
Vantz Stockwell
7c2ab2aa60 fix: error watcher crash — tokio::spawn without runtime context
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m4s
Same root cause as the PTY crash (v1.2.6): tokio::spawn called from
Tauri setup hook without a tokio runtime guard. Switched error watcher
to std:🧵:spawn. Also wrapped both error watcher and MCP server
spawn in individual catch_unwind blocks so neither can crash the app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 12:16:50 -04:00
Vantz Stockwell
1b74527a62 feat: tab notifications, session persistence, Docker panel, drag reorder sidebar
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m53s
Tab activity notifications:
- Background tabs pulse blue when new output arrives
- Clears when you switch to the tab
- useTerminal marks activity on every data event

Session persistence:
- Workspace saved to DB on window close (connection IDs + positions)
- Restored on launch — auto-reconnects saved sessions in order
- workspace_commands: save_workspace, load_workspace

Docker Manager (Tools → Docker Manager):
- Containers tab: list all, start/stop/restart/remove/logs
- Images tab: list all, remove
- Volumes tab: list all, remove
- One-click Builder Prune and System Prune buttons
- All operations via SSH exec channels — no Docker socket exposure

Sidebar drag-and-drop:
- Drag groups to reorder
- Drag connections between groups
- Drag connections within a group to reorder
- Blue border indicator on drop targets

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:50:49 -04:00
Vantz Stockwell
e6766062b1 fix: MCP startup panic + RDP crypto provider panic
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m57s
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>
2026-03-25 11:28:46 -04:00
Vantz Stockwell
357491b4e8 feat: debug logging macro + MCP tools inject button in copilot
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>
2026-03-25 11:12:23 -04:00
Vantz Stockwell
5d1aeb5fe3 fix: log actual panic message when MCP startup fails
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m54s
Was logging "panicked — continuing" without the WHY. Now captures
the panic payload (String, &str, or type_id) so the log shows
exactly what went wrong in clone_services().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:06:06 -04:00
Vantz Stockwell
03bb6f3ccf fix: RDP panic logging + CWD starts at home directory
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m16s
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>
2026-03-25 11:02:30 -04:00
Vantz Stockwell
83b746df0e fix: OSC 7 hook quoting — remove extra escaped quotes around pwd
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m59s
The printf argument had escaped quotes that passed through literally,
producing paths like /"/Users/foo". Removed the outer escaped quotes
— printf %s handles the command substitution directly. Also simplified
PROMPT_COMMAND assignment to avoid quote nesting issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:42:56 -04:00
Vantz Stockwell
c1f8d2a14d fix: read version from tauri.conf.json, not CARGO_PKG_VERSION
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
CARGO_PKG_VERSION is always 0.1.0 (hardcoded in Cargo.toml). CI
patches tauri.conf.json from the git tag. Now reads app_handle.config()
for the real version so the update checker compares correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:42:20 -04:00
Vantz Stockwell
4b26d9190b feat: update checker — startup prompt + Settings → About button
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m2s
Checks Gitea releases API for latest version on startup. If newer
version available, shows confirm dialog to open download page.

Also adds "Check for Updates" button in Settings → About with
version comparison, release notes display, and download button.

Backend: check_for_updates command with semver comparison (6 tests).
96 total tests, zero warnings.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:35:54 -04:00
Vantz Stockwell
e9b504c733 fix: SFTP browser — default to / instead of /home, strip quotes from CWD
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m0s
/home doesn't exist on macOS (home dirs are /Users/). Changed default
SFTP path to / so it always loads. OSC 7 parser now strips stray
quotes from shell printf output that produced paths like /"/path".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:29:38 -04:00
Vantz Stockwell
8565f11c11 fix: more portable OSC 7 hook — BEL terminator, %20 space encoding
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 7s
Switched to printf '\e]7;file://localhost/%s\a' with sed space encoding.
BEL (\a) terminator is more universally supported than ST (\e\\).
Shared __wraith_osc7 function avoids duplicating the printf across
bash/zsh branches.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:20:06 -04:00
Vantz Stockwell
0251614732 fix: trigger initial CWD emission with cd . after OSC 7 hook inject
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 6s
precmd/PROMPT_COMMAND only fire after a command runs. Without cd .
the first OSC 7 never emits and SFTP doesn't know the initial directory.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:18:35 -04:00
Vantz Stockwell
0bcf59865d fix: hide OSC 7 hook injection from terminal output
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 6s
The CWD hook command was visible to the user. Now wrapped in
stty -echo/echo to suppress echo, followed by clear to wipe the
screen. Space prefix prevents history recording in most shells.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 01:16:20 -04:00
Vantz Stockwell
3e548ed10e feat: SFTP editor opens as popup window instead of inline overlay
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 6s
Right-click → Edit now opens a separate Tauri window with the file
content in a monospace editor. Ctrl+S saves back to remote via SFTP.
Tab inserts 4 spaces. Modified indicator in toolbar.

Removed the inline EditorWindow overlay that covered the terminal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:58:09 -04:00
Vantz Stockwell
016906fc9d fix: add window/webview creation permissions for tool popup windows
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
Tauri v2 ACL requires explicit permissions to create windows from the
frontend. Added core🪟allow-create and
core:webview:allow-create-webview-window so the Tools menu can open
popup windows.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:56:34 -04:00
Vantz Stockwell
0e88f9f07c feat: file-based logging to wraith.log for MCP startup diagnostics
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
env_logger was never initialized so log::info/error went nowhere.
Added write_log() that appends to data_dir/wraith.log with timestamps.
Logs MCP server startup success/failure and any panics.

Check: %APPDATA%\Wraith\wraith.log (Windows)
       ~/Library/Application Support/Wraith/wraith.log (macOS)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:55:31 -04:00
Vantz Stockwell
44c79decf3 fix: SFTP preserves position on tab switch + CWD following on macOS
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m58s
SFTP tab switch fix:
- Removed :key on FileTree that destroyed component on every switch
- useSftp now accepts a reactive Ref<string> sessionId
- Watches sessionId changes and reinitializes without destroying state
- Per-session path memory via sessionPaths map — switching back to a
  tab restores exactly where you were browsing

CWD following fix (macOS + all platforms):
- Injects OSC 7 prompt hook into the shell after SSH connect
- zsh: precmd() emits \e]7;file://host/path\e\\
- bash: PROMPT_COMMAND emits the same sequence
- Sent via the PTY channel so it configures the interactive shell
- The passive OSC 7 parser in the output loop picks it up
- SFTP sidebar auto-navigates to the current working directory

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:41:50 -04:00
Vantz Stockwell
c507c515ef fix: wrap MCP/error watcher startup in catch_unwind — never crash app
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m1s
The MCP server and error watcher are nice-to-have services that were
crashing the app on startup. Wrapped in catch_unwind + error handling
so a failure in these subsystems logs an error instead of taking down
the entire application.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:30:49 -04:00
Vantz Stockwell
15055aeb01 feat: all 18 tools exposed as MCP tools for AI copilot
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 6s
Every tool in Wraith is now callable by the AI through MCP:

| MCP Tool          | AI Use Case                              |
|-------------------|------------------------------------------|
| network_scan      | "What devices are on this subnet?"       |
| port_scan         | "Which servers have SSH open?"           |
| ping              | "Is this host responding?"               |
| traceroute        | "Show me the route to this server"       |
| dns_lookup        | "What's the MX record for this domain?"  |
| whois             | "Who owns this IP?"                      |
| wake_on_lan       | "Wake up the backup server"              |
| bandwidth_test    | "How fast is this server's internet?"    |
| subnet_calc       | "How many hosts in a /22?"               |
| generate_ssh_key  | "Generate an ed25519 key pair"           |
| generate_password | "Generate a 32-char password"            |
| terminal_read     | "What's on screen right now?"            |
| terminal_execute  | "Run df -h on this server"               |
| terminal_screenshot| "What's that RDP error?"                |
| sftp_list/read/write| "Read the nginx config"               |
| list_sessions     | "What sessions are active?"              |

11 new HTTP endpoints on the MCP server. 11 new tool definitions
in the bridge binary. The AI doesn't just chat — it scans, discovers,
analyzes, and connects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:15:08 -04:00
Vantz Stockwell
b3f56a2729 feat: Tools R2 — DNS, Whois, Bandwidth, Subnet Calculator
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 7s
4 new tools with full backend + popup UIs:

DNS Lookup:
- dig/nslookup/host fallback chain on remote host
- Record type selector (A, AAAA, MX, NS, TXT, CNAME, SOA, SRV, PTR)

Whois:
- Remote whois query, first 80 lines
- Works for domains and IP addresses

Bandwidth Test (2 modes):
- iperf3: LAN speed test between remote host and iperf server
- Internet: speedtest-cli / curl-based Cloudflare test fallback

Subnet Calculator:
- Pure Rust, no SSH needed
- CIDR input with quick-select buttons (/8 through /32)
- Displays: network, broadcast, netmask, wildcard, host range,
  total/usable hosts, class, private/public

Tools menu now has 11 items across 3 sections.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:12:11 -04:00
Vantz Stockwell
875dd1a28f feat: complete Tools suite — 7 tool UIs in popup windows
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 6s
All 7 tool windows with full UIs:
- Network Scanner: subnet scan, ARP+DNS discovery, results table with
  Quick Scan per host, SSH/RDP connect buttons, CSV export
- Port Scanner: custom range or quick scan (24 common ports), open/closed
  results table with service names
- Ping: remote ping with count, raw output display
- Traceroute: remote traceroute, raw output display
- Wake on LAN: MAC address input, broadcasts via python3 on remote host
- SSH Key Generator: ed25519/RSA, copy public/private key, fingerprint
- Password Generator: configurable length/charset, copy button, history

Architecture:
- App.vue detects tool mode via URL hash (#/tool/name?sessionId=...)
- ToolWindow.vue routes to correct tool component
- Tools menu in toolbar opens Tauri popup windows (WebviewWindow)
- Capabilities grant tool-* windows the same permissions as main
- SFTP context menu: right-click Edit/Download/Rename/Delete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:07:15 -04:00
Vantz Stockwell
5cc412a251 feat: Tools menu + backend commands for all tools
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m2s
Tools menu in toolbar (next to File) with 7 tools:
- Network Scanner (existing scan_network command)
- Port Scanner (existing scan_ports/quick_scan commands)
- Ping — via SSH exec channel, cross-platform
- Traceroute — via SSH exec channel
- Wake on LAN — broadcasts WoL magic packet via python3 on remote host
- SSH Key Generator — pure Rust ed25519/RSA keygen via ssh-key crate
- Password Generator — cryptographic random with configurable charset

Backend: all 5 new Tauri commands (tool_ping, tool_traceroute,
tool_wake_on_lan, tool_generate_ssh_key, tool_generate_password)

Frontend: Tools dropdown menu wired, popup window launcher ready.
Tool window UIs (the actual panels inside each popup) to follow.

SFTP context menu: right-click Edit/Download/Rename/Delete working.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 00:03:34 -04:00
Vantz Stockwell
2d0964f6b2 feat: network scanner + SFTP context menu + CI fix
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m7s
Network scanner (through SSH exec channels):
- scan_network: ping sweep + ARP table + reverse DNS on remote network
- scan_ports: TCP connect scan via bash /dev/tcp (parallel batches of 20)
- quick_scan: 24 common ports (SSH, HTTP, RDP, SMB, DB, etc.)
- Cross-platform: Linux + macOS
- No agent/nmap required — uses standard POSIX commands
- All scans run on the remote host through existing SSH tunnel

SFTP context menu:
- Right-click on files/folders shows Edit, Download, Rename, Delete
- Right-click on folders shows Open Folder
- Teleport menu to body for proper z-index layering
- Click-away handler to close menu
- Rename uses sftp_rename invoke

CI fix:
- Added default-run = "wraith" to Cargo.toml
- The [[bin]] entry for wraith-mcp-bridge confused Cargo about which
  binary is the Tauri app main binary

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 23:56:42 -04:00
Vantz Stockwell
4532f3beb6 feat: local terminal tabs — + button spawns WSL/Git Bash/PowerShell/CMD
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 16s
The + button in the tab bar now shows a dropdown of detected local
shells. Clicking one opens a full-size PTY terminal in the main
content area as a proper tab — not the copilot sidebar.

- New "local" protocol type in Session interface
- LocalTerminalView component uses useTerminal(id, 'pty')
- SessionContainer renders local sessions alongside SSH/RDP
- TabBadge shows purple dot for local sessions
- Shell detection includes WSL (wsl.exe) on Windows
- closeSession handles PTY disconnect for local tabs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 23:46:09 -04:00
Vantz Stockwell
2ad6da43eb feat: remote monitoring bar + SFTP tab follow + CWD macOS fix
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 15s
Remote monitoring bar:
- Slim 24px bar at bottom of every SSH terminal
- CPU, RAM, disk, network stats polled every 5s via exec channel
- Cross-platform: Linux (/proc), macOS (vm_stat/sysctl), FreeBSD
- Color-coded thresholds: green/amber/red
- No agent installation — standard POSIX commands only

SFTP follows active tab:
- Added :key="activeSessionId" to FileTree component
- Vue recreates FileTree when session changes, reinitializing SFTP

CWD tracking fix (macOS + all platforms):
- Old approach: exec channel pwd — returns HOME, not actual CWD
- New approach: passive OSC 7 parsing in the output stream
- Scans for \e]7;file://host/path\a without modifying data
- Works with bash, zsh, fish on both Linux and macOS
- Zero corruption risk — data passes through unmodified
- Includes URL percent-decoding for paths with spaces

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 23:38:01 -04:00
Vantz Stockwell
bc608b0683 feat: copilot QoL — resizable panel, SFTP tools, context, error watcher
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 15s
Resizable panel:
- Drag handle on left border of copilot panel
- Pointer events for smooth resize (320px–1200px range)

SFTP MCP tools:
- sftp_list: list remote directories
- sftp_read: read remote files
- sftp_write: write remote files
- Full HTTP endpoints + bridge tool definitions

Active session context:
- mcp_get_session_context command returns last 20 lines of scrollback
- Frontend can call on tab switch to keep AI informed

Error watcher:
- Background scanner runs every 2 seconds across all sessions
- 20+ error patterns (permission denied, OOM, segfault, disk full, etc.)
- Emits mcp:error events to frontend with session ID and matched line
- Sessions auto-registered with watcher on connect

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 23:30:12 -04:00
Vantz Stockwell
add0f0628f feat: MCP auto-inject + RDP screenshot tool
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 16s
- 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>
2026-03-24 23:17:36 -04:00
Vantz Stockwell
8276b0cc59 feat: MCP bridge binary + HTTP server + auto-config injection
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Failing after 16s
Complete MCP communication pipeline:

Backend HTTP server (axum on localhost:0):
- POST /mcp/sessions — list active sessions
- POST /mcp/terminal/read — read scrollback (ANSI stripped)
- POST /mcp/terminal/execute — send command + marker, capture output
- Port written to data_dir/mcp-port at startup
- Shares SshService and ScrollbackRegistry with AppState via Clone

Bridge binary (wraith-mcp-bridge):
- Speaks JSON-RPC 2.0 over stdio (MCP protocol)
- Translates tool calls to HTTP requests against running Wraith
- Implements initialize, tools/list, tools/call
- Exposes: terminal_read, terminal_execute, list_sessions
- Reads MCP port from data_dir/mcp-port

Auto-config:
- PTY spawn injects WRAITH_MCP_BRIDGE env var
- SshService and ScrollbackRegistry derive Clone for sharing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 23:10:09 -04:00
Vantz Stockwell
a3a7116f00 feat: MCP Phase 1 — scrollback buffer, terminal_read, terminal_execute
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m52s
Infrastructure for the Wraith Terminal MCP server:

- ScrollbackBuffer: 64KB circular buffer per session with ANSI stripping
- ScrollbackRegistry: DashMap registry shared between output loops and MCP
- SSH output loop feeds scrollback in addition to emitting events
- PTY output loop feeds scrollback in addition to emitting events
- mcp_terminal_read: read last N lines from any session (ANSI stripped)
- mcp_terminal_execute: send command + marker, capture output until marker
- mcp_list_sessions: enumerate all active SSH sessions with metadata

8 new scrollback tests (ring buffer, ANSI strip, line limiting).
95 total tests, zero warnings.

Bridge binary and auto-config injection to follow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 23:00:32 -04:00
Vantz Stockwell
8df59683d2 fix: disable Tauri file drop handler — unblocks HTML5 drag-and-drop
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m4s
Tauri's built-in dragDropEnabled intercepts all drag events in the
WebView for native file drop handling. This prevents HTML5 drag-and-drop
between elements within the page. Disabled so tab reordering works.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:48:46 -04:00
Vantz Stockwell
37c9b46a51 fix: PTY crash — use std:🧵:spawn instead of tokio::spawn_blocking
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 2m49s
tokio::task::spawn_blocking panics when called without a tokio runtime
context. Sync Tauri command handlers may not have one. The PTY reader
loop is long-lived anyway — std:🧵:spawn is more correct for
persistent blocking I/O and doesn't require a runtime guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:13:42 -04:00
Vantz Stockwell
512347af5f feat: Local PTY Copilot Panel — replace Gemini stub with real terminal
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m6s
Ripped out the Gemini API stub (ai/mod.rs, ai_commands.rs, GeminiPanel.vue)
and replaced it with a local PTY terminal in the sidebar panel. Users select
a shell (bash/zsh/sh on Unix, PowerShell/CMD/Git Bash on Windows), launch it,
and run claude/gemini/codex or any CLI tool directly.

Backend:
- New PtyService module using portable-pty (cross-platform PTY)
- DashMap session registry (same pattern as SshService)
- spawn_blocking output loop (portable-pty reader is synchronous)
- 5 Tauri commands: list_available_shells, spawn_local_shell, pty_write,
  pty_resize, disconnect_pty

Frontend:
- Parameterized useTerminal composable: backend='ssh'|'pty'
- convertEol=false for PTY (PTY driver handles LF→CRLF)
- CopilotPanel.vue with shell selector, launch/kill, session ended prompt
- Ctrl+Shift+G toggle preserved

Tests: 87 total (5 new PTY tests), zero warnings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:43:18 -04:00
Vantz Stockwell
eda36c937b fix: pure Rust EC key decryption — no openssl dependency
All checks were successful
Build & Sign Wraith / Build Windows + Sign (push) Successful in 3m3s
Replaced the openssl CLI fallback with pure Rust crypto for EC private
keys in SEC1 format (-----BEGIN EC PRIVATE KEY-----). Handles PKCS#5
encrypted keys (AES-128-CBC + MD5 EVP_BytesToKey KDF) and converts to
PKCS#8 PEM that russh can parse natively.

All crypto crates (md5, aes, cbc, sec1, pkcs8) were already in the dep
tree via russh — just promoted to direct dependencies. Zero new binary
dependencies, works on Windows without openssl installed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:08:55 -04:00
Vantz Stockwell
74b9be3046 fix: remove desktop shortcut from NSIS installer by default
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
Tauri's NSIS bundler creates a desktop shortcut unconditionally. Added
a POSTINSTALL hook that deletes it immediately after creation. Start
menu shortcut remains. Users who want a desktop shortcut can create
one manually.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 20:04:06 -04:00
Vantz Stockwell
4a0c2c9790 fix: SSH key auth — handle EC/DSA keys via openssl pkey fallback
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
russh only parses 4 PEM headers: OPENSSH, RSA, PKCS8, ENCRYPTED PKCS8.
EC keys (-----BEGIN EC PRIVATE KEY-----) with PKCS5 encryption silently
failed with "Could not read key".

Fix adds two fallbacks:
1. If russh can't parse the key, convert to PKCS8 via `openssl pkey`
   which handles EC, DSA, and all other OpenSSL-supported formats
2. If the input doesn't start with -----BEGIN, try reading it as a
   file path (supports ~ expansion) for keys stored on disk

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 19:18:01 -04:00
Vantz Stockwell
633087633e test: full test coverage — 82 tests across all modules, zero warnings
Added tests for 3 uncovered modules:
- db: open, migrate, idempotent migration, FK/WAL pragmas, clone shares conn
- theme: seed_builtins (7 themes), idempotent seed, get_by_name, hex color
  validation, sort ordering, case sensitivity
- rdp/input: scancode lookup, extended key detection, value extraction,
  mouse flag composition, map coverage assertion

Existing test count: 52 (vault, connections, credentials, settings, host_keys)
New tests added: 30
Total: 82 tests, all passing, zero compiler warnings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:33:36 -04:00