Eney
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);
}