* docs: losslessly shrink README images and mirror Trendshift badge
Recompress local images linked from the READMEs only when the file gets
smaller and decoded pixels stay identical. Copy the Trendshift badge from
README.md into the zh-CN, zh-TW, and ja-JP READMEs.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* docs: replace README screenshots with lossless WebP
Store the ten README screenshots as lossless WebP under docs/assets/readme
and point every language README at those files. Keep them out of app.asar.
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-manager): add container runtime switcher and kubectl pods
Keep the existing Docker tab and select docker, podman, nerdctl, or
Kubernetes from runtimes detected on the host. Kubernetes replaces the
switcher with context and namespace selectors in the same panel.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): address container runtime review findings
Move the runtime adapter into the domain layer, keep a context namespace
when namespace listing is forbidden, and emit PowerShell or cmd startup
commands for Kubernetes shell, logs, and describe.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): cover Windows container popups and stale namespaces
Run container shell and logs through the host shell's inspect wrapper on
PowerShell and cmd, and reset the namespace when a remembered Kubernetes
context is no longer present.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): parse kubectl JSON after banners and scope inspect cache
Skip bracketed banners before kubectl JSON, and include the container
runtime in image and container inspect cache keys.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): parse Podman image lists emitted as JSON arrays
Podman applies {{json .}} to the whole image slice. Accept that array,
including Names and byte sizes, and keep Docker's JSON lines.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): parse Podman stats arrays
Accept Podman's stats JSON array and its id/cpu_percent fields, and keep
Docker's one-stat-per-line output.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): list every Podman image tag
Expand each name in a Podman image's Names array into its own row so
extra tags stay visible and searchable.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): quote kubectl list and delete for the session shell
Namespace, pod, and delete commands follow PowerShell or cmd quoting when
the session shell is not POSIX, so apostrophes in a context name survive
local PowerShell.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): drop renamed runtime launch commands from shell history
Container popups now probe with _nc_rt_err and also cover podman, nerdctl,
and kubectl. History sanitizers still required _nc_docker_err, so those
launches stayed in persisted history. Confirm-dialog resets also follow the
selected runtime.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): sum Podman interface stats and quote kubectl for the executor
Podman {{json .}} stats keep per-interface counters on Network, so the
details panel now sums RxBytes and TxBytes. Background kubectl runs in
powershell.exe on local Windows even when the terminal is cmd, so those
commands are quoted for that executor instead of the interactive shell.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): remove a selected image tag instead of the shared id
Podman rows that share one image id were all deleted with rmi <id>, which
either fails while other tags remain or drops every name. Tagged rows now
run rmi repository:tag; dangling images still use the id.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): reject cmd kubectl arguments that contain percent signs
Interactive cmd.exe expands %VAR% inside double quotes, so a context such
as prod-%USERNAME% would be rewritten before kubectl sees it. Cmd popups
now refuse that argument. PowerShell quoting still preserves the percent.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* refactor(system-manager): move runtime selection into an application hook
Persisted source, context, and namespace state plus the kubectl discovery
effects now live in useContainerRuntimeSelection. DockerManagerTab only
renders the switcher and panels.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): offer kubectl shell only for running containers
Succeeded and failed pods have no running container, and a completed init
container cannot accept exec. Shell targets now come from container
statuses that are running; logs still include init containers.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): keep Windows popup commands out of shell history
PowerShell and cmd container popups inspect then run, and kubectl popups
are typed directly. History filtering only matched the POSIX sh -c wrapper,
so those launches were stored as user commands.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): mark Windows popups instead of matching kubectl syntax
Filtering kubectl --context logs and describe also dropped commands the
user typed. Windows popups now carry __NC_POPUP__, and ordinary kubectl
lines stay in history.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): reject cmd arguments that contain delayed-expansion marks
cmd.exe with /V:ON expands !VAR! inside double quotes. Contexts such as
prod!USER! are refused for cmd popups, same as percent signs.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): hide raw nerdctl and unreachable cluster errors
Only offer nerdctl after a short info probe succeeds, or when the failure is a socket permission error that sudo can still recover. Map dead containerd and unreachable kube API errors to short localized messages and keep the CLI text in the log.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): show terminating pods and ephemeral containers
A deletion timestamp is Terminating even while the phase is still Running. Ephemeral containers are included in the logs list, and a running one is a shell target.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): keep the runtime select on Kubernetes and avoid covering it
Kubernetes uses the same compact source menu as Docker, with context and namespace beside it. Shell popups open in the free part of the window so they no longer sit on top of the pod badges.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): restore the saved engine when Kubernetes disappears
A host that was on Podman before Kubernetes keeps Podman if kubectl is gone, instead of falling back to Docker and overwriting that choice.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): avoid the visible system panel when others are parked
A hidden parking-host panel can be the first system-manager match and
has a zero-size rect. Scan every match and pass the first panel that
actually has size so the shell popup still sits beside the open panel.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): keep a runtime choice across probe gaps and show podman ports
A failed nerdctl or kubectl probe was saved as the fallback engine, so the
previous choice never returned. Reconciliation now restores the stored source
when it is detected again, and automatic fallbacks are not written back.
Podman ps port mappings and exposed ports are formatted into the same display
string the container detail strip already shows.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): show a pod's Evicted reason
Pod status.reason is the eviction signal, while the phase stays Failed and
the container often reports Error. Use that reason after a container waiting
state and before the generic phase so the badge stays Evicted.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): keep an avoided shell popup inside the work area
When the source window sits partly off-screen, clamping a slot back onto
the display could cover the system panel, and the fallback then used the
raw slot origin. Place the popup in the on-screen part of the slot instead.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(system-manager): left-align the runtime selector row
The Kubernetes context, namespace, and runtime selects sat on the right of
the header, so they did not line up with the search field. Keep the same
padding, let the context select fill the remaining width, and leave the
runtime and namespace selects at their natural width.
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(ssh): add per-host TOTP with QR scan and MFA auto-fill
Store an optional otpauth TOTP secret on the host, encrypt and sync it
like a password, and auto-submit it once when a keyboard-interactive
prompt matches JumpServer or PAM TOTP text.
Closes#3323
Refs #3415
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): address Codex TOTP review findings
Reset authenticator editor state when the host changes, match custom
prompts with RE2, offer keyboard-interactive during connection tests
when TOTP is configured, and drop the secret when a host becomes a plugin.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): fill TOTP from the active prompt and ship re2js
Attach the connection's otpauth URI to the keyboard-interactive dialog
so Fill current code uses that attempt, including unsaved hosts. Move
re2js into production dependencies so packaged builds can match custom prompts.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): ship the shared TOTP runtime in packaged builds
electron-builder allowlists domain CommonJS modules individually, and
sshAuthHelper requires domain/totp.shared.cjs at load.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): save a pasted TOTP secret and ignore stale QR imports
Host save waits for the authenticator draft to validate before writing
the host. QR import completions from the previous host no longer change
busy state or errors on the newly selected host.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* test(host): ignore TOTP copy in the proxy command summary check
The assertion was matching the word secret in the authenticator UI.
It now checks that the ProxyCommand token itself is not rendered.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* feat(ssh): simplify host TOTP setup and type codes into the terminal
Move authenticator setup into a dialog so the host form keeps a single setting row, show keyboard-interactive prompts as field labels, and add a terminal context-menu action that types the current code without Enter.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): keep TOTP fill inside the auth dialog
Remove the terminal context-menu action. Offer the verification-code button on each non-password prompt, highlight OTP prompts, and never write the code into the password field.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): keep MFA instructions and scan every screen
Show keyboard-interactive name and instructions as plain text when they are not already the field label, and scan each unmatched desktop source once instead of repeating the first display.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): keep multiline MFA prompt directions
Show lines before the last keyboard-interactive prompt as plain-text guidance, and keep that last line as the field label.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): scan TOTP QR codes at each display's full size
Request a thumbnail as wide as the widest display and as tall as the tallest, so a portrait screen is not scaled into a landscape frame.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* fix(ssh): keep TOTP fill off menu prompts
Judge the fill action from the last prompt line and the shared menu, SMS, and confirmation exclusion list. Use a secondary button on the label row, and simplify the host authenticator row.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
Follow-up to #3773: Traditional Chinese (Taiwan) autocomplete description dictionary via OpenCC s2twp, lazy-loaded like zh-CN.
Closes#3157.
Real-app smoke PASS on 4d2bd32e.
Overlay bundled Fig description strings when the UI locale is zh-CN.
Cached specs stay in English, and missing entries fall back to the original text.
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* ci: hide only risky download links in issue comments
Stop deleting comments that merely mention an archive or executable
name. Match http(s) URLs whose path contains a risky extension, skip
the issue author as well as maintainers and bots, and minimize matches
as spam instead of deleting them.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
* ci: relay edited issue comments with truncated bodies
Forward issue_comment edited events and include comment identity,
association, timestamps, and bodies clipped to 4000 characters.
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: 陈大猫 <binaricat@users.noreply.github.com>
Keep renderer-only libraries available as development dependencies so Vite
bundles their runtime code without shipping their dependency trees again.
Exclude native compilation helpers from packaged resources, and prune
node-pty/serialport prebuilds for other platforms and architectures while
preserving matching universal binaries and rebuilt runtime files.
Validation:
- npm run lint; 33 packaging tests pass.
- npm run pack:dir, real packaged application UI, and 29 packaged runtime
smoke checks pass (SDK imports, PTY, serial port listing, SQLite query).
- All 999 UI files retain their code/content; differences are generated
asset references and the embedded dependency classification metadata.
- Dependency versions are unchanged.
- macOS arm64 app: 394,959,135 -> 360,740,625 bytes.
- macOS arm64 ZIP: 150,847,369 -> 143,151,622 bytes; ZIP integrity passes.
- Full suite: 14,035 pass, 36 skipped, 5 fail. The four FIDO helper failures
and transfer FileHandle-GC failure reproduce on unchanged main with Node 26.
* feat(ssh): restore FIDO2 security key support (#2308)
Consolidate the restored feature and its review fixes before rebasing onto current main. Original PR head: 5d0a0c6c9a550364d3ec5c2331395cedfc9ea7ae.
* fix(ssh): verify and repair FIDO authentication with simulated hardware
Preserve complete OpenSSH SK signature payloads, classify combined PIN/presence prompts correctly, expand IdentityFile tokens, retain certificate selectors, and route shared-agent signing prompts to their originating window. Dismiss prompts when notification helpers exit. Add a software SK provider and opt-in real OpenSSH integration coverage for both algorithms, certificates, SFTP, forwarding, and concurrent windows.
* refactor(ui): refine security key forms and authentication motion
Use shared Select and Switch controls, concise localized copy and compact token-based dialogs. Add scoped enter/exit, field transition and presence animations with reduced-motion support. Preserve raw prompt details and visible PIN errors.
* fix(ssh): align security key prompts with hardware presence and verify Docker logins
* fix(ui): keep security key dialog above its remounted overlay
* fix: address Codex review on PR #2823
* feat(ssh): guide security key recovery and explicit authentication fallback
* test(ssh): exercise security key authentication on native Windows
* test(ssh): verify Windows fixture signatures and explicit fallback
* test(ssh): configure Windows OpenSSH toolchain and document coverage
---------
Co-authored-by: netcatty-bot <308658023+netcatty-bot@users.noreply.github.com>
* feat(ai): scope external MCP approvals to connection or host
* test(ai): keep MCP fixture in Netcatty temp directory
* fix(ai): refine external MCP approval UI and grant safety
* fix(ai): wrap long approval targets and support Node 22
* fix(ai): keep automatic scripts in observer mode
* fix(sftp): release preflight markers after transfer
* fix(sftp): retain preflight cap through conflict resolution
* Keep SFTP preflight cap across panel remount
* Update worker terminal metadata expectations
* Persist SFTP preflight skip state across restart
* Limit persistent host approvals to saved hosts
* Scope host-open approvals to the selected saved host
* Exclude serial hosts from persistent approval scopes
Add a host and group toggle for bastions that allow one session channel per TCP connection. After the handshake, BHostSSH, TERM-SSHD, and CLOUDBILITY take that path automatically. File transfer uses a separate SFTP login, and the interactive terminal is not given another exec, SFTP, copy/split, or port-forward channel.
The manual toggle remains for bastions that still advertise OpenSSH.
fontLigatures already defaulted to on, but the terminal never loaded
the ligatures addon, so Fira Code and Maple Mono kept drawing != as two
cells. Activate the addon after open and before WebGL, and rebuild the
WebGL atlas when the setting changes so glyphs are not rasterized
without the calt feature.
The addon bundles lru-cache's node:diagnostics_channel import. Alias
that builtin to a no-op channel in the Vite renderer build and in the
Electron live-test bundles.
Closes#3543
Restore full height through the AppLockGate background wrapper, which otherwise lets the tray content collapse to about half of its window height. Preserve the existing lock-screen interaction restrictions.
Add real Electron regression coverage for repeated opening, session lists, lock/unlock, short windows, and Escape. Run it on macOS and Windows, including 100% and 200% device scale on Windows, and trigger it for the relevant renderer changes.
Fixes#3181
Claude Code Ajv does not load that dialect, so every triage died before
the model ran: no issue reply and no diagnosis. Strip $schema/$id before
--json-schema.
Route and several other jobs required $RUNNER_TEMP/ai-automation.cjs after
checking the helper out to the workspace, so GitHub never reached classify.
#3181 dispatch failed immediately with MODULE_NOT_FOUND.
Unindented Brave helper heredocs made GitHub reject ai-automation.yml.
The workflow never registered issues/opened, so new issues only got the
format check and template triage label.
Swap issue triage, implement, follow-up, and Codex-fix jobs from Cursor
CLI to Claude Code against Ollama Cloud (glm-5.3-flash:cloud). Isolated
research now uses Brave Search. Automation files and repo variables use
an ai- prefix; existing cursor-* HTML markers and cursor/issue-*
branches still parse so in-flight work is not reprocessed.