Utilities
runScript
Run AppleScript commands from your extension
runScript is a plain async function that wraps the macOS osascript process into a simple API for your extension.
Import
import { runScript } from "@eney/api";Usage
Execute a script to interact with a native macOS application:
const result = await runScript(`
tell application "Notes"
get name of first note
end tell
`);Signature
function runScript(script: string): Promise<string>When called with an AppleScript string, it resolves with the trimmed output (stdout) of the script, or rejects if the script fails.
Full example — send an email
This complete example shows how to build a mail-sending widget using AppleScript automation:
import { useState } from "react";
import { Form, Action, ActionPanel, runScript, useCloseWidget } from "@eney/api";
function SendMail(props: { to?: string; subject?: string; body?: string }) {
const closeWidget = useCloseWidget();
const [to, setTo] = useState(props.to ?? "");
const [subject, setSubject] = useState(props.subject ?? "");
const [body, setBody] = useState(props.body ?? "");
const [sending, setSending] = useState(false);
function escape(s: string) {
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
}
async function onSubmit() {
setSending(true);
try {
await runScript(`
tell application "Mail"
set msg to make new outgoing message with properties {
subject: "${escape(subject)}",
content: "${escape(body)}",
visible: false
}
tell msg
make new to recipient with properties {address: "${escape(to)}"}
end tell
send msg
end tell
`);
closeWidget(`Email sent to ${to}`);
} catch (error) {
setSending(false);
}
}
return (
<Form
actions={
<ActionPanel>
<Action.SubmitForm
title={sending ? "Sending..." : "Send"}
onSubmit={onSubmit}
style="primary"
isLoading={sending}
/>
</ActionPanel>
}
>
<Form.TextField name="to" label="To" value={to} onChange={setTo} />
<Form.TextField name="subject" label="Subject" value={subject} onChange={setSubject} />
<Form.RichTextEditor value={body} onChange={setBody} />
</Form>
);
}Always escape user input before interpolating into AppleScript strings. Replace \ with \\ and " with \". Unescaped input can break the script or cause unexpected behavior.
Error handling
runScript rejects if osascript exits with a non-zero code. Always wrap calls in try/catch:
try {
const result = await runScript(`tell application "Notes" to get name of first note`);
console.log(result);
} catch (error) {
// Handle AppleScript error
logger.error("AppleScript failed: %s", error.message);
}