Introduce workspace-aware System side panel with remote process/tmux/Docker management, terminal popup for interactive attach, capability warmup, review-hardened IPC, performance optimizations, toast action errors, and SSH channel recovery on reconnect.
* fix(ai): make SDK deps optional, degrade gracefully when missing
- Move @anthropic-ai/claude-agent-sdk and @github/copilot-sdk
from dependencies to optionalDependencies so npm install does
not fail when they are unavailable
- claudeDriver.listClaudeModels: catch import error, return [] silently
- copilotDriver.listCopilotModels: catch import error, return [] silently
- sdkStreamHandlers: downgrade log from console.error to console.debug
The renderer already falls back to curated model presets when
list-models returns [], so no functional change.
* fixup: honor queryFn before SDK import; regenerate lockfile with optional markers
* fixup: guard runTurn against missing SDK modules
runClaudeTurn and runCopilotTurn now catch dynamic import errors
and emit a user-friendly error message instead of crashing with
a raw module-not-found error.
* chore(ai): upgrade ACP packages and unwrap Skill+CLI command in tool-call panel
Package bumps:
- @zed-industries/claude-agent-acp 0.22.2 → @agentclientprotocol/claude-agent-acp 0.37.0
(old npm package is deprecated; scope rename)
- @zed-industries/codex-acp 0.10.0 → 0.15.0
- @mcpc-tech/acp-ai-provider 0.2.8 → 0.3.3
- electron-builder asarUnpack glob + bridge require.resolve switched to the new scope
After the upgrade Codex tool-call cards started showing the local
worktree path for every step — "Run /Users/.../netcatty-tool-cli session
--session …" — instead of the remote command. Three things lined up:
1. The new acp-ai-provider maps ACP's `title` to `toolName`, and Codex's
title is the full shell invocation it's about to run.
2. Codex local_shell ships args as ["/bin/zsh","-lc","<full>"], so the
old `typeof args.command === 'string'` branch in ToolCall never fired
and we fell through to printing `name` (i.e. the title).
3. The bridge serializes tool args under `args`, but the ACP adapter
only read `event.input`, so even when args were available the
renderer received {}.
Fixes:
- acpAgentAdapter: read tool input from both `event.input` and
`event.args` so bridge-serialized chunks and direct AI SDK chunks
both work.
- ai-elements/tool-call: new extractDisplayCommand() unwraps the shell
array, then the netcatty-tool-cli wrapper (exec/job-start … -- <cmd>),
and renders the real remote command. session/env/job-poll/etc. fall
back to short labels ("netcatty: inspect session", …) instead of
exposing the binary path.
- shellUtils.cjs: defensive JSON-parse the ACP wrapper input in case
the AI SDK ever stops auto-parsing it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(build): exclude bundled Claude CLI binaries from the installer
@anthropic-ai/claude-agent-sdk@0.3.x bundles the native Claude Code CLI
(~211MB per arch) as optional sibling packages. Including them would
silently regress Netcatty's "bring your own Claude" design — the project
has always required users to install Claude Code locally, and the entire
path-discovery flow exists precisely to honor that contract:
- useAgentDiscovery.ts scans the user's PATH for `claude` and writes
the absolute path into the agent config's CLAUDE_CODE_EXECUTABLE env.
- aiBridge.cjs runs normalizeClaudeCodeExecutableEnvForAcp on every ACP
spawn, forwarding the env var to the child process.
- The @agentclientprotocol/claude-agent-acp wrapper's claudeCliPath()
(acp-agent.js) prefers process.env.CLAUDE_CODE_EXECUTABLE over the
bundled binary and only falls back to sibling-package resolution when
the env var is empty.
So the right place to enforce the design is electron-builder: exclude
node_modules/@anthropic-ai/claude-agent-sdk-* from `files`. Dev mode is
unaffected (optional deps still install for `npm run dev`); only the
packaged installer drops the binaries, saving ~150MB. Users without
Claude Code installed get the same SDK error they got pre-upgrade.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(ctrl-w): add ps-node + windows-process-tree + tsx deps for close-priority feature
* fix(ctrl-w): drop ps-node dep and add windows-process-tree to asarUnpack
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): add ptyProcessTree bridge with per-platform child-process enumeration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ctrl-w): ptyProcessTree uses args= for full command + warns on pid overwrite
- Replace `comm=` with `args=` in defaultListPosix so the full command
line is captured on both macOS (BSD ps) and Linux (GNU ps), avoiding
the 15-char TASK_COMM_LEN truncation.
- Add console.warn in registerPid when the same sessionId is overwritten
with a different pid, making the race condition visible in logs.
- Add test: registerPid warns exactly once on a pid change, not on a
same-pid re-registration.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): register local PTY pid with ptyProcessTree on spawn/exit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ctrl-w): unregister pids in cleanupAllSessions to match per-delete invariant
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): add IPC handlers for pty child processes and confirm-close dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ctrl-w): guard BrowserWindow.fromWebContents null and document dialog dismiss contract
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): expose ptyGetChildProcesses and confirmCloseBusy on window.netcatty
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): add i18n strings for close-busy-terminal dialog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): add resolveCloseIntent pure function with 8 unit tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): expose handleCloseSidePanel via ref to App.tsx
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): wire resolveCloseIntent + local-shell busy confirmation into closeTab hotkey
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ctrl-w): add re-entrancy guard, aggregate busy count, sync sidebar ref, dedupe intent branches
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(ctrl-w): auto-close workspace when its last session is closed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ctrl-w): sidebar close wins over focused terminal in priority chain
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ctrl-w): sidebar priority applies to single-session tabs too, not just workspaces
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(ctrl-w): compute empty-workspace auto-close outside setSessions updater
Addresses Codex P2 on #739: React 18+ does not guarantee updater
execution timing under concurrent scheduling. Moving the decision
outside the updater makes the microtask queue deterministic.
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add ZMODEM (lrzsz) file transfer support for terminal sessions
Adds ZMODEM protocol detection and file transfer capability to all
terminal session types (Local, SSH, Telnet, Mosh, Serial). Uses
zmodem.js library with main-process sentry pattern to intercept
binary data before string decoding, avoiding IPC pipeline changes.
- zmodemHelper.cjs: shared ZMODEM sentry with Electron dialog integration
- terminalBridge.cjs: encoding:null for PTY + sentry wrappers for all session types
- sshBridge.cjs: sentry wrapper for SSH stream data
- preload.cjs + global.d.ts: ZMODEM event IPC bridge and TypeScript types
- useZmodemTransfer.ts: React hook for ZMODEM transfer state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: preserve charset decoding and add ZMODEM progress UI
- zmodemHelper: pass raw Buffer to onData, let callers handle decoding
- terminalBridge: use StringDecoder for telnet/serial, UTF-8 for local/mosh
- sshBridge: restore iconv decoder for SSH session charset support
- ZmodemProgressIndicator: floating progress bar with cancel button
- Terminal.tsx: wire useZmodemTransfer hook + toast notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: ZMODEM listener cleanup, stream leak, and toast dedup
- preload: clean up zmodemListeners on session exit (memory leak)
- zmodemHelper: add ws.on('error') handler to close write stream on failure
- Terminal: use ref guard to prevent duplicate toast notifications
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address code review findings for ZMODEM
- cancel/consume error now send IPC event to renderer (prevents stuck UI)
- sanitize download filename with path.basename (path traversal prevention)
- add on_detect concurrency guard (deny if transfer already active)
- formatBytes: handle negative, zero, and TB+ values safely
- closeSession: cancel active ZMODEM before destroying transport
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: prevent double-notification on cancel and stream error resilience
- Guard .then()/.catch() in promise chain: skip if cancel() already handled
- Download: add writeAborted flag to stop on_input after stream error
- Upload: pre-compute file stats to avoid O(N²) statSync calls
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use zsession.abort() instead of close() on dialog cancel
close() is only available on Send sessions. Calling it on a Receive
session throws, leaving the sentry's internal _zsession dangling and
causing subsequent terminal data to be consumed by the abandoned
ZMODEM session (terminal freeze). abort() is defined on the base
ZmodemSession class and properly fires session_end to reset the sentry.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: handle ZFIN/OO mismatch as successful transfer
When sz exits over SSH, the shell prompt often arrives before the
ZMODEM "OO" end marker, causing zmodem.js to throw a protocol error.
Since ZFIN was already exchanged (= all file data transferred), treat
this specific error as a successful completion and forward the shell
prompt data back to the terminal via sentry re-consume.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — UTF-8 decoder, ZFIN abort, session exit cleanup
- terminalBridge: use StringDecoder for local/mosh PTY to handle
multi-byte UTF-8 split across buffer boundaries (prevents garbled
CJK/emoji output)
- zmodemHelper: on ZFIN/OO success path, use _on_session_end() instead
of abort() to avoid sending CAN (Ctrl-X) bytes to the remote shell
- useZmodemTransfer: listen to onSessionExit to reset state when the
session dies mid-transfer (prevents stuck progress indicator)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — file collision handling and stream flush
- Download: auto-rename with (1), (2), etc. if file already exists
in the target directory, preventing silent overwrite
- Download: wait for all write streams to finish flushing before
resolving the session_end promise, ensuring data is on disk when
the UI reports completion
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — Windows PTY string compat and Telnet binary safety
- Local/Mosh PTY: handle string data from Windows node-pty which
ignores encoding: null; convert to Buffer before sentry.consume()
- Telnet: bypass IAC negotiation during active ZMODEM transfer to
preserve 0xFF bytes in binary data
- Telnet writeToRemote: escape 0xFF as 0xFF 0xFF per Telnet spec
so ZMODEM binary data is not treated as IAC commands
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — Windows PTY guard, Telnet IAC, stream cleanup
- Local/Mosh: skip ZMODEM sentry on Windows where node-pty can't
provide raw bytes; fall back to original string pipeline
- Telnet: always run IAC negotiation (even during ZMODEM) since the
Telnet layer still escapes 0xFF as IAC IAC; the existing handler
already correctly collapses IAC IAC → single 0xFF
- Download: destroy un-ended write streams on session_end to prevent
hanging promises and leaked file descriptors on abort
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — early session start, progress throttle, no dup start
- Download: call zsession.start() before showing folder picker dialog
so lrzsz doesn't time out waiting for ZRINIT
- Download: throttle progress IPC to ~10 updates/sec (100ms interval)
to avoid overwhelming renderer on fast links
- Download: remove duplicate zsession.start() at bottom of Promise
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: handle ZRPOS and prevent terminal flood after ZMODEM abort
- Add 500ms cooldown after ZMODEM abort: suppress residual protocol
bytes from remote rz/sz that would otherwise flood the terminal
- Send 8x CAN (Ctrl-X) on abort/cancel/error to force remote end to
stop transmitting even if the initial abort sequence was lost
- Handles "Unhandled header: ZRPOS" gracefully (zmodem.js doesn't
support error recovery, so abort is the correct response)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: send Ctrl+C after abort in all cancel/error paths
Debian's rz stays attached to the TTY after receiving CAN sequences.
The cancel() path already sent Ctrl+C via scheduleRemoteInterruptAfterCancel,
but dialog-cancel and consume-error paths did not. Now all three abort
paths (dialog cancel, consume error, explicit cancel) send Ctrl+C after
150ms to ensure the remote rz/sz process exits and the shell regains control.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add interruptRemote for SSH ZMODEM sentry
Pass SSH stream.signal("INT") as interruptRemote callback so the
ZMODEM helper can send SIGINT to the remote process when cancelling
transfers, complementing the Ctrl+C byte sent via writeToRemote.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: dialog-cancel abort uses module-level helper to avoid ReferenceError
sendExtraAbortBytes and writeToRemote are closure-scoped inside
createZmodemSentry, not accessible from handleUpload/handleDownload.
Extract abortRemoteProcess as a module-level function that takes
writeToRemote as a parameter, used in both dialog-cancel paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: dialog cancel throws instead of returning to avoid false complete
When user dismisses the file/folder picker, handleUpload/handleDownload
now throw "Transfer cancelled" instead of returning normally. This
ensures the .catch() handler fires (sending error event) rather than
.then() (which would incorrectly send complete event).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — preserve transferType in progress events
- useZmodemTransfer: copy transferType from progress events so the
transfer direction is preserved if renderer re-subscribes after
the initial detect event was missed
- zmodemHelper: clean up upload loop comments (backpressure handled
via 64KB chunks + setImmediate yield per iteration)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: codex review — guard stale session cleanup, delete partial downloads
- Promise chain .then/.catch/.finally now compare currentZSession
identity (=== zsession) instead of truthiness, preventing a new
transfer from being clobbered by the old promise settling
- Aborted/incomplete downloads are deleted from disk on session_end
so users don't end up with corrupt partial files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: unconditional cooldown suppression after ZMODEM abort
The previous cooldown checked if data "looks like residual ZMODEM"
which fails for sz's file content (arbitrary printable bytes). Now
cooldown unconditionally drops ALL incoming data for 2 seconds after
abort, with repeated CAN bursts to ensure the remote sz stops. This
prevents the terminal flood seen when cancelling large sz downloads
on fast connections.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Load @xterm/addon-unicode11 and set activeVersion to '11' for better
character width handling of Nerd Fonts, Powerline glyphs, and CJK
characters. This matches the approach used by tabby terminal.
Closes#543 (Nerd Fonts portion)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Load @xterm/addon-unicode11 and set activeVersion to '11' for better
character width handling of Nerd Fonts, Powerline glyphs, and CJK
characters. This matches the approach used by tabby terminal.
Closes#543 (Nerd Fonts portion)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: bundle claude-code-acp to prevent crash when binary is missing (#400)
When users select Claude Code in the AI module, the app spawns
`claude-code-acp` via ACP. Previously only the `claude` CLI was checked
during agent discovery, so if `claude-code-acp` was not on PATH the
spawn would fail with ENOENT and crash the Electron main process.
- Add `@zed-industries/claude-code-acp` as a bundled dependency
- Add `resolveClaudeAcpBinaryPath()` that checks PATH first, then
falls back to the npm-bundled binary (mirrors Codex pattern)
- Use the resolver in both the primary and fallback ACP provider paths
- Update agent discovery to detect agents via bundled ACP binary when
the standalone CLI is not installed
Closes#400
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add claude-code-acp and its deps to asarUnpack
In packaged Electron builds, files inside app.asar cannot be executed
by child_process.spawn. Add claude-code-acp and its runtime dependencies
to asarUnpack so the binary is accessible in production.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: migrate from deprecated claude-code-acp to claude-agent-acp
The @zed-industries/claude-code-acp package has been renamed to
@zed-industries/claude-agent-acp (bin: claude-agent-acp). Update all
references across the codebase:
- package.json: replace dep with @zed-industries/claude-agent-acp@0.22.2
- electron-builder.config.cjs: update asarUnpack entries, remove stale
deps (diff, minimatch) no longer needed by the new package
- shellUtils.cjs: update binary name and require.resolve path
- aiBridge.cjs: update acpCommand, ALLOWED_AGENT_COMMANDS, isClaudeAgent
- settings types, i18n locales: update command references
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The beta version had native module loading issues on Arch Linux AppImage
builds (ERR_DLOPEN_FAILED). The stable release uses an improved module
loading strategy with prebuild support for macOS/Windows and better
build-from-source fallback for Linux.
Related: #264
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Integrate Claude Agent SDK for direct streaming chat, add Codex login/logout
flow with OAuth support in settings, improve AI chat panel UI and agent
discovery, and update build config for new dependencies.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add auto-discovery of CLI agents (Claude Code, Codex, Gemini) from system PATH
- Integrate ACP (Agent Client Protocol) for real-time streaming with codex-acp
- Bundle @zed-industries/codex-acp binary for reliable agent spawning
- Add ThinkingBlock component with shimmer animation and auto-collapse
- Refactor chat UI: no avatars, bordered user bubbles, plain assistant text
- Support {prompt} placeholder in agent args for flexible invocation
- Add persistent ACP sessions with proper cleanup on app exit
- Detect auth errors and show actionable messages to users
- Fallback to raw process spawn for agents without ACP support
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add auto-update support via electron-updater (#289)
- Add autoUpdateBridge.cjs wrapping electron-updater for check/download/install
- Register bridge in main.cjs, expose IPC in preload.cjs
- Add auto-update methods to NetcattyBridge type in global.d.ts
- Extend updateService.ts with electron-updater bridge functions
- Add Software Update section in Settings > System tab with state machine UI
- Add i18n keys for update UI (en + zh-CN)
- Add publish config for GitHub Releases in electron-builder.config.cjs
- Update CI workflow to upload update metadata (*.yml, *.blockmap, *.zip)
- Fallback to manual GitHub download for unsupported platforms or errors
* fix: address Codex review - guard bridge call and pin sender window
- Guard optional bridge call in SettingsSystemTab to prevent TypeError
when getAppInfo is unavailable (e.g. browser/dev/test rendering)
- Capture senderWindow at download initiation in autoUpdateBridge so
progress/downloaded/error events always go to the requesting renderer,
even if focus changes during download
* fix: use semver ordering for version check and clean up listeners on rejection
- Replace strict equality (===) with localeCompare for version comparison
to avoid false positives on pre-release/nightly builds
- Clean up download-progress/update-downloaded/error listeners in the
catch path when downloadUpdate() rejects before emitting events
* feat: redirect update toast to Settings window for in-app update
- Update toast notification now opens Settings window instead of
GitHub Releases page, enabling the in-app download/install flow
- Add 'update.viewInSettings' i18n key (en + zh-CN)
- Remove unused openReleasePage from App.tsx destructuring
- Move useWindowControls() before the update effect to fix declaration order
On Windows/Linux, the frameless title bar had ~20px of dead space
(12px right padding + 8px drag shim) to the right of the close button.
- Replace Tailwind `px-3` with conditional inline paddingRight (0 on
Windows, 12px on macOS) so the close button sits at the window edge
- Render the drag shim only on macOS where it's useful as a drag region
macOS layout is unchanged.
Co-authored-by: binaricat <16399091+binaricat@users.noreply.github.com>
The cpu-features package fails to compile with newer Node.js/Electron
due to deprecated V8 APIs. Since it's an optional dependency of ssh2,
replace it with an empty package via npm overrides.
- Remove chacha20-poly1305@openssh.com from SSH cipher list as Electron's
BoringSSL (from Chromium) does not support standalone chacha20 cipher
- Upgrade Electron from 39.2.6 to 40.1.0 (Node.js 24.11.1)
- Keep AES-GCM and AES-CTR ciphers which are fully supported
The chacha20-poly1305 algorithm requires OpenSSL's chacha20 cipher which
is not available in Electron's bundled BoringSSL. This caused connection
failures with 'Unsupported algorithm' error when connecting to SSH servers.
- Added `CreateWorkspaceDialog` component for creating named workspaces with multiple hosts.
- Implemented `createWorkspaceWithHosts` in `useSessionState`.
- Integrated dialog into `App.tsx` and triggered from Quick Switcher.
- Updated `QuickSwitcher` logic to improve visibility of recent connections.
- Added i18n keys for the dialog.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Replace text+icon buttons with icon-only buttons and tooltips for Upload,
Upload Folder, New Folder, and New File actions. Uses more distinctive
icons (FolderPlus, FilePlus) and adds a new Tooltip component.
Co-Authored-By: Claude (gemini-claude-opus-4-5-thinking) <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
- Use toast.success/warning instead of toast({title:}) for better UX
- Change credentials copy format to labeled multi-line format
- Add ESLint global declarations for Node.js globals
Co-Authored-By: Claude <noreply@anthropic.com>
Add real-time monitoring of Linux server resources in the terminal statusbar:
- CPU usage with per-core breakdown in hover popup
- Memory usage with htop-style colored bar (Used/Buffers/Cache/Free)
- Top 10 processes by memory consumption
- Disk usage for all mounted partitions
- Network speed (RX/TX) with per-interface details
Features:
- Only enabled for Linux servers (detected automatically)
- Configurable refresh interval (default 5 seconds)
- Toggle in Settings > Terminal tab
- Hover-triggered popups using Radix UI HoverCard
- BusyBox compatibility with fallback commands
Closes#108
Co-Authored-By: Claude <noreply@anthropic.com>
Detects common SFTP session errors and automatically attempts to re‑establish the connection (up to three tries).
Provides user feedback with a reconnect overlay, spinner integration, and success/error toast notifications.
Adds corresponding English and Chinese i18n messages for reconnect status and failure.
Minor build config comment added (no functional impact).
Bumps a wide range of packages to their newest releases, including AWS SDK v3.967 and related @smithy modules, Electron builder libraries, Rollup 4.55.1, Babel 7.28.x, and @npmcli tooling. Removes deprecated packages (e.g., @tootallnate/once, is-ci) and adds missing utilities such as @isaacs/fs-minipass and ci-info. These updates improve compatibility with newer Node versions, address security fixes, and enhance build stability.
Adds missing `"peer": true` entries for several development packages and removes incorrectly set peer flags from optional dependencies. This aligns the lockfile metadata with the actual peer‑dependency relationships, improving package resolution and consistency.