- Use scoped historySessions for draft-force and ownership-clear guards
so out-of-scope sessions demote instead of sticking blank.
- On server-stats pause, keep the last snapshot but clear givenUp so
resume can auto-retry after hard failure.
- Fix ProcessRow undeclared vendorLabel via vendorDisplayLabel; make
GPU marks decorative (aria-hidden); attribute Simple Icons as CC0.
- Sticky icon-only when tab bar width is zero; include workspaces in
TerminalLayer ctx deps.
Prevent StrictMode draft demotion after send, keep workspace AI maintenance
mounted with a workspaces list, and keep live Streamdown markdown while
streaming. System Manager gains overflow-aware icon-only tabs, customize
layout, GPU vendor badges, and cache-preserving overview remounts. Settings
search scrolls only the content pane so traffic lights stay put.
Related to #2561.
Adds detect-first Ports/Services system manager tabs, network-appliance
read-only gating, and hardened collectors/parsers from Bugbot review.
* fix(system-manager): parse CANN 24.x Ascend npu-smi info tables
ModelArts / CANN 24.1 tables include Hugepages-Usage and Bus-Id chip rows
that the old regex rejected, so the GPU tab showed zero Ascend devices
even when npu-smi was present. Parse summary+chip pairs like nputop,
always collect the info dump, and fall back to info -m for NPU IDs.
Closes#2811
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* feat(system-manager): harden Ascend parsing from nputop fixtures and polish GPU UI
Borrow real npu-smi samples from youyve/nputop (Apache-2.0) so CI covers
910B2C, 310B4, Atlas A3 multi-chip, and 310P3 process tables without
hardware. Aggregate multi-chip NPUs, parse info-dump processes, and surface
npu-smi driver versions.
GPU tab now keeps a short util/HBM sparkline history and ResourceBar uses
smooth width transitions with load-aware tones, closer to an nvtop feel
inside the existing system-manager chrome.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* refactor: migrate architecture-debt hooks into application/state
Move SFTP Wave A stores/hooks and related vault/AI/terminal/systemManager
hooks out of components into application/state, update importers, and keep
thin deprecated re-exports at the old paths.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* refactor(sftp): align local bookmarks store API with global bookmarks
Export subscribe/get/set/rehydrate helpers from localSftpBookmarks to match
the globalSftpBookmarks external-store pattern.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(electron): reduce baseline memory via spellcheck/GPU/prewarm guards
Disable spellcheck on BrowserWindows and the default session, drop spare
renderers, gate aggressive GPU switches behind NETCATTY_COMPAT_GPU, and make
settings prewarm opt-in via NETCATTY_PREWARM_SETTINGS.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* Isolate notes and customAccent from TerminalLayer hot props
Route vault notes through notesStore (shellHistoryStore pattern) and
app accent through appearanceChromeStore so note edits and accent-drag
ticks no longer rebuild TerminalLayer. Notes/AI slots and Terminal leaves
subscribe locally; VaultView and open-note callbacks stay unchanged.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ui): cut unnecessary AppView/VaultView/settings re-renders
Stabilize TopTabs close handler, memo AppHostTreeLayer, exclude accent from
settingsVersion, ignore connectionLogs off the logs section, share lastConnected
host refs, and keep rename dialog drafts local so chrome domain stays stable.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* chore: package size, dead code, and consolidation cleanup
Remove unused direct deps, exclude Vite-bundled renderer packages from
electron-builder, delete high-confidence dead code/no-op transfer warm
wiring, consolidate cloud provider IDs and KnownHost/SFTP helpers, and
land UI/AGENTS quick wins (rAF text batching, notes draft debounce,
streaming plain text, tempDirBridge, diagnostics adapter, External MCP
setters).
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: stabilize rAF text batching and diagnostics tests
Polyfill requestAnimationFrame for Node, flush pending text before
steer buffering, bypass rAF while steer is in flight, and stub
global localStorage for AI panel diagnostics adapter tests.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: correct import paths after application/state hook migrations
Migrated vault/AI/system hooks still used components/-relative imports;
point them at repo-root domain/components/types/lib instead.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: address Bugbot/Codex regressions from perf cleanup
- Keep blank Enter from closing RenameDraftDialog; only reset rename state after a non-empty submit
- Flush note drafts before vault mutations so pending title/body edits are not overwritten
- Re-apply appearanceChromeStore accent on appearanceTheme in Terminal, and keep layer themes unaccented
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(notes): flush draft before markdown export paths
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: keep editor-close hotkey ref fresh during render
Assign handleRequestCloseEditorTabRef in render instead of useEffect so
Cmd/Ctrl+W never hits the App stub before the effect runs.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: keep accent in chrome themes without TerminalLayer thrash
Restore accent in globalAppearance for chrome/injection consumers.
Keep resolveFocusedAppearance identity stable across accent drag via
accent ref, while Terminal leaf still re-applies appearanceChromeStore.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: keep compose chrome accent live and merge note renames
Subscribe theme-panel focusedAppearance to appearanceChromeStore so
compose-bar chrome updates during color-picker drag even when
resolveFocusedAppearance identity stays stable. Tree renames now merge
title into the post-flush note instead of replacing from a stale row.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: clear terminal accent when switching back to theme mode
Re-resolve appearanceTheme by catalog id before applyCustomAccent so a
stale baked custom cursor/selection cannot stick after accentMode returns
to theme while TerminalLayer memo ignores accent props.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: register unsaved prompt singleton during render
AppView close handlers call promptUnsavedChanges outside the old
render-prop. Assign the singleton during render so Cmd/Ctrl+W and tab
close never hit the pre-effect null window that auto-cancels.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: keep vault import hooks UI-free and flush notes on teardown
Move ImportOptions into application/state and inject a notifier so
useVaultImportHandlers no longer imports components. Notes drafts also
flush on pagehide/beforeunload when Electron tears down without React
unmount.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: move AI terminal session context builders into domain
buildAITerminalSessionInfo and AIPanelContext now live under domain/ so
application hooks no longer import TerminalLayerSupport and create a
UI → application → UI cycle.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: drop duplicate AIPanelContext type from TerminalLayerSupport
The type is re-exported from domain; the local definition conflicted.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: keep migrated state hooks free of UI-layer imports
Move aiChatStreamingSupport into infrastructure/ai and poll list helpers
into domain/systemManager so useAIChatStreaming / useSystemManager no
longer import from components. Leave thin re-exports at the old paths.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: move remaining migrated-hook deps out of components
Host-key verification types/helpers now live in domain/, and SFTP column
layout types live in application/state/sftp/columnLayout. Application
hooks no longer import those definitions from the UI layer.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: clear lint blockers and flush notes when panels hide
Move AI panel diagnostics persistence into application/state so
components stop importing localStorageAdapter. Flush note drafts when
retained NotesManager mounts become inactive, and silence related lint
warnings in theme/host-key helpers.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(notes): publish notesStore sync on vault note updates
updateNotes/updateNoteGroups now publishNotesSnapshot immediately so
AI/notes consumers do not briefly read a stale catalog after a hide
flush. Flush inactive drafts in useLayoutEffect before paint.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* feat(system): add GPU/NPU monitor tab when accelerators are detected
Probe nvidia-smi and npu-smi during System capabilities checks and show a
GPU sub-tab with utilization, memory/HBM, temperature, power, and compute
processes. Reuses the existing SSH exec + parse pattern (same approach as
open-source remote GPU monitors) without new dependencies.
Related to #2561
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system): address GPU monitor Bugbot findings
- Use PowerShell nvidia-smi collector for local Windows sessions
- Keep GPU tab in loading state while listAccelerators is pending
- Render compute processes even when device list is empty
- Stop treating Ascend HBM usage rate (%) as megabytes
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system): address Codex GPU collector review findings
- Wrap POSIX accelerator script with JSON.stringify so nested sed
quotes cannot break outer sh -c
- Parse Ascend proc-mem whitespace-delimited table rows
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system): show unknown GPU util/memory as -- not 0%
ResourceBar now treats null/undefined as unavailable, and the GPU
device cards pass through null metrics instead of coalescing to 0.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix: keep non-hibernated tabs active in background
* fix: scope background work to hibernation policy
* fix: bind background monitoring to its tab
* fix: measure hidden local workspaces
* fix(ui): replace native confirms in system manager panels
Windows native confirm dialogs steal focus after process/tmux/docker
destructive actions. Use SystemPanelConfirmDialog so the side panel
stays usable after confirm/cancel.
Fixes#2242
* fix(ui): clear system manager confirms on session switch
Drop pending process/docker confirms when sessionId changes so a
dialog opened for one host cannot execute against another.
* fix(ui): clear docker image action busy on session switch
Reset actionBusy when sessionId changes so a previous host's
in-flight remove/prune cannot leave the new session's confirm
dialog disabled. Guard stale completions with a generation counter.
* Fix tmux detach focus regression on Windows (#1587)
Replace native confirm with an in-app dialog and restore terminal cursor/focus after detach so sidebar tmux actions keep working.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Skip terminal refocus while app dialogs are open
Avoid deferred tmux detach focus from stealing Radix modal focus when users open the new-session dialog immediately after detach.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(system): increase process list limit and improve Docker detection for openEuler
Root cause analysis for issue #1453:
1. Process list limit too low: The `head -n 200` pipeline capped the process
list at 200 entries, causing the displayed count to mismatch `ps aux | wc -l`
on systems with many processes (common on openEuler servers with Docker,
databases, etc.). Increased limit from 200 to 2000 for both Linux/SSH
(ps) and Windows (PowerShell) backends.
2. Docker detection failure on openEuler 24.03: The capability probe only
relied on `docker info >/dev/null 2>&1`, which can fail even when Docker
is running due to:
- SSH exec channel environment differences vs interactive shell
- Docker socket permission variations in non-interactive sessions
- Different socket path configurations on openEuler
Added a fallback: if `docker info` fails but the Docker socket exists at
`/var/run/docker.sock`, Docker is still detected as available. This
matches the behavior of other SSH terminal clients.
* fix(system): also add Docker socket fallback to fallback probe script for consistency
* fix(system): remove hardcoded process list limit, add capability probe TTL, auto-reprobe on tab switch
Three remaining issues from PR #1455:
1. Remove hardcoded `head -n 2000` / `Select-Object -First 2000`
process list limits — virtual list handles rendering efficiently.
2. Add 60-second TTL to sessionCapabilitiesStore cache. `get()` returns
undefined for expired entries, forcing re-probe on next access.
`set()` always refreshes `probedAt`. Export CAPABILITIES_TTL_MS
constant for future tuning.
3. Auto-trigger capability re-probe when switching to Docker/Tmux tab
whose tool was previously reported unavailable — handles the case
where Docker/Tmux was installed after the last probe.
* fix: replace Docker socket -S check with -r for permission accuracy; sync capabilities TTL with process refresh interval
- Change [ -S /var/run/docker.sock ] to [ -r /var/run/docker.sock ] in
both the main capability probe script and the POSIX fallback (electron bridge).
-r verifies the socket exists AND the current user has read permission,
preventing false-positive Docker detection that leads to failed Docker ops.
- Remove hardcoded CAPABILITIES_TTL_MS (60s) from sessionCapabilitiesStore.
Store now computes expiresAt internally in set(ttlMs) and checks it in get()
without requiring a parameter at call sites.
- useSessionCapabilities and useSystemCapabilitiesWarmup accept a
capabilitiesTtlMs parameter derived from
terminalSettings.systemManagerProcessRefreshInterval (default 3s → 3 000ms).
- SystemManagerSidePanel passes the TTL from terminalSettings to the hook.
- TerminalLayerTabBridge passes TTL from stableRef settings to warmup hook.
- Fix missing refreshCapabilities destructuring in SystemManagerSidePanel.
* fix: restore process list safety cap (head -n 2000 / -First 2000)
Codex review flagged that removing the process list cap entirely could cause
timeout/maxBuffer issues on process-dense hosts. Restore head -n 2000 (POSIX)
and -First 2000 (Windows) as a safety guard with comments clarifying this is
NOT a functional limit — monitored processes still show accurate metrics.
* fix: hoist useRef/useEffect before early returns to fix React hook order violation
The useRef and useEffect for tab-switch re-probe were placed after early returns
for missing/disconnected sessions. When a session later connects, React discovers
new hooks that weren't registered before, causing hook order violation crashes.
Moved both hooks immediately after the resolvedTab computation, before any early
return path, satisfying React's Rules of Hooks.
* fix: change Docker detection from OR to AND (CLI + socket)
Both capability detection and fallback probe now require:
- docker CLI is on PATH (command -v docker)
- docker.sock is readable ([ -r /var/run/docker.sock ])
Previously used OR logic (docker info || socket readable),
which could report hasDocker=true even when docker CLI
was unavailable (e.g., non-login SSH shell).
Fixes#1453
* fix(system-monitor): prefer docker info, fallback to CLI+socket
Co-authored-by: Codex <codex@anthropic.com>
Changes:
- Line 12: Replace strict CLI+socket check with docker info first,
falling back to CLI+socket check only if docker info fails.
- Line 139: Same fix in the fallback probe script.
This handles DOCKER_HOST, Docker contexts, and rootless Docker.
* fix: notify subscribers when TTL expires in sessionCapabilitiesStore.get()
When capabilitiesBySessionId.get() finds an expired entry, it deletes the
entry but did not notify session subscribers. This caused components to
stale capabilities until the next successful set() call.
Now get() calls notifySession() on expiry, matching the notification
behavior already present in delete().
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.