feat: harden local shell, SFTP, and desktop session reliability

Finder-launched terminals now inherit a login PATH so tools like ollama resolve, destructive SFTP/editor actions require confirmation, and terminal search plus window dragging work again. SSH forwards and RDP sessions keep listeners and survive reconnect without FastPath crashes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Logan.LiandCursor committed 2026-08-16 16:08:11 +08:00
1 parent 188f3556ed
commit 08696896f9
223 files changed
+13493 -3423

No files matched your search

+107 -32
View File
@@ -90,6 +90,8 @@
"terminal": "Terminal",
"batch": "Thực thi hàng loạt",
"newTerminal": "Terminal mới",
"closeAria": "Đóng {{title}}",
"listAria": "Các tab đang mở",
"kind": {
"terminal": "Terminal",
"sftp": "SFTP",
@@ -105,7 +107,8 @@
"closeRight": "Đóng các tab bên phải",
"closeLeft": "Đóng các tab bên trái",
"closeAll": "Đóng tất cả",
"clone": "Nhân đôi tab"
"clone": "Nhân đôi tab",
"openSftp": "Mở SFTP"
}
},
"sidebar": {
@@ -151,7 +154,7 @@
"pro": {
"upgrade": "Nâng cấp Pro",
"feature": "Tính năng Pro",
"unlock": "Mở khóa {{feature}}",
"unlock": "Mở khóa tính năng nâng cao Pro",
"comingSoon": "Sắp ra mắt",
"activateSuccess": "Đã kích hoạt",
"activateFailed": "Kích hoạt thất bại",
@@ -160,28 +163,33 @@
"invalidLicense": "Kích hoạt thất bại: giấy phép không hợp lệ",
"goUpgrade": "Nâng cấp",
"haveLicense": "Có giấy phép? Kích hoạt",
"title": "OpsXShell Pro · Mở khóa các tính năng vận hành chuyên nghiệp",
"subtitleComingSoon": "{{feature}} sắp ra mắt · nâng cấp Pro để truy cập sớm",
"subtitleUnlock": "Đang mở khóa: {{feature}}",
"subtitleDefault": "Chuyển tiếp cổng, proxy, serial, AI, hàng loạt và phát sóng",
"title": "OpsXShell · Mở khóa Pro",
"subtitleComingSoon": "Tính năng nâng cao sắp có · nâng cấp Pro để dùng sớm",
"subtitleUnlock": "Đang mở khóa tính năng nâng cao",
"subtitleDefault": "Chuyển tiếp cổng, AI terminal, vận hành hàng loạt, danh sách host và máy tính từ xa trong Pro",
"activated": "Đã kích hoạt Pro",
"expiresAt": " · hợp lệ đến {{date}}",
"lifetime": " · giấy phép trọn đời",
"oneTimeFee": "Mua một lần · trọn đời trên thiết bị này · không cần đăng ký",
"oneTimeFee": "Miễn phí / Pro năm / Pro vĩnh viễn",
"pasteLicense": "Dán giấy phép",
"activateButton": "Kích hoạt",
"clearLicense": "Xóa giấy phép cục bộ",
"paymentNote": "Thanh toán được xử lý bởi Waffo; ứng dụng này không thu thập thông tin thẻ.",
"testDeviceId": "Môi trường thử nghiệm · ID thiết bị: {{deviceId}}",
"later": "Để sau",
"viewPro": "Xem Pro",
"wallComingSoonSuffix": " · sắp ra mắt",
"wallUnlock": "Mở khóa {{feature}}",
"wallMessageComingSoon": "Tính năng Pro này vẫn đang được phát triển. Nâng cấp để truy cập sớm.",
"wallMessageDefault": "Tính năng này yêu cầu OpsXShell Pro. Nâng cấp để sử dụng trên thiết bị này.",
"viewPro": "Xem gói Pro",
"wallComingSoonSuffix": "sắp có",
"wallUnlock": "Mở khóa tính năng nâng cao Pro",
"wallMessageComingSoon": "Khả năng này thuộc OpsXShell Pro và đang hoàn thiện. Nâng cấp Pro năm hoặc vĩnh viễn để dùng sớm.",
"wallMessageDefault": "Chuyển tiếp cổng, AI terminal, chạy hàng loạt, danh sách host và máy tính từ xa nằm trong Pro. Nâng cấp Pro năm hoặc vĩnh viễn để dùng trên máy này.",
"checkoutUnavailable": "Không thể thanh toán ({{status}})",
"emailLabel": "Email",
"emailRequired": "Nhập email trước khi thanh toán",
"claimPending": "Đang nhận giấy phép…",
"invalidKeyFormat": "Định dạng khóa không hợp lệ — dán khóa giấy phép LIC-",
"accountEmail": "Tài khoản: {{email}}",
"freeTier": "Miễn phí",
"proTier": "Pro",
"proTier": "Chuyên nghiệp",
"freeItems": {
"ssh": "Terminal SSH",
"sftp": "Quản lý tệp SFTP",
@@ -192,17 +200,38 @@
"proItems": {
"forward": "Chuyển tiếp cổng",
"proxy": "Proxy phiên / SOCKS",
"serial": "Terminal Serial",
"serial": "Terminal serial",
"ai": "Trợ lý AI terminal",
"batch": "Thực thi hàng loạt / đồng bộ phát sóng",
"broadcast": "Đồng bộ đầu vào phát sóng",
"importExport": "Nhập/xuất máy chủ hàng loạt",
"desktop": "Màn hình từ xa RDP / VNC"
}
"batch": "Chạy hàng loạt / đồng bộ phát sóng",
"broadcast": "Đồng bộ nhập phát sóng",
"importExport": "Nhập/xuất hàng loạt danh sách host",
"desktop": "Máy tính từ xa (RDP / VNC)"
},
"planYearly": "Pro theo năm",
"planYearlyDesc": "¥99 / năm · 2 thiết bị",
"planPerpetual": "Pro vĩnh viễn",
"planPerpetualDesc": "¥199 · 5 thiết bị · trọn đời",
"planTrial": "Pro dùng thử",
"devices": "Tối đa {{count}} thiết bị",
"goUpgradeYearly": "Mua Pro theo năm",
"goUpgradePerpetual": "Mua Pro vĩnh viễn",
"activatedYearly": "Đã kích hoạt Pro năm",
"activatedPerpetual": "Đã kích hoạt Pro vĩnh viễn",
"activatedTrial": "Đã kích hoạt Pro dùng thử",
"choosePlan": "Chọn: Miễn phí / Pro năm / Pro vĩnh viễn",
"planFreePrice": "¥0",
"planFreeDesc": "SSH · SFTP · terminal local",
"planFreeCta": "Gói hiện tại",
"planIncludesPro": "Đầy đủ tính năng Pro",
"planFree": "Miễn phí",
"subtitleUnlockDetail": "Khả năng liên quan: {{feature}}",
"wallUnlockComingSoon": "Tính năng nâng cao Pro sắp có",
"wallMessageComingSoonFeature": "「{{feature}}」 thuộc tính năng nâng cao Pro và đang hoàn thiện. Nâng cấp Pro năm hoặc vĩnh viễn để dùng sớm.",
"wallMessageFeature": "「{{feature}}」 thuộc tính năng nâng cao Pro. Nâng cấp Pro năm hoặc vĩnh viễn để dùng trên máy này."
},
"launcher": {
"title": "Khởi động nhanh",
"description": "Phiên, shell cục bộ và bảng điều khiển thiết bị",
"description": "Phiên, shell cục bộ, desktop, serial",
"cards": {
"quickConnect": {
"title": "Kết nối nhanh",
@@ -215,6 +244,14 @@
"serial": {
"title": "Terminal Serial",
"desc": "Tốc độ baud và cài đặt cổng"
},
"rdp": {
"title": "Máy tính RDP",
"desc": "Desktop Windows từ xa"
},
"vnc": {
"title": "Máy tính VNC",
"desc": "Desktop đồ họa từ xa"
}
},
"sectionLocalShell": "Shell cục bộ",
@@ -229,6 +266,7 @@
"forwardOpenRunning": "SOCKS5 đang chạy (:{{port}}) · nhấp để quản lý · nhấp chuột phải để sao chép",
"forwardStarted": "Đã bắt đầu chuyển tiếp",
"forwardStartedDynamic": "Đã khởi động SOCKS5: socks5://127.0.0.1:{{port}}",
"forwardResumed": "Đã khôi phục {{count}} chuyển tiếp cổng",
"socksStartFailed": "Khởi động thất bại: {{message}}",
"socksStopFailed": "Dừng thất bại: {{message}}",
"socksCopied": "Đã sao chép socks5://127.0.0.1:{{port}}"
@@ -249,7 +287,7 @@
"typeDynamic": "Động",
"running": "Đang chạy",
"socksProxy": "SOCKS5: 127.0.0.1:{{port}}",
"remoteToLocal": "Từ xa {{remote}} → cục bộ {{local}}",
"remoteToLocal": "từ xa {{bind}}:{{remote}} → {{host}}:{{local}}",
"stats": "{{connections}} kết nối · ↑{{up}} · ↓{{down}}",
"copyProxy": "Sao chép proxy",
"copyRule": "Nhân đôi quy tắc",
@@ -259,15 +297,15 @@
"delete": "Xóa",
"editTitle": "Sửa chuyển tiếp",
"addTitle": "Thêm chuyển tiếp",
"typeLocalDesc": "Cục bộ → từ xa",
"typeRemoteDesc": "Từ xa → cục bộ",
"typeLocalDesc": "Truy cập dịch vụ từ xa",
"typeRemoteDesc": "Công khai dịch vụ cục bộ",
"typeDynamicDesc": "SOCKS5",
"selectType": "Loại",
"drawerSubtitle": "Đường hầm qua phiên SSH hiện tại",
"ruleFields": "Chi tiết",
"dynamicHint": "SOCKS5 cục bộ tại 127.0.0.1:1080. Lưu lượng thoát qua địa chỉ IP công cộng của máy chủ SSH này.",
"dynamicSingleHint": "Một quy tắc Động cho mỗi máy chủ SSH, cổng cố định 1080.",
"dynamicPortHint": "If the port is busy, pick another local port (e.g. 1081).",
"dynamicHint": "SOCKS5 cục bộ (mặc định :1080). Lưu lượng ra qua SSH hiện tại.",
"dynamicSingleHint": "Mỗi SSH một quy tắc động; đổi cổng khi đã dừng.",
"dynamicPortHint": "Nếu bận, chọn cổng khác (vd. 1081).",
"ruleList": "Quy tắc",
"ruleListEmpty": "Chưa có quy tắc Cục bộ / Từ xa nào",
"addSection": "Thêm mới",
@@ -301,17 +339,30 @@
"internet": "Internet",
"localCaption": "Cục bộ: truy cập một cổng từ xa như thể nó là cổng cục bộ.",
"remoteCaption": "Từ xa: quyền truy cập từ xa được chuyển tiếp tới dịch vụ cục bộ.",
"dynamicCaption": "Động: máy này trở thành proxy SOCKS5 thoát qua IP công cộng của máy chủ SSH hiện tại."
"dynamicCaption": "Động: SOCKS5 cục bộ, ra ngoài qua SSH hiện tại."
},
"ruleName": "Tên",
"ruleNamePlaceholder": "vd. MySQL",
"localListenPort": "Cổng lắng nghe cục bộ",
"localListenPortHint": "Mặc định localhost — giống ssh -L cổng:…. Thường chỉ cần cổng.",
"localBindAdvanced": "Nâng cao: đổi bind cục bộ",
"localTargetPort": "Cổng đích cục bộ",
"remoteTargetPort": "Cổng đích từ xa",
"remoteTargetPort": "Cổng đích",
"remoteListenPort": "Cổng lắng nghe từ xa",
"remoteListenPortHint": "Mặc định localhost phía remote — giống ssh -R cổng:…. Thường chỉ cần nhập cổng.",
"remoteListenAddress": "Lắng nghe từ xa",
"remoteListenAddressPlaceholder": "127.0.0.1:18080",
"remoteListenAddressHint": "127.0.0.1 = chỉ máy remote; 0.0.0.0 = LAN remote (cần GatewayPorts).",
"errorRemoteListenAddress": "Nhập địa chỉ lắng nghe remote hợp lệ, vd. 127.0.0.1:18080",
"localTargetAddress": "Đích cục bộ / LAN",
"localTargetAddressPlaceholder": "127.0.0.1:8080",
"localTargetAddressHint": "Chuyển tới dịch vụ local/LAN, vd. 127.0.0.1:8080. Không dùng 0.0.0.0.",
"viaSessionRemote": "Lắng nghe trên {{target}} (mặc định localhost)",
"errorRemoteListenPort": "Nhập cổng lắng nghe từ xa hợp lệ (1–65535)",
"errorLocalTargetAddress": "Nhập đích local/LAN hợp lệ, vd. 127.0.0.1:8080",
"portPlaceholder": "vd. 3306",
"remoteHost": "Máy chủ từ xa",
"remoteHostPlaceholder": "localhost hoặc IP",
"remoteHost": "Máy đích",
"remoteHostPlaceholder": "127.0.0.1",
"socksRuleName": "Proxy SOCKS5",
"defaultLocalName": "Chuyển tiếp cục bộ",
"defaultRemoteName": "Chuyển tiếp từ xa",
@@ -325,11 +376,35 @@
"deleteConfirm": "Xóa quy tắc này?",
"errorNamePort": "Nhập tên và cổng hợp lệ (1–65535)",
"errorTargetPort": "Nhập cổng đích hợp lệ (1–65535)",
"errorRemoteHost": "Nhập máy chủ từ xa",
"errorRemoteHost": "Nhập máy đích (tính theo máy SSH)",
"errorNotConnected": "Chưa kết nối",
"errorStartFailed": "Khởi động thất bại",
"errorStopFailed": "Dừng thất bại",
"errorSocksRunning": "SOCKS5 đã đang chạy",
"copySuffix": "Sao chép"
"copySuffix": "Sao chép",
"remoteBindHint": "0.0.0.0 cần GatewayPorts; không có thì thường chỉ bind 127.0.0.1. Đích không được là 0.0.0.0.",
"localToRemote": "cục bộ {{bind}}:{{local}} → remote {{host}}:{{remote}}",
"localToRemotePort": "cục bộ :{{local}} → remote {{host}}:{{remote}}",
"remoteHostHint": "Theo máy SSH. Máy đó dùng 127.0.0.1, LAN dùng IP tới được. Không 0.0.0.0.",
"localBindHost": "Bind cục bộ",
"localBindHostPlaceholder": "127.0.0.1",
"localBindHostHint": "Mặc định chỉ máy này. 0.0.0.0 hoặc IP LAN để mạng truy cập.",
"errorTargetHostInvalid": "Đích không được 0.0.0.0 — dùng 127.0.0.1 hoặc IP nội bộ",
"listenAddress": "Lắng nghe cục bộ",
"listenAddressPlaceholder": "127.0.0.1:8080",
"listenAddressHint": "Mặc định chỉ máy này; 0.0.0.0 cho phép LAN.",
"targetAddress": "Đích từ xa",
"targetAddressPlaceholder": "127.0.0.1:80",
"targetAddressHint": "Theo góc nhìn máy SSH. Dịch vụ trên máy đó: 127.0.0.1:cổng.",
"errorListenAddress": "Nhập địa chỉ lắng nghe hợp lệ, vd. 127.0.0.1:8080",
"errorTargetAddress": "Nhập đích hợp lệ, vd. 127.0.0.1:80",
"targetAddressHintVia": "Qua {{target}}. Dịch vụ trên máy đó: 127.0.0.1:cổng (không mở cổng remote mới).",
"viaSession": "Qua phiên {{target}}",
"remoteToLocalPort": "remote :{{remote}} → {{host}}:{{local}}",
"remoteBindAdvanced": "Nâng cao: đổi bind phía remote",
"remoteBindHost": "Bind phía remote",
"remoteBindHostPlaceholder": "127.0.0.1",
"remoteBindHostHint": "Mặc định chỉ máy remote. 0.0.0.0 cần GatewayPorts; nếu không, hầu hết sshd vẫn chỉ bind 127.0.0.1.",
"remoteGatewayPortsWarning": "Đã yêu cầu lắng nghe 0.0.0.0 phía remote. Không có GatewayPorts, sshd thường vẫn chỉ bind 127.0.0.1."
}
}