From ed4e16b6256914a09a3eedecd837ac832803643f Mon Sep 17 00:00:00 2001 From: Jack Koch Date: Sun, 25 Jan 2026 13:46:29 -0500 Subject: [PATCH] Fix AppleScript execution for multi-line scripts The previous implementation replaced newlines with spaces when executing AppleScript, which caused syntax errors because AppleScript requires newlines or semicolons between statements. This fix: - Splits the script into individual lines - Passes each line as a separate -e argument to osascript - Properly escapes single quotes in the script content Fixes the "syntax error: Expected end of line but found 'tell'" error that occurred when creating notes. Co-Authored-By: Claude Opus 4.5 --- src/utils/applescript.ts | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) 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 });