Skip to content

Commit dff869a

Browse files
authored
Merge pull request #51 from binaricat/copilot/add-keepalive-feature
Add SSH Keepalive Interval setting
2 parents be4da72 + 78d7b41 commit dff869a

7 files changed

Lines changed: 41 additions & 2 deletions

File tree

application/i18n/locales/en.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ const en: Messages = {
179179
'settings.terminal.localShell.startDir.placeholder': 'Home directory',
180180
'settings.terminal.localShell.startDir.notFound': 'Directory not found',
181181
'settings.terminal.localShell.startDir.isFile': 'Path is a file, not a directory',
182+
'settings.terminal.section.connection': 'Connection',
183+
'settings.terminal.connection.keepaliveInterval': 'Keepalive Interval',
184+
'settings.terminal.connection.keepaliveInterval.desc': 'How often (in seconds) to send SSH-level keepalive packets to server. Set to 0 to disable.',
182185

183186
// Settings > Shortcuts
184187
'settings.shortcuts.section.scheme': 'Hotkey Scheme',

application/i18n/locales/zh-CN.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,9 @@ const zhCN: Messages = {
817817
'settings.terminal.localShell.startDir.placeholder': '用户主目录',
818818
'settings.terminal.localShell.startDir.notFound': '目录不存在',
819819
'settings.terminal.localShell.startDir.isFile': '路径是文件,不是目录',
820+
'settings.terminal.section.connection': '连接',
821+
'settings.terminal.connection.keepaliveInterval': '会话保持间隔',
822+
'settings.terminal.connection.keepaliveInterval.desc': '向服务器发送 SSH 级别保活数据包的频率(秒)。设为 0 表示禁用。',
820823

821824
// Settings > Shortcuts
822825
'settings.shortcuts.section.scheme': '快捷键方案',

components/settings/tabs/SettingsTerminalTab.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,28 @@ export default function SettingsTerminalTab(props: {
580580
</div>
581581
</SettingRow>
582582
</div>
583+
584+
<SectionHeader title={t("settings.terminal.section.connection")} />
585+
<div className="space-y-0 divide-y divide-border rounded-lg border bg-card px-4">
586+
<SettingRow
587+
label={t("settings.terminal.connection.keepaliveInterval")}
588+
description={t("settings.terminal.connection.keepaliveInterval.desc")}
589+
>
590+
<Input
591+
type="number"
592+
min={0}
593+
max={3600}
594+
value={terminalSettings.keepaliveInterval}
595+
onChange={(e) => {
596+
const val = parseInt(e.target.value) || 0;
597+
if (val >= 0 && val <= 3600) {
598+
updateTerminalSetting("keepaliveInterval", val);
599+
}
600+
}}
601+
className="w-24"
602+
/>
603+
</SettingRow>
604+
</div>
583605
</SettingsTabContent>
584606
);
585607
}

components/terminal/runtime/createTerminalSessionStarters.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ export const createTerminalSessionStarters = (ctx: TerminalSessionStartersContex
343343
env: termEnv,
344344
proxy: proxyConfig,
345345
jumpHosts: jumpHosts.length > 0 ? jumpHosts : undefined,
346+
keepaliveInterval: ctx.terminalSettings?.keepaliveInterval,
346347
});
347348
};
348349

domain/models.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,9 @@ export interface TerminalSettings {
378378
// Local Shell Configuration
379379
localShell: string; // Path to shell executable (empty = system default)
380380
localStartDir: string; // Starting directory for local terminal (empty = home directory)
381+
382+
// SSH Connection
383+
keepaliveInterval: number; // Seconds between SSH-level keepalive packets (0 = disabled)
381384
}
382385

383386
export const DEFAULT_KEYWORD_HIGHLIGHT_RULES: KeywordHighlightRule[] = [
@@ -415,6 +418,7 @@ export const DEFAULT_TERMINAL_SETTINGS: TerminalSettings = {
415418
keywordHighlightRules: DEFAULT_KEYWORD_HIGHLIGHT_RULES,
416419
localShell: '', // Empty = use system default
417420
localStartDir: '', // Empty = use home directory
421+
keepaliveInterval: 0, // 0 = disabled (use SSH library defaults)
418422
};
419423

420424
export interface TerminalTheme {

electron/bridges/sshBridge.cjs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,9 @@ async function connectThroughChain(event, options, jumpHosts, targetHost, target
199199
port: jump.port || 22,
200200
username: jump.username || 'root',
201201
readyTimeout: 20000, // Reduced from 60s for faster failure detection
202-
keepaliveInterval: 10000,
202+
// Use user-configured keepalive interval from options (in seconds -> convert to ms)
203+
// If 0 or not provided, use 10000ms as default
204+
keepaliveInterval: options.keepaliveInterval && options.keepaliveInterval > 0 ? options.keepaliveInterval * 1000 : 10000,
203205
keepaliveCountMax: 3,
204206
algorithms: {
205207
// Prioritize fastest ciphers (GCM modes are hardware-accelerated)
@@ -355,7 +357,9 @@ async function startSSHSession(event, options) {
355357
username: options.username || "root",
356358
// `readyTimeout` covers the entire connection + authentication flow in ssh2.
357359
readyTimeout: 20000, // Fast failure for non-interactive auth
358-
keepaliveInterval: 10000,
360+
// Use user-configured keepalive interval (in seconds -> convert to ms)
361+
// If 0 or not provided, use 10000ms as default
362+
keepaliveInterval: options.keepaliveInterval && options.keepaliveInterval > 0 ? options.keepaliveInterval * 1000 : 10000,
359363
keepaliveCountMax: 3,
360364
algorithms: {
361365
// Prioritize fastest ciphers (GCM modes are hardware-accelerated)

global.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ interface NetcattySSHOptions {
6161
proxy?: NetcattyProxyConfig;
6262
// Jump hosts (bastion chain)
6363
jumpHosts?: NetcattyJumpHost[];
64+
// SSH-level keepalive interval in seconds (0 = disabled)
65+
keepaliveInterval?: number;
6466
}
6567

6668
interface SftpStatResult {

0 commit comments

Comments
 (0)