diff --git a/src/utils/applescript.ts b/src/utils/applescript.ts index cfb2f1a..fcb3a43 100644 --- a/src/utils/applescript.ts +++ b/src/utils/applescript.ts @@ -1,6 +1,16 @@ import { execSync } from 'child_process'; import type { AppleScriptResult } from '@/types.js'; +/** + * Escapes a string for use in a shell single-quoted argument + * @param str - The string to escape + * @returns The escaped string safe for shell single quotes + */ +function escapeForShellSingleQuotes(str: string): string { + // In single quotes, only single quotes need escaping: ' -> '\'' + return str.replace(/'/g, "'\\''"); +} + /** * Executes an AppleScript command and returns the result * @param script - The AppleScript command to execute @@ -8,11 +18,20 @@ import type { AppleScriptResult } from '@/types.js'; */ export function runAppleScript(script: string): AppleScriptResult { try { - // Trim and sanitize the script - const sanitizedScript = script.trim().replace(/[\r\n]+/g, ' '); + // Split script into lines and build multiple -e arguments + // osascript requires each -e argument to be a separate line of the script + const lines = script + .trim() + .split(/\r?\n/) + .map(line => line.trim()) + .filter(line => line.length > 0); + + const args = lines + .map(line => `-e '${escapeForShellSingleQuotes(line)}'`) + .join(' '); // Execute the AppleScript command - const output = execSync(`osascript -e '${sanitizedScript}'`, { + const output = execSync(`osascript ${args}`, { encoding: 'utf8', timeout: 10000 // 10 second timeout });