* feat(scripts): add terminal script automation, recording, and side panel
Introduce nct script runtime in the main process with terminal-side recording,
execution overlay, Monaco editor, connect-script queues, and scripts side panel
integration. Fix recording to wire scriptRecorderRef into xterm, use waitForPrompt
for root/user shells, and save recorded scripts through the global editor dialog.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): address Bugbot review findings for recording and side panel
Refresh script run state in side panel memo, guard toolbar recording against
multi-session conflicts, reset connect scripts on reconnect, resolve focused
session via getActiveTerminalSessionId, and avoid wiping host edit form when
snippets list updates.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): prevent pending script re-run and improve workspace run feedback
Track one-shot pendingScript execution separately from onConnect queue so
reconnects do not replay Run-now scripts. Fall back to focused session when
running on all tabs outside a workspace, and toast when every tab is still
connecting.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): consume connect-script window once and filter serial hosts
Mark the onConnect script evaluation as consumed even when the queue is
empty so later snippet/host edits do not rerun automation mid-session.
Restore serial-host filtering in SelectHostPanel confirm handler.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): grace period before giving up on connect-script queue
Only mark onConnect automation as consumed after scripts run or a short
post-connect grace window expires, so late-loading snippets still trigger
while mid-session Vault edits do not.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): gate connect-script consumption on vault hydration
Replace the grace timer with vault-init and unresolved host script binding
checks so late-loading snippets still run onConnect automation while
mid-session edits stay suppressed. Clear pending script run state on
disconnect so reconnect retries workspace pending scripts.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): honor run targets and retry failed connect automation
Route QuickScriptEditorDialog Run through onRunSnippet for multi-host
workspaces. Defer connect/pending script completion markers until each
script succeeds and retry the queue after failures.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): stabilize pending runs and global connect queue sync
Keep pending script run state across reconnects, run onConnect scripts
before one-shot workspace pending scripts, and strip per-host queue entries
when an onConnect script targets all hosts.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): defer host queue snippet sync and guard connect runs
Persist snippet target links only when the host panel is saved, block
duplicate connect-script scheduling while a batch is running, and require
runnable hosts before showing Run in the snippets editor footer.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): retry connect failures and surface output-trigger errors
Use a retry tick in connect-script effect deps, toast automation failures
from output triggers, and require runnable hosts before QuickScript Run.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): track id-less pending runs and re-arm output triggers
Remember anonymous pendingScript objects after first run and allow
onOutput triggers to fire again when new terminal output arrives.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): unblock paused connect runs and pass session meta
Resolve waitForScriptRun on pause, run workspace scripts per session
with hostname context, defer output-trigger arming until runs start, and
add noRunnableHosts i18n for QuickScript Run.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): serialize output triggers and defer empty connect finalize
Fire at most one onOutput trigger per scan while a run is active, and
only finalize an empty connect queue after vault snippets are loaded.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): guard output launch race and script run waits
Block overlapping onOutput launches, timeout stuck waitForScriptRun
promises, and disable vault Run when no connectable targets exist.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): match output triggers on new chunks only
Scan onOutput patterns against recent terminal output instead of buffer
length dedupe, and restore overflow-visible on SelectHostPanel new-host flow.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): await sequential workspace runs and output launch
Wait for each tab script to finish in sequential workspace mode, and hold
output-trigger launch guard until the session run becomes active.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): wait through pause and hold output trigger until done
Keep connect and sequential workspace queues blocked until scripts
complete or fail, and retain output-trigger guard until the launched run
finishes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): harden output trigger wait helpers
Add explicit timeouts to output-trigger wait helpers and stop rescanning
the buffer after script completion to avoid sticky-match rerun loops.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): allow empty connect queue and match output in new chunks
Treat an empty connectScriptIds array as an explicit cleared queue instead
of re-migrating from snippet targets, and only fire onOutput triggers when
the latest terminal output contains the pattern.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): require fresh output overlap for onOutput triggers
Only fire output-matched scripts when the regex match extends into the
latest terminal chunk, preventing reruns from stale buffer text.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): promote manual scripts added to host connect queue
Diff connect queue changes from raw connectScriptIds so saving a host
updates manual scripts to onConnect when they are newly queued.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): dedupe output triggers by match position
Track the buffer end offset of each output trigger match and ignore
stale re-scans, with a longer wait for run registration before retry.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): record output trigger matches only after run starts
Propagate automation launch failures to output triggers and commit match
dedupe only once the session run is registered as active.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): address Codex review on wait cursor and sensitive codegen
Track scan offset so waitFor/waitForAny only match output after the previous wait, and emit sendLine after sensitive prompt in recorded scripts.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(scripts): harden onOutput triggers against PTY echo and local input
Filter server output before pattern matching so onOutput fires only after
Enter on real stdout, not on keystroke/paste echo, OSC/SGR sequences, or
alternate-screen apps. Add dev diagnostics and scope triggers to the active
session when no explicit host targets are configured.
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(scripts): remove onOutput trigger debug logging
Drop temporary diagnostics module and console traces now that PTY echo
filtering is verified; keep the production trigger pipeline unchanged.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ui): improve host tree inline group rename interactions
Cancel rename when clicking another tree row and prevent parent drag from blocking text selection in the rename input.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ui): block group toggle keyboard while inline renaming
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ui): cancel host inline rename when clicking other tree rows
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(vault): add duplicate host action to tree view context menu
Wire the existing onDuplicateHost handler into vault host tree menus so
tree view matches grid/list duplicate behavior. Fixes#1329.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(vault): switch to hosts section when duplicating from terminal tree
Ensure the host details panel is visible after duplicate is triggered
from the terminal host tree sidebar.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* perf(terminal): smooth layout drags and faster tab switching
Defer xterm refit during split, sidebar, and host-tree drags while keeping pane containers in sync with live layout measurements. Refactor TerminalLayer into focused sections with TabBridge/memo optimizations and add the terminal host tree sidebar.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(terminal): keep side panels alive and guard session attach races
Prevent terminal boot unmount from leaking backend sessions, keep SFTP/scripts/theme/AI state when switching side tabs, and defer heavy SFTP UI mount so first entry stays responsive.
Co-authored-by: Cursor <cursoragent@cursor.com>
* perf(terminal): reduce tab switch jank
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
getDropTargetClasses and setDragOverDropTarget were added to
HostTreeViewProps interface and used in JSX but never destructured
from the component's props parameter. TypeScript didn't catch it
because the interface defined them as optional, but at runtime the
bare variable references caused ReferenceError, crashing React and
producing a white screen on startup.
Closes#625
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(models): add pinned and lastConnectedAt fields to Host
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(i18n): add translations for pinned and recently connected sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(vault): add pin toggle, lastConnectedAt tracking, and computed sections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(vault): render Pinned and Recently Connected sections at root level
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(vault): add pin/unpin context menus and hover edit buttons in all views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(vault): make breadcrumb a drop target for moving groups back to root
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(settings): add toggle for showing recently connected hosts section
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: resolve lint warnings for unused vars and unnecessary dependency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: improve pin performance and add pop-in animation
- Use ref for hosts in callbacks to avoid stale closures and
unnecessary re-renders when hosts array changes
- Add pop-in spring animation on pinned host cards with staggered
delay for a satisfying visual effect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: fix pop-in animation visibility and improve pin responsiveness
- Move @keyframes pop-in out of @layer base to global scope so inline
styles can reference it
- Add translateY to animation for a bouncier, more satisfying feel
- Use pinnedAnimKey to force card remount on pin changes so animation
replays each time
- Wrap onUpdateHosts in startTransition for non-blocking pin updates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: only animate newly pinned card, increase section spacing
- Track lastPinnedId instead of global animKey so only the newly pinned
card gets the pop-in animation, not all existing pinned cards
- Clear animation state via onAnimationEnd for clean re-trigger
- Add mb-4 to Pinned and Recent sections for better visual separation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(vault): show pin indicator icon on pinned host cards
Small semi-transparent pin icon in top-right corner of pinned host
cards in the Hosts section (grid view only).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: use solid amber/yellow pin indicator icon
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: tilt pin indicator icon 45 degrees
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: replace pin indicator with filled amber star on all pinned cards
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move lastConnectedAt tracking to App-level handleConnectToHost
Previously updating lastConnectedAt in VaultView's handleHostConnect
which could be lost during tab switches. Now tracked at the App level
where all connections are handled, ensuring the timestamp persists
regardless of UI navigation state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address Codex review findings (P2 issues)
1. useStoredBoolean now syncs across same-window components via
CustomEvent dispatch, so Settings toggle immediately updates VaultView
2. lastConnectedAt updated after connectToHost succeeds, not before
3. Pinned and Recently Connected sections now respect active search
and tag filters
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address second round Codex review findings
1. Track lastConnectedAt on actual 'connected' status instead of
session creation - handles via handleSessionStatusChange wrapper
2. Covers tray panel connections since all paths go through
updateSessionStatus
3. Pinned/Recent cards now honor multi-select mode with checkbox
UI instead of triggering connections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address third round Codex review findings
1. [P1] Use hostsRef in handleSessionStatusChange to avoid
overwriting concurrent host changes with stale snapshot
2. [P2] Exclude pinned/recent hosts from main host list at root
level to prevent duplicate cards on screen
3. [P2] Remove Pin action from tree view context menu since tree
view has no pinned ordering/indicator support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address fourth round Codex review findings
1. [P1] Remove leftover onToggleHostPinned references in HostTreeView
root-level component that were missed in previous cleanup
2. [P2] Add draggable + onDragStart to pinned/recent host cards so
drag-and-drop between groups still works
3. [P3] Fix grouped view header count to exclude hosts already shown
in pinned/recent sections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use functional state update for lastConnectedAt, dedupe pinned from recent
1. [P2] Add updateHostLastConnected using setHosts(prev => ...) functional
update pattern (same as updateHostDistro) to avoid overwriting concurrent
host changes when multiple sessions connect simultaneously
2. [P3] Exclude pinned hosts from Recently Connected section to prevent
duplicate cards between the two top sections
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: wire showRecentHosts into settings sync, clear pin on duplicate
1. [P2] Add showRecentHosts to SyncPayload settings so the preference
survives cloud sync and settings export/import
2. [P2] Clear pinned and lastConnectedAt on duplicated hosts so copies
don't inherit pin/recent status from the original
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: tray quit button, tree view multi-select, and SFTP banner handling
- Add "Quit Netcatty" button pinned to the bottom of TrayPanel so users
can exit the app when close-to-tray is enabled
- Support multi-select mode in HostTreeView (checkboxes, click-to-select)
so tree view behaves the same as grid/list views
- Patch ssh2 SFTP parser to skip non-SFTP preamble data (MOTD/banner text)
that causes "Packet length exceeds max length" errors on misconfigured
servers, with proper cross-frame buffering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: gate SFTP preamble scan to client-mode only
Server-mode SFTP expects SSH_FXP_INIT (0x01) as the first packet, not
SSH_FXP_VERSION (0x02). Skip the preamble scan entirely when running in
server mode to avoid stalling server-side SFTP sessions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Fix managed host sync: add group field to change detection
- Auto-set managedSourceId when moving host to managed group
- Add 'managed' badge to managed hosts in VaultView
- Fix file path resolution for managed sources using webUtils
- Add managedSources prop to HostDetailsPanel for proper sync
- Restrict spaces in label for managed hosts
- Reorder HostDetailsPanel sections: General > Address > Port & Credentials
- Add debug logging for managed source sync troubleshooting
- Display folders above ungrouped hosts in tree view
- Change host connection from double-click to single-click
- Sanitize host before connecting to handle whitespace in hostname
- Guard optional host.tags to prevent crash on legacy data
- Show telnet-specific credentials (telnetUsername/telnetPort) for telnet hosts
- Remove unused groupTree variable and prefix unused moveHostToGroup param
Co-Authored-By: Claude <noreply@anthropic.com>
- Add tree view mode alongside existing grid and list views
- Implement hierarchical display of hosts organized by groups
- Add expand/collapse all controls with Chinese translations
- Support all sorting modes (A-Z, Z-A, newest, oldest) in tree view
- Persist expand/collapse state across view switches and app restarts
- Hide Groups section in tree view to avoid duplication
- Display ungrouped hosts at root level instead of "General" group
- Add missing delete group dialog with proper translations
- Maintain full functionality: search, filtering, drag-drop, context menus
Technical changes:
- Create HostTreeView component with TreeNode recursive structure
- Add useTreeExpandedState hook for persistent state management
- Extend ViewMode type to include "tree" option
- Add sortMode prop to enable dynamic sorting in tree structure
- Separate group tree logic for tree view vs other view modes
- Add comprehensive English and Chinese translations