Overview

Script API

/// <reference path="./.cursorcrane/cursorcrane.d.ts" />

Start a script#

Every script needs meta and run(ctx):

/** @type {CursorCrane.Meta} */
const meta = {
  type: "action",
  name: "Example",
  permissions: [],
};
 
/** @param {CursorCrane.Context} ctx */
async function run(ctx) {
  ctx.toast("Done");
}
meta field Purpose
type "action" performs a one-off action; "form" opens a form
presentation Optional for forms. "panel" suits continued work; "transient" closes on focus loss
name The script name shown in Cursor Crane
permissions The permissions the script requires

Permissions#

Available permissions are "accessibilityAPI", "clipboard", "keyboard", "mouse", and "shell".

An API cannot be used unless the script declares its required permission, so a script that reads elements and clicks them needs both accessibilityAPI and mouse. Declaring them up front also means anyone reading the script can see its reach at a glance.

These are separate from the macOS permissions the app itself needs, described in Permissions.

Find apps and windows#

Use ctx.applicationManager to inspect running apps:

Member Purpose
applications All available apps
getApplicationByBundleIdentifier(id) Finds an app by bundle identifier
getApplicationByPid(pid) Finds an app by process ID

Each Application has name, bundleIdentifier, and pid.

Use ctx.windowManager to find and switch windows:

Method Purpose
getWindowsByPid(pid) Gets an app's windows
getWindowsByBundleIdentifier(id) Gets windows by app
getWindowById(windowId) Finds a window by ID
getActiveWindow() Gets the window currently in use
getPreviousWindow() Gets the previously used window
activateWindow(windowId) Switches to a window

A Window has title, windowId, and its application.

Find and control interface elements#

ctx.elementInspector.getElementByPid(pid) returns an app's element entry point and requires accessibilityAPI. From there, use getWindows() to find the window, then query its buttons, text fields, and rows:

const application = ctx.elementInspector.getElementByPid(window.application.pid);
const root = application?.getWindows().find(item => item.windowId === window.windowId);
const saveButton = root?.queryElements('Button[title="Save"]')[0];

Selector syntax is covered in Element Selectors.

Element information#

Property Purpose
title The title provided by the element
displayTitle A title more suitable to show a person
label, description Additional information about the element
kind The element type, such as Button or TextField
windowId The ID of the containing window
rect / frame On-screen position and size

Traverse and query elements#

Method Purpose
getChildren() Gets direct children
getVisibleChildren() Gets children that are currently visible
getParent() Gets the parent element
queryElements(selector) Finds descendants matching a selector

Prefer getVisibleChildren() when you only care about what the user can see, since a large hidden subtree costs time to walk.

Next#