Cursor blinking (ACTUALLY fixed this time):
- handleFocus() was STILL missing due to botched duplicate removal in
v1.12.1. Now defined once at line 80, no duplicates.
- vue-tsc --noEmit now runs clean (was erroring with TS2393)
Tool windows:
- App.vue now has onErrorCaptured + error display overlay so tool window
crashes show the error instead of silently closing
- defineAsyncComponent uses object form with onError callback for logging
Selection highlighting:
- Changed from rgba(88,166,255,0.4) transparent to solid #264f78
(VS Code's selection color) — always visible on dark backgrounds
- Applied to default theme, TerminalView applyTheme, LocalTerminalView
CSP:
- Simplified to 'self' 'unsafe-inline' asset: for default-src
- Separate connect-src for IPC protocols
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cursor blinking:
- handleFocus() was referenced in TerminalView template but never
defined in script — clicking the terminal container threw a runtime
error preventing focus. Added the missing function.
- Removed duplicate handleFocus at end of file
Tool windows:
- CSP simplified for macOS WKWebView compatibility. Previous CSP
was blocking child WebviewWindow IPC initialization.
RDP tab switch:
- Added rdp_force_refresh command that marks frame_dirty=true and
clears dirty region, forcing next get_frame to return full buffer
- Called on tab activation and after resize completion
- Eliminates 4-5 second wait for "keyframe" when switching tabs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Popup windows (tools/editor/help):
- CSP broadened for macOS: added tauri: and https://tauri.localhost to
default-src, https://ipc.localhost and tauri: to connect-src. WKWebView
uses different IPC scheme than Windows WebView2.
Theme application:
- terminal.refresh() after theme change forces xterm.js canvas repaint
of existing text — was only changing background, not text colors
Selection highlighting:
- Removed CSS .xterm-selection div rule entirely — xterm.js v6 canvas
renderer doesn't use DOM selection divs, the CSS was a no-op that
conflicted with theme-driven selectionBackground
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Popup windows (tools/editor/help):
- CSP script-src 'self' blocked Tauri's inline IPC bridge scripts in
child WebviewWindows. Added 'unsafe-inline' to script-src. Still
restrictive (was null before SEC-4).
Theme application:
- Watcher on sessionStore.activeTheme needed { deep: true } — Pinia
reactive proxy identity doesn't change on object replacement
- LocalTerminalView.vue had ZERO theme support — added full applyTheme()
with watcher and mount-time application
- Container background now syncs with theme (was stuck on CSS variable)
Cursor blink:
- terminal.focus() after mount in useTerminal.ts — terminal opened
without focus, xterm.js rendered static outline instead of blinking block
Selection highlighting:
- applyTheme() was overwriting theme without selectionBackground/
selectionForeground/selectionInactiveBackground — selection invisible
after any theme change
- Removed !important from terminal.css that overrode canvas selection
- Bumped default selection opacity 0.3 → 0.4
Status bar:
- h-6 text-[10px] → h-8 text-xs (24px/10px → 32px/12px)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract handleKeydown into useKeyboardShortcuts.ts composable; reduces
MainLayout by ~20 lines and isolates keyboard logic cleanly
- ConnectionTree: watch groups for additions and auto-expand new entries
- MonitorBar: generation counter prevents stale event listeners on rapid
tab switching
- NetworkScanner: revoke blob URL after CSV export click (memory leak)
- TransferProgress: implement the auto-expand/collapse watcher that was
only commented but never wired up
- FileTree: block binary/large file uploads with clear user error rather
than silently corrupting — backend sftp_write_file is text-only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
VUE-1: store workspace save interval ID, clear in onUnmounted
VUE-2: extract beforeunload handler to named function, remove in onUnmounted
VUE-3: move useTerminal() to <script setup> top level in DetachedSession
VUE-4: call useTerminal() before nextTick await in CopilotPanel launch()
VUE-5: remove duplicate ResizeObserver from LocalTerminalView (useTerminal already creates one)
VUE-6: store terminal.onResize() IDisposable, dispose in onBeforeUnmount
VUE-7: extract connectSsh(), connectRdp(), resolveCredentials() from 220-line connect()
VUE-8: check session protocol before ssh_resize vs pty_resize in TerminalView
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
Two issues:
1. convertEol was false for PTY sessions, but Windows ConPTY sends
bare \n without \r. Now enabled on Windows PTY sessions (checked
via navigator.platform). Unix PTY still false (driver handles it).
2. LocalTerminalView had no ResizeObserver, so the terminal never
reflowed when the container size changed. Added ResizeObserver
matching the SSH TerminalView pattern. Also added proper cleanup
on unmount.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
The watch on isActive never fired on initial mount because the value
starts as true (Vue watch only triggers on changes). Added explicit
focus + fit in onMounted with a short delay for DOM readiness.
Also added @click handler on container as fallback focus mechanism.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rust SSH service: russh async client, DashMap session registry,
TOFU host key verification, CWD tracking via separate exec channel
(never touches terminal stream), base64 event emission for terminal
I/O. 52/52 tests passing.
Vue 3 frontend: ported from Wails v3 to Tauri v2 — useTerminal
composable with streaming TextDecoder + rAF batching, session store
with multi-connection support, connection store/tree, sidebar, tab
bar, status bar, keyboard shortcuts. All Wails imports replaced
with Tauri API equivalents.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>