diff --git a/.github/workflows/resolutionFix.ts b/.github/workflows/resolutionFix.ts index 4c5dcee..0cbbbaa 100644 --- a/.github/workflows/resolutionFix.ts +++ b/.github/workflows/resolutionFix.ts @@ -3,7 +3,8 @@ import { execSync } from "child_process"; if (process.platform === "darwin") { try { execSync( - `"/Library/Application Support/VMware Tools/vmware-resolutionSet" 1920 1080` + `"/Library/Application Support/VMware Tools/vmware-resolutionSet" 1920 1080`, + { encoding: "utf8" } ); } catch (_) { // swallow diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ab27f3b..5e9bed6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,17 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-14, macos-15, macos-26, windows-2022, windows-2025] + os: + [ + macos-14, + macos-15, + macos-15-intel, + macos-26, + macos-26-intel, + windows-2022, + windows-2025, + windows-11-arm, + ] steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v6 @@ -31,7 +41,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-14] + os: [macos-latest] steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v6 @@ -49,7 +59,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [windows-2022, windows-2025] + os: [windows-2022, windows-2025, windows-11-arm] steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v6 diff --git a/package.json b/package.json index a8832fd..538dbec 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,10 @@ "ts-node": "^10.9.2", "typescript": "^5.6.2" }, + "optionalDependencies": { + "@guidepup/record": "^0.1.0" + }, "dependencies": { - "@guidepup/record": "^0.1.0", "chalk": "^4.0.0", "decompress": "^4.2.1", "https-proxy-agent": "^7.0.5", diff --git a/src/macOS/disableDictationInputAutoEnable.ts b/src/macOS/disableDictationInputAutoEnable.ts index fee3235..e584799 100644 --- a/src/macOS/disableDictationInputAutoEnable.ts +++ b/src/macOS/disableDictationInputAutoEnable.ts @@ -4,9 +4,12 @@ import { ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS } from "../errors"; export function disableDictationInputAutoEnable(): void { try { execSync( - "defaults write com.apple.HIToolbox AppleDictationAutoEnable -bool false" + "defaults write com.apple.HIToolbox AppleDictationAutoEnable -bool false", + { encoding: "utf8" } ); } catch (e) { - throw new Error(`${ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS}\n\n${e.message}`); + throw new Error( + `${ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS}\n\n${e.message}` + ); } } diff --git a/src/macOS/disableSplashScreenSystemDefaults.ts b/src/macOS/disableSplashScreenSystemDefaults.ts index 5800be8..80ee8ff 100644 --- a/src/macOS/disableSplashScreenSystemDefaults.ts +++ b/src/macOS/disableSplashScreenSystemDefaults.ts @@ -4,9 +4,12 @@ import { ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS } from "../errors"; export function disableSplashScreenSystemDefaults(): void { try { execSync( - "defaults write com.apple.VoiceOverTraining doNotShowSplashScreen -bool true" + "defaults write com.apple.VoiceOverTraining doNotShowSplashScreen -bool true", + { encoding: "utf8" } ); } catch (e) { - throw new Error(`${ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS}\n\n${e.message}`); + throw new Error( + `${ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS}\n\n${e.message}` + ); } } diff --git a/src/macOS/enableAppleScriptControlSystemDefaults.ts b/src/macOS/enableAppleScriptControlSystemDefaults.ts index 29fc4ba..3b16cb3 100644 --- a/src/macOS/enableAppleScriptControlSystemDefaults.ts +++ b/src/macOS/enableAppleScriptControlSystemDefaults.ts @@ -4,9 +4,14 @@ import { ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS } from "../errors"; export function enableAppleScriptControlSystemDefaults(): void { try { execSync( - "defaults write com.apple.VoiceOver4/default SCREnableAppleScript -bool true" + "defaults write com.apple.VoiceOver4/default SCREnableAppleScript -bool true", + { encoding: "utf8" }, ); + + return; } catch (e) { - throw new Error(`${ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS}\n\n${e.message}`); + throw new Error( + `${ERR_MACOS_UNABLE_UPDATE_SYSTEM_DEFAULTS}\n\n${e.message}`, + ); } } diff --git a/src/macOS/enableDoNotDisturb.ts b/src/macOS/enableDoNotDisturb.ts index 676d654..b9e791f 100644 --- a/src/macOS/enableDoNotDisturb.ts +++ b/src/macOS/enableDoNotDisturb.ts @@ -1,9 +1,9 @@ import { exec } from "child_process"; -import * as os from "os"; +import { promisify } from "util"; import { ERR_MACOS_FAILED_TO_ENABLE_DO_NOT_DISTURB } from "../errors"; import { runAppleScript } from "./runAppleScript"; -import { promisify } from "util"; import { retryOnError } from "./retryOnError"; +import { getPlatformVersionMajor } from "./getPlatformVersionMajor"; // REF: https://github.com/sindresorhus/do-not-disturb/issues/9 const enableFocusModeShellscript = `defaults write com.apple.ncprefs.plist dnd_prefs -data 62706C6973743030D60102030405060708080A08085B646E644D6972726F7265645F100F646E64446973706C6179536C6565705F101E72657065617465644661636574696D6543616C6C73427265616B73444E445875736572507265665E646E64446973706C61794C6F636B5F10136661636574696D6543616E427265616B444E44090808D30B0C0D070F1057656E61626C6564546461746556726561736F6E093341C2B41C4FC9D3891001080808152133545D6C828384858C9499A0A1AAACAD00000000000001010000000000000013000000000000000000000000000000AE && killall usernoted && killall ControlCenter`; @@ -39,7 +39,7 @@ my withTimeout(command, timeoutSeconds) const enableFocusModeVenturaAppleScript = ( locale: string, - platformMajor: number + platformMajor: number, ) => { // TODO: attempt to rewrite scripts without any locale specific instructions // so this setup can be used regardless of user locale preferences. @@ -97,7 +97,7 @@ my withTimeout(command, timeoutSeconds) }; export async function enableDoNotDisturb() { - const platformMajor = Number(os.version().split("Version ")[1].split(".")[0]); + const platformMajor = getPlatformVersionMajor(); try { if (platformMajor <= 20) { @@ -110,12 +110,14 @@ export async function enableDoNotDisturb() { // From MacOS 13 Ventura (Darwin 22) there is no known way to enable DND via system settings await retryOnError(() => - runAppleScript(enableFocusModeVenturaAppleScript(locale, platformMajor)) + runAppleScript( + enableFocusModeVenturaAppleScript(locale, platformMajor), + ), ); } } catch (e) { throw new Error( - `${ERR_MACOS_FAILED_TO_ENABLE_DO_NOT_DISTURB}\n\n${e.message}` + `${ERR_MACOS_FAILED_TO_ENABLE_DO_NOT_DISTURB}\n\n${e.message}`, ); } } diff --git a/src/macOS/getPlatformVersionMajor.ts b/src/macOS/getPlatformVersionMajor.ts new file mode 100644 index 0000000..2c3097b --- /dev/null +++ b/src/macOS/getPlatformVersionMajor.ts @@ -0,0 +1,4 @@ +import { version } from "os"; + +export const getPlatformVersionMajor = () => + Number(version().split("Version ")[1].split(".")[0]); diff --git a/src/macOS/isAppleScriptControlEnabled/enabledDefaults.ts b/src/macOS/isAppleScriptControlEnabled/enabledDefaults.ts index 92191e5..1ff18b6 100644 --- a/src/macOS/isAppleScriptControlEnabled/enabledDefaults.ts +++ b/src/macOS/isAppleScriptControlEnabled/enabledDefaults.ts @@ -1,16 +1,16 @@ -import { exec } from "child_process"; +import { execSync } from "child_process"; const VOICE_OVER_APPLESCRIPT_ENABLED_DEFAULTS = "defaults read com.apple.VoiceOver4/default SCREnableAppleScript"; -export async function enabledDefaults(): Promise { - return await new Promise((resolve) => { - exec(VOICE_OVER_APPLESCRIPT_ENABLED_DEFAULTS, (err, stdout) => { - if (err) { - resolve(false); - } else { - resolve(stdout.trim() === "1"); - } +export function enabledDefaults(): boolean { + try { + const result = execSync(VOICE_OVER_APPLESCRIPT_ENABLED_DEFAULTS, { + encoding: "utf8", }); - }); + + return result.trim() === "1"; + } catch { + return false; + } } diff --git a/src/macOS/setup.ts b/src/macOS/setup.ts index a7b44ad..3ec9d3f 100644 --- a/src/macOS/setup.ts +++ b/src/macOS/setup.ts @@ -1,5 +1,4 @@ import { platform, release } from "os"; -import { macOSRecord } from "@guidepup/record"; import chalk from "chalk"; import { checkVersion } from "./checkVersion"; import { enableAppleScriptControlSystemDefaults } from "./enableAppleScriptControlSystemDefaults"; @@ -36,18 +35,29 @@ export async function setup(): Promise { } else { handleWarning( "Ignoring TCC.db updates", - "If the necessary permissions have not been granted by other means, using this flag may result in your environment not being set up for reliable screen reader automation." + "If the necessary permissions have not been granted by other means, using this flag may result in your environment not being set up for reliable screen reader automation.", ); } const osName = platform(); const osVersion = release(); - const stopRecording = isRecorded - ? macOSRecord( - `./recordings/macos-guidepup-setup-${osName}-${osVersion}-${+new Date()}.mov` - ) - : () => null; + let stopRecording: () => void = () => null; + + if (isRecorded) { + try { + const { macOSRecord } = await import("@guidepup/record"); + + stopRecording = macOSRecord( + `./recordings/macos-guidepup-setup-${osName}-${osVersion}-${+new Date()}.mov`, + ); + } catch { + handleWarning( + "@guidepup/record not available", + "Recording will be skipped. This is expected on platforms without ffmpeg support (e.g., Windows ARM64).", + ); + } + } try { checkVersion(); @@ -77,9 +87,9 @@ export async function setup(): Promise { "Please complete remaining setup by following this guide:\n\n--> " + chalk.underline( chalk.bold( - "https://www.guidepup.dev/docs/guides/manual-voiceover-setup" - ) - ) + "https://www.guidepup.dev/docs/guides/manual-voiceover-setup", + ), + ), ); } finally { stopRecording(); diff --git a/src/macOS/updateTccDb.ts b/src/macOS/updateTccDb.ts index 389b0ff..85ba72c 100644 --- a/src/macOS/updateTccDb.ts +++ b/src/macOS/updateTccDb.ts @@ -194,7 +194,9 @@ export function updateTccDb(path: string): void { });`; try { - execSync(`sqlite3 "${path}" "${query}" >/dev/null 2>&1`); + execSync(`sqlite3 "${path}" "${query}" >/dev/null 2>&1`, { + encoding: "utf8", + }); } catch (e) { throw new Error( `${ERR_MACOS_UNABLE_TO_WRITE_USER_TCC_DB}\n\n${e.message}`,