feat: shortcut recorder, configurable terminal toolbar, offline changelog
- Global shortcut setting: press-to-record input (Esc cancels, Backspace clears); requires a modifier or F-key so plain typing can't be hijacked - Terminal toolbar: three settings-gated buttons — session-log record (default off), open logs dir (default off), open working directory (default on, new; local sessions only, cwd tracked via cd/OSC 7) - Input suggestions + command history now default off, with a one-time migration that resets persisted true values for existing installs - Settings dialog: fix broken scrolling — antd v6 renamed the Tabs scroll container to .ant-tabs-body-holder; theme gallery drops its nested scroll (single outer scrollbar) - Offline changelog: CHANGELOG.md at repo root bundled via ?raw; About tab reads it first, network sources stay as fallback; scripts/sync-changelog.cjs merges RELEASE_NOTES.md per release (release.cjs fails without an entry) - commands.ts history prefs default aligned with new off-by-default
This commit is contained in:
1 parent
c1744184a3
commit
34094d607b
17 files changed
+319
-41
No files matched your search
@@ -376,7 +376,7 @@ function loadHistoryPrefs(): { historyEnabled: boolean; historyLimit: number } {
|
||||
try {
|
||||
const terminal = loadSettings().terminal
|
||||
return {
|
||||
historyEnabled: terminal.historyEnabled !== false,
|
||||
historyEnabled: terminal.historyEnabled === true,
|
||||
historyLimit: normalizeLimit(terminal.historyLimit)
|
||||
}
|
||||
} catch {
|
||||
|
||||
+15
-1
@@ -1,6 +1,7 @@
|
||||
import { app, ipcMain } from 'electron'
|
||||
import { app, ipcMain, shell } from 'electron'
|
||||
import fontList from 'font-list'
|
||||
import { homedir } from 'os'
|
||||
import { statSync } from 'fs'
|
||||
import { Ipc, type AppInfo, type LayoutMeta, type PtyCreateOptions } from '../shared/ipc'
|
||||
import type { HostKeyAction, SessionOpenOptions, SshConnection, SshConnectionInput } from '../shared/connections'
|
||||
import { getLayout, listLayouts, saveLayout, deleteLayout } from './layouts'
|
||||
@@ -181,4 +182,17 @@ export function registerIpc(): void {
|
||||
resolveCwd(current, arg)
|
||||
)
|
||||
ipcMain.handle(Ipc.CWD_REPORT, (_event, payload: string) => normalizeReportedCwd(payload))
|
||||
|
||||
// Open a local directory in the file manager. Validates the path is an
|
||||
// existing directory so renderer-supplied values can't open arbitrary files.
|
||||
ipcMain.handle(Ipc.CWD_OPEN, (_event, dir: unknown): boolean => {
|
||||
if (typeof dir !== 'string' || dir === '') return false
|
||||
try {
|
||||
if (!statSync(dir).isDirectory()) return false
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
void shell.openPath(dir)
|
||||
return true
|
||||
})
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import { app, ipcMain, powerSaveBlocker } from 'electron'
|
||||
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs'
|
||||
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import { Ipc } from '../shared/ipc'
|
||||
import {
|
||||
@@ -161,6 +161,32 @@ export function loadSettings(): AppSettings {
|
||||
|
||||
let settingsQueue: Promise<unknown> = Promise.resolve()
|
||||
|
||||
/**
|
||||
* One-time reset for existing installs: input suggestions and command history
|
||||
* are now off by default, but installs that upgraded from earlier versions
|
||||
* already have `true` persisted — flip those off exactly once, then leave a
|
||||
* marker so the user's later choices are never touched again.
|
||||
*/
|
||||
function migrateDefaultsOnce(): void {
|
||||
try {
|
||||
const flag = join(app.getPath('userData'), '.migrate-defaults-v2')
|
||||
if (existsSync(flag)) return
|
||||
const current = loadSettings()
|
||||
if (current.terminal.suggestEnabled || current.terminal.historyEnabled) {
|
||||
current.terminal.suggestEnabled = false
|
||||
current.terminal.historyEnabled = false
|
||||
mkdirSync(app.getPath('userData'), { recursive: true })
|
||||
const path = settingsPath()
|
||||
const tmp = `${path}.tmp`
|
||||
writeFileSync(tmp, JSON.stringify(current, null, 2), 'utf8')
|
||||
renameSync(tmp, path)
|
||||
}
|
||||
writeFileSync(flag, '', 'utf8')
|
||||
} catch {
|
||||
// best effort: a failed migration just keeps the old values
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize a settings mutation against every other writer. Each queued step
|
||||
* re-reads the file so the mutation applies on top of the latest state — a
|
||||
@@ -196,6 +222,7 @@ export function saveSettings(next: AppSettings): Promise<AppSettings> {
|
||||
}
|
||||
|
||||
export function registerSettingsIpc(): void {
|
||||
migrateDefaultsOnce()
|
||||
ipcMain.handle(Ipc.SETTINGS_GET, () => loadSettings())
|
||||
ipcMain.handle(Ipc.SETTINGS_SET, (_event, next: AppSettings) => saveSettings(next))
|
||||
}
|
||||
Reference in new issue
Block a user