source dump of claude code
at main 124 lines 2.8 kB view raw
1import { stat } from 'fs/promises' 2import { homedir } from 'os' 3import { join } from 'path' 4import { getGlobalConfig, saveGlobalConfig } from './config.js' 5import { execFileNoThrow } from './execFileNoThrow.js' 6import { logError } from './log.js' 7export function markTerminalSetupInProgress(backupPath: string): void { 8 saveGlobalConfig(current => ({ 9 ...current, 10 appleTerminalSetupInProgress: true, 11 appleTerminalBackupPath: backupPath, 12 })) 13} 14 15export function markTerminalSetupComplete(): void { 16 saveGlobalConfig(current => ({ 17 ...current, 18 appleTerminalSetupInProgress: false, 19 })) 20} 21 22function getTerminalRecoveryInfo(): { 23 inProgress: boolean 24 backupPath: string | null 25} { 26 const config = getGlobalConfig() 27 return { 28 inProgress: config.appleTerminalSetupInProgress ?? false, 29 backupPath: config.appleTerminalBackupPath || null, 30 } 31} 32 33export function getTerminalPlistPath(): string { 34 return join(homedir(), 'Library', 'Preferences', 'com.apple.Terminal.plist') 35} 36 37export async function backupTerminalPreferences(): Promise<string | null> { 38 const terminalPlistPath = getTerminalPlistPath() 39 const backupPath = `${terminalPlistPath}.bak` 40 41 try { 42 const { code } = await execFileNoThrow('defaults', [ 43 'export', 44 'com.apple.Terminal', 45 terminalPlistPath, 46 ]) 47 48 if (code !== 0) { 49 return null 50 } 51 52 try { 53 await stat(terminalPlistPath) 54 } catch { 55 return null 56 } 57 58 await execFileNoThrow('defaults', [ 59 'export', 60 'com.apple.Terminal', 61 backupPath, 62 ]) 63 64 markTerminalSetupInProgress(backupPath) 65 66 return backupPath 67 } catch (error) { 68 logError(error) 69 return null 70 } 71} 72 73type RestoreResult = 74 | { 75 status: 'restored' | 'no_backup' 76 } 77 | { 78 status: 'failed' 79 backupPath: string 80 } 81 82export async function checkAndRestoreTerminalBackup(): Promise<RestoreResult> { 83 const { inProgress, backupPath } = getTerminalRecoveryInfo() 84 if (!inProgress) { 85 return { status: 'no_backup' } 86 } 87 88 if (!backupPath) { 89 markTerminalSetupComplete() 90 return { status: 'no_backup' } 91 } 92 93 try { 94 await stat(backupPath) 95 } catch { 96 markTerminalSetupComplete() 97 return { status: 'no_backup' } 98 } 99 100 try { 101 const { code } = await execFileNoThrow('defaults', [ 102 'import', 103 'com.apple.Terminal', 104 backupPath, 105 ]) 106 107 if (code !== 0) { 108 return { status: 'failed', backupPath } 109 } 110 111 await execFileNoThrow('killall', ['cfprefsd']) 112 113 markTerminalSetupComplete() 114 return { status: 'restored' } 115 } catch (restoreError) { 116 logError( 117 new Error( 118 `Failed to restore Terminal.app settings with: ${restoreError}`, 119 ), 120 ) 121 markTerminalSetupComplete() 122 return { status: 'failed', backupPath } 123 } 124}