- event.preventDefault() must be called synchronously before the
async IPC call, otherwise the browser processes the default paste
action before we can intercept it
- When clipboard has no files (or on error), fall back to text paste
via pasteTextIntoTerminal since the default action was already
prevented
When pasting (Ctrl+V / right-click paste) in a local terminal,
if the clipboard contains files, insert their paths instead of
doing nothing.
- New hook useTerminalFilePaste: capture-phase paste listener
on terminal container, reads clipboard files via Electron bridge,
formats paths (spaces quoted, deduped), writes to session
- Updated useTerminalContextActions: right-click paste checks
clipboard files first, falls back to text paste
- New terminalHelpers.extractRootPathsFromClipboardFiles
- Tests: 9 unit tests for path extraction logic
- Verified via headless Chromium integration test (15 tests)
- Build: npm run build ✅, npm test ✅ (1899 pass)
* fix(linux): restore multi-size hicolor icons for Ubuntu launchers (#1340)
PR #816 set linux.icon to a single 1024px PNG, which regressed the #274
fix and left only hicolor/1024x1024 on .deb installs. Drop the override
so electron-builder uses build/icons again, regenerate those PNGs from the
tight-crop icon-win source, and add a helper script plus a config test.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(linux): set linux.icon to icons dir for proper multi-size hicolor icons (#1340)
---------
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>
* fix(ai): cap Catty agent request payload to prevent HTTP 413
Long-running chats accumulated full terminal tool outputs in SDK history
while token-based compaction only triggered near the model context window,
so nginx gateways could reject oversized JSON bodies before the model saw them.
Add a byte-budget pass that compresses verbose output, tail-preserving
truncation, and a safe sliding window before each Catty agent turn.
Fixes#1323
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ai): compaction was using unfiltered sdkMessages, fix didAdjust and emergency loop
* fix(ai): compact and retry oversized Catty requests
* fix(ai): preserve current input while guarding 413 retries
* fix(ai): avoid false 413 detection and fit oversized current input
* fix(ai): pair replayed tool results chronologically
---------
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>
Avoid accidentally persisting built-in editor as the default for all
extensionless files when double-clicking binaries without an extension.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce shared SettingCard and SettingsSection primitives so AI, SFTP,
system, and terminal tabs use the same white-card + row control pattern.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(sftp): add follow terminal directory mode for sidebar (#1266)
Add a toolbar toggle that keeps the side-panel SFTP browser synced with the linked SSH terminal cwd, inspired by MobaXterm's follow-folder behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(sftp): probe pwd after commands when follow mode lacks OSC 7
Add a deferred getSessionPwd fallback after terminal commands when follow-terminal-cwd is enabled and the shell did not report OSC 7, and fix settings sync hook dependencies.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(sftp): repair follow toggle UI and backend cwd sync fallback
Fix SftpPaneView memo skipping follow prop updates, probe fresh pwd when OSC 7 is missing, and broaden linked terminal session resolution for sidebar follow mode.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(sftp): harden follow sync after review findings
Reuse shouldFollowTerminalCwdNavigate in production path, re-read connection
after async cwd probe, skip redundant navigate on toggle, and only probe pwd
when the SFTP side panel is open.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Require bug/feature reports via issue forms with automated format checks, while accepting legacy Bug: titles from older app builds.
Co-authored-by: Cursor <cursoragent@cursor.com>
Add issue #1293 screenshot-exact cases for sudo/telnet autofill and
include English password in the handleOutput fast-path bypass.
Co-authored-by: Cursor <cursoragent@cursor.com>
Kylin Professional's sudo prompt doesn't include the [sudo] tag and
doesn't end with a colon. The existing regex patterns required either
[sudo] or a trailing colon, causing the autofill hint to never fire.
Changes:
- Make trailing colon optional in SUDO_PROMPT_PATTERN and
EXPLICIT_SUDO_PROMPT_PATTERN (terminalSudoAutofill.ts)
- Update fast path to not skip output containing Chinese password
keywords (密码/口令) that lack a colon
- Make trailing colon/angle-bracket optional in telnet username and
password prompt patterns (telnetAutoLogin.cjs)
- Also relax LAST_LOGIN_PATTERN for consistency
- Add Kylin-style test cases for both sudo and telnet auto-login
Expose whole-window transparency via setOpacity with settings and a top-bar quick control, persisting across restarts and syncing across windows.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: align top bar right-side icon buttons (#1298)
Unify AI/sync/theme/settings buttons to h-7 in one row aligned with tabs.
SyncStatusButton was h-8 and settings lived in a separate container, causing
misalignment. Preserve Windows spacing before window controls (mr-2).
Fixes#1298
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix: align window controls with utility icons in top bar
Merge window controls into the same row as utility buttons, match h-7 height, add left margin separation, and restore rectangular gray hover for all three buttons.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Expose data-section selectors for SFTP/side panel, split panes, and resizers
so custom CSS can target the correct regions. Clarify docs that
terminal-workspace-sidebar is focus-mode only.
Fixes#1301
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(ai): infer MIME type from file extension for YAML and other code files
When uploading YAML files (and other code/text files) via Electron,
file.type is often empty, causing the system to default to
'application/octet-stream'. AI providers reject this media type
with 'functionality not supported'.
Fix by inferring the correct MIME type from the file extension
when file.type is empty. Includes mappings for YAML, JSON, TOML,
shell scripts, and 50+ common code/text file extensions.
Fixes#1287
* fix(ai): use text/plain for all code/text files to ensure provider compatibility
Change all non-standard MIME types (text/x-*, application/x-*) to
text/plain for maximum provider compatibility. Anthropic and other
providers reject non-standard MIME types like application/x-yaml
with 'UnsupportedFunctionalityError'.
Changes:
- All code files (js, ts, py, rb, rs, go, java, c, cpp, sh, etc.) → text/plain
- Web component/stylesheet files (vue, svelte, scss, sass, less) → text/plain
- yaml/yml → text/plain (was application/x-yaml)
- dockerfile → text/plain (was text/x-dockerfile)
- Standard types (html, css, json, xml, csv, md, txt, pdf) preserved
* fix(telnet, sudo): support Chinese-localized prompts with full-width colons (#1286)
Two bugs in prompt detection for Chinese-locale users:
1. telnetAutoLogin: USERNAME_PROMPT_PATTERN, PASSWORD_PROMPT_PATTERN,
and LAST_LOGIN_PATTERN only matched half-width colon ':' or '>'.
Chinese-locale telnet prompts use full-width colon ':' (U+FF1A),
e.g. '登录:', '密码:'. Changed [:'>] to [::'|] in all three
patterns to accept both colon variants.
2. terminalSudoAutofill: EXPLICIT_SUDO_PROMPT_PATTERN required
'[sudo]' (closing bracket immediately after 'sudo'), but Chinese
sudo prompts use '[sudo: authenticate] 密码:' format where sudo
is followed by colon. Changed \[sudo\] to \[sudo[^\]]*\] to
match any '[sudo...]' variant, making the explicit (no-arm-needed)
hint detection work for Chinese locale.
Fixes#1286
* fix: restore OSC stripping pattern broken in previous commit
The regex negated character class [^\x07]* was truncated to just \x07,
breaking OSC sequence stripping (e.g. window title changes embedded in
terminal output). Restore the original negated class so stripTerminalControl-
Sequences continues to remove OSC title sequences before prompt detection.
This was caught by Codex review of PR #1288.
Sudo hints were flaky for manually typed commands: arming depends on
recognizing the submitted line as a command (recordedCommand), which is
unreliable while echo round-trips over SSH — so the hint sometimes didn't
fire for "sudo -i" / "sudo -s".
Explicit "[sudo] …" prompts are sudo-specific, so hint on them without
requiring an arm — reliable regardless of command recording. Bare
"Password:" still needs the arm window to avoid noise on unrelated prompts
(ssh, mysql). Filling still requires explicit Enter, so showing the hint
without arming stays safe. Added a colon fast-path so bulk output skips the
detection regex.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sudo autofill only read host.password and never resolved a host's reference
to a Keychain identity (host.identityId). When the account password lived in
a referenced identity, the autofill got nothing — while SSH login worked
because it goes through resolveHostAuth, which resolves the identity.
Add domain resolveHostAutofillPassword (same resolveHostAuth resolution:
identity.password ?? host.password, honoring savePassword and dropping
undecryptable placeholders) and use it as the terminal autofill password
source. Login and autofill now share one resolution path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Rework sudo password autofill from auto-fill to a Tabby-style hint + Enter to confirm. When a sudo command is armed and a password prompt appears, show a dimmed inline hint instead of sending the password; Enter pastes the saved password and submits, any other key dismisses it.
Confirmation removes the credential-leak class (nothing is sent without the user pressing Enter at a visible hint), so detection is relaxed to a broad match (Ubuntu/PAM bare "Password:", "[sudo] password for…", localized prompts) and the per-host toggle is removed — always available when the host has a saved password.
Safety guards:
- don't arm when the hint can't render (no overlay) so Enter isn't silently intercepted;
- swallow Escape/Backspace so the byte never reaches the no-echo prompt;
- clear the pending hint once output moves past the prompt (sudo timeout/failure/returns to shell) so a later Enter can't leak the password to the shell.
Implementation ~140 lines; full suite green; manually verified on a real Linux host.
Replace the command-rewriting scheme (inject sudo -p marker, sanitize the echo, Ctrl-U retype) with passive observation: arm a short window on a sudo command and fill the password when a real sudo prompt appears.
- Fixes the Ubuntu/PAM no-fill, the cursor jump below the prompt, and the typed-vs-autocomplete discrepancy from #1281.
- Detection requires the [sudo] tag, or a whole-line bare "Password:" / "密码:"; prefixed prompts (mysql -p "Enter password:", ssh "x@h's password:", psql "Password for user x:") are rejected so the sudo password can't leak to a child program when sudo's creds are warm.
- Disarms when a non-sudo command follows, so a stale window can't fill a later prompt.
Implementation: 322 -> ~140 lines.
The dedupe in startSession.cjs runs under `with(ctx)`, where ctx is wired
with sshBridge.cjs's own local findDefaultPrivateKey /
findAllDefaultPrivateKeys — not the sshAuthHelper.cjs copies. The
characterization test targeted the helper's exports, which the connect
path never calls (sshAuthHelper.findDefaultPrivateKey has no production
consumers at all), so it gave false confidence and the in-code comment
pointed at the wrong test.
Expose the local pair as _findDefaultPrivateKey / _findAllDefaultPrivateKeys
(matching the existing _-prefixed test-export convention) and retarget the
test at them, so it actually guards the path the optimization depends on.
Behavior is unchanged; the two local functions are verified equivalent.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each terminal that loads the WebGL addon holds a live WebGL context for
its whole lifetime, and all session panes stay mounted (hidden ones
off-screen). Batch connect therefore created a WebGL context per host up
front, contending for the GPU on the main thread — also the root of the
"garbled / 花屏" corruption in #1049/#1063. Defer WebGL creation for panes
that mount hidden (background tabs of a batch) and upgrade them on first
visibility via an idempotent ensureWebglRenderer(); a hidden pane renders
through xterm's DOM renderer until shown. Visible panes (single connect,
the active tab) keep creating WebGL immediately — unchanged behavior.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Batch-connecting N hosts called onConnect() in a synchronous forEach, so
all N terminals mounted in one React commit and each createXTermRuntime()
(which spins up a live WebGL context) ran back-to-back on the main
thread, freezing the UI until the whole batch finished (~2-3s per host,
linear). Spread the connects across frames via a small injectable-scheduler
helper: the first host still connects synchronously so its tab appears
immediately, the rest are deferred one step apart so no two heavy mounts
land on the same frame.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>