Skip to content

Script API

This page organizes the script API by task. For live autocomplete and complete signatures in VSCode, add this line at the top of a script:

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

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 fieldPurpose
type"action" performs a one-off action; "form" opens a form.
presentationOptional for forms. "panel" suits continued work; "transient" closes on focus loss.
nameThe script name shown in Cursor Crane.
permissionsThe permissions required by the script.

Available permissions are "accessibilityAPI", "keyboard", and "mouse". An API cannot be used unless the script declares its required permission.

Use ctx.applicationManager to inspect running apps:

MemberPurpose
applicationsAll 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:

MethodPurpose
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.

Window has title, windowId, and its application.

ctx.elementInspector.getElementByPid(pid) gets an app’s interface-element entry point and requires accessibilityAPI. From there, use getWindows() to find the window, then find its buttons, text fields, and list 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];
PropertyPurpose
titleThe title provided by the element.
displayTitleA title that is more suitable to show to a person.
label, descriptionAdditional information about the element.
kindThe element type, such as Button or TextField.
windowIdThe ID of the window containing the element.
rect / frameThe element’s on-screen position and size.
MethodPurpose
getChildren()Gets direct children.
getVisibleChildren()Gets children that are currently visible.
getParent()Gets the parent element.
getFocusedWindow()Gets the app’s focused window.
getWindows()Gets the app’s windows.
getWindow()Gets the element’s containing window.
queryElements(selector, maxCount?)Searches all elements in a window. It traverses children and can block noticeably on a large hierarchy.
queryVisibleElement(selector, maxCount?)Searches only the currently visible content.
getStringValue()Gets the current value as text, such as the content of a text field.
getIntValue()Gets the current value as an integer.
getDoubleValue()Gets the current value as a floating-point number.

See Element Selectors for selector syntax.

These methods require accessibilityAPI and can be awaited:

MethodPurpose
performPress()Triggers the element’s main action.
setStringValue(value)Sets a new text value on an element.
setIntValue(value)Sets a new integer value on an element.
setDoubleValue(value)Sets a new floating-point value on an element.
performClick()Moves to an element and clicks it.
performMoveCursorTo()Moves to an element.
performShowMenu()Opens an element’s menu.
getActions()Lists the actions supported by an element.
performAction(identifier)Triggers a particular action.

Choose the getter or setter that matches the value type used by the element.

Requires keyboard. All three methods return a Promise:

await ctx.keyboard.pressKey("a", ["command"]);
await ctx.keyboard.releaseKey("a", ["command"]);
await ctx.keyboard.pressAndReleaseKey("return", []);

Use "shift", "control", "option", and "command" as modifiers.

Requires mouse:

MethodPurpose
moveTo(x, y)Moves the pointer smoothly.
warpTo(x, y)Moves the pointer immediately.
click(button, modifiers?)Clicks; 0 is left, 1 is right, and 2 is middle.
doubleClick(button, modifiers?)Double-clicks.
rightClick(modifiers?)Right-clicks.

Requires shell. execute(command) runs a non-interactive zsh command and returns its output:

const result = await ctx.shell.execute("git status --short");
if (result.exitCode === 0) {
ctx.toast(result.stdout || "Working tree is clean");
}

The result contains stdout, stderr, and exitCode. Commands share the script’s execution timeout, and output is limited to 1 MiB per stream.

Use ctx.toast(message) for brief feedback. ctx.toast.highlight(rect, text?, timeout?) highlights an area on screen and can show a short hint below it.

ctx.toast("Finished");
ctx.toast.highlight(element.rect, "Save button", 3);

ctx.logger.log(), error(), warn(), info(), and debug() write to the script log. They are useful for checking progress and errors while you develop a script.

A form script returns an array from run(ctx). Every item needs a unique id:

function run(ctx) {
return [
{
id: "selector",
kind: "textInput",
title: "Selector",
value: "Button",
},
{
id: "run",
kind: "button",
title: "Query",
submit: true,
onClick: formCtx => {
formCtx.toast(`Searching for ${formCtx.formData.selector}`);
},
},
];
}
kindCommon fieldsBest for
labeltext, value?Showing instructions or results.
numberInputtitle, value?, min?, max?, step?Entering a number.
textInputtitle, value?, placeholder?Entering one line of text.
selecttitle, value?, optionsChoosing from a list.
checkboxtitle?, value?Checking an option.
toggletitle?, value?Turning an option on or off.
buttontitle, submit?, onClick?Performing an action.

Editable items can provide onChange(newValue, ctx); buttons use onClick(ctx). Both can be async functions.

A form ctx also provides:

MemberPurpose
formDataReads the current form values.
updateForm(items)Replaces the form. A matching item without a new value preserves the person’s current input.
closeForm()Closes the current form.

People can use Tab, Shift + Tab, and arrow keys to move through a form. When a button is focused, Enter or Space activates it. A button marked submit: true can be activated from anywhere with Command + Enter.

Use try / catch while developing a script to show a clear message:

try {
await ctx.mouse.moveTo(100, 100);
} catch (error) {
ctx.toast(String(error));
}

If a script calls an API without the required permission, uses an invalid selector, or cannot reach its target, that call fails. Add a toast or a form message for common failures so the script stays easy to use.