π File detail
utils/appleTerminalBackup.ts
π― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes markTerminalSetupInProgress, markTerminalSetupComplete, getTerminalPlistPath, backupTerminalPreferences, and checkAndRestoreTerminalBackup β mainly functions, hooks, or classes. Dependencies touch Node filesystem, Node OS/process metadata, and Node path helpers. It composes internal code from config, execFileNoThrow, and log (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import { stat } from 'fs/promises' import { homedir } from 'os' import { join } from 'path' import { getGlobalConfig, saveGlobalConfig } from './config.js' import { execFileNoThrow } from './execFileNoThrow.js'
π€ Exports (heuristic)
markTerminalSetupInProgressmarkTerminalSetupCompletegetTerminalPlistPathbackupTerminalPreferencescheckAndRestoreTerminalBackup
π External import roots
Package roots from from "β¦" (relative paths omitted).
fsospath
π₯οΈ Source preview
import { stat } from 'fs/promises'
import { homedir } from 'os'
import { join } from 'path'
import { getGlobalConfig, saveGlobalConfig } from './config.js'
import { execFileNoThrow } from './execFileNoThrow.js'
import { logError } from './log.js'
export function markTerminalSetupInProgress(backupPath: string): void {
saveGlobalConfig(current => ({
...current,
appleTerminalSetupInProgress: true,
appleTerminalBackupPath: backupPath,
}))
}
export function markTerminalSetupComplete(): void {
saveGlobalConfig(current => ({
...current,
appleTerminalSetupInProgress: false,
}))
}
function getTerminalRecoveryInfo(): {
inProgress: boolean
backupPath: string | null
} {
const config = getGlobalConfig()
return {
inProgress: config.appleTerminalSetupInProgress ?? false,
backupPath: config.appleTerminalBackupPath || null,
}
}
export function getTerminalPlistPath(): string {
return join(homedir(), 'Library', 'Preferences', 'com.apple.Terminal.plist')
}
export async function backupTerminalPreferences(): Promise<string | null> {
const terminalPlistPath = getTerminalPlistPath()
const backupPath = `${terminalPlistPath}.bak`
try {
const { code } = await execFileNoThrow('defaults', [
'export',
'com.apple.Terminal',
terminalPlistPath,
])
if (code !== 0) {
return null
}
try {
await stat(terminalPlistPath)
} catch {
return null
}
await execFileNoThrow('defaults', [
'export',
'com.apple.Terminal',
backupPath,
])
markTerminalSetupInProgress(backupPath)
return backupPath
} catch (error) {
logError(error)
return null
}
}
type RestoreResult =
| {
status: 'restored' | 'no_backup'
}
| {
status: 'failed'
backupPath: string
}
export async function checkAndRestoreTerminalBackup(): Promise<RestoreResult> {
const { inProgress, backupPath } = getTerminalRecoveryInfo()
if (!inProgress) {
return { status: 'no_backup' }
}
if (!backupPath) {
markTerminalSetupComplete()
return { status: 'no_backup' }
}
try {
await stat(backupPath)
} catch {
markTerminalSetupComplete()
return { status: 'no_backup' }
}
try {
const { code } = await execFileNoThrow('defaults', [
'import',
'com.apple.Terminal',
backupPath,
])
if (code !== 0) {
return { status: 'failed', backupPath }
}
await execFileNoThrow('killall', ['cfprefsd'])
markTerminalSetupComplete()
return { status: 'restored' }
} catch (restoreError) {
logError(
new Error(
`Failed to restore Terminal.app settings with: ${restoreError}`,
),
)
markTerminalSetupComplete()
return { status: 'failed', backupPath }
}
}