@rebind.gg/mcp-server 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebind.gg/mcp-server",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "MCP server exposing Rebind as computer-use tools: screenshot, verified click, type, key, scroll, and window control over the Remote Access protocol.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -53,7 +53,7 @@ async function main() {
53
53
 
54
54
  const session = new Session(client);
55
55
 
56
- const server = new McpServer({ name: "rebind", version: "0.1.4" });
56
+ const server = new McpServer({ name: "rebind", version: "0.1.5" });
57
57
 
58
58
  // REBIND_AGENT_LOG=<path>: opt-in telemetry — one JSONL line per tool call
59
59
  // ({ts, tool, ok, latency_ms, note}). No screenshot bytes, no user content.
@@ -101,7 +101,8 @@ async function main() {
101
101
  description:
102
102
  "Capture a display and return it as an image. The cursor is marked with a red crosshair. " +
103
103
  "All click/move coordinates you emit must be pixel coordinates in the MOST RECENT screenshot. " +
104
- "After every action, take a new screenshot and verify the action had the intended effect before continuing; if not, correct and retry.",
104
+ "After every action, take a new screenshot and verify the action had the intended effect before continuing; if not, correct and retry. " +
105
+ "Identify UI elements (labels, inputs, search boxes) before acting; prefer type/key over blind clicking.",
105
106
  inputSchema: {
106
107
  display: z
107
108
  .number()
@@ -224,7 +225,8 @@ async function main() {
224
225
  {
225
226
  description:
226
227
  "Capture a region of the last screenshot at full native resolution, for reading small text or inspecting small targets. " +
227
- "READ-ONLY: click coordinates still refer to the last full screenshot, not the zoomed image.",
228
+ "READ-ONLY: click coordinates still refer to the last full screenshot, not the zoomed image. " +
229
+ "Useful to check cursor-target alignment when a click missed.",
228
230
  inputSchema: {
229
231
  x: z
230
232
  .number()
@@ -288,7 +290,8 @@ async function main() {
288
290
  {
289
291
  description:
290
292
  "Move the mouse to a point in the last screenshot and click. The landing position is verified and corrected before pressing. " +
291
- "Prefer keyboard shortcuts (the key tool) for fiddly widgets like address bars and dropdowns.",
293
+ "Prefer keyboard shortcuts (the key tool) for fiddly widgets like address bars and dropdowns. " +
294
+ "Identify the target (read its label/text) before clicking, and confirm the effect with a screenshot after.",
292
295
  inputSchema: {
293
296
  x: z.number().describe("x in last-screenshot image pixels"),
294
297
  y: z.number().describe("y in last-screenshot image pixels"),
@@ -314,7 +317,8 @@ async function main() {
314
317
  "move_mouse",
315
318
  {
316
319
  description:
317
- "Move the mouse to a point in the last screenshot without clicking.",
320
+ "Move the mouse to a point in the last screenshot without clicking. " +
321
+ "If the response warns the cursor stopped short, take a fresh screenshot and retry.",
318
322
  inputSchema: {
319
323
  x: z.number().describe("x in last-screenshot image pixels"),
320
324
  y: z.number().describe("y in last-screenshot image pixels"),
@@ -337,7 +341,9 @@ async function main() {
337
341
  register(
338
342
  "type",
339
343
  {
340
- description: "Type text into the focused element via the keyboard.",
344
+ description:
345
+ "Type text into the focused element via the keyboard. " +
346
+ "Use LCtrl+A / LMeta+A (key tool) to select all first when replacing existing text.",
341
347
  inputSchema: { text: z.string() },
342
348
  },
343
349
  async ({ text: t }) => {
@@ -353,7 +359,8 @@ async function main() {
353
359
  {
354
360
  description:
355
361
  'Press a key or combo. Names: "Enter", "Escape", "Tab", "Backspace", arrows ("Up", "Down", "Left", "Right"), letters/digits, modifiers "LCtrl", "LAlt", "LShift", "LMeta". ' +
356
- 'Combos join with "+", e.g. "LCtrl+L" (focus address bar), "LCtrl+C", "LAlt+Tab".',
362
+ 'Combos join with "+", e.g. "LCtrl+L" (focus address bar), "LCtrl+C", "LAlt+Tab". ' +
363
+ 'Useful shortcuts: Space/PageDown/PageUp to scroll, LCtrl+F or LMeta+F to find text on the page, Escape to close dialogs.',
357
364
  inputSchema: { combo: z.string() },
358
365
  },
359
366
  async ({ combo }) => {
@@ -367,7 +374,8 @@ async function main() {
367
374
  "scroll",
368
375
  {
369
376
  description:
370
- "Scroll the mouse wheel at the current cursor position. Positive = up, negative = down.",
377
+ "Scroll the mouse wheel at the current cursor position. Positive = up, negative = down. " +
378
+ "Key shortcuts (Space, PageDown/PageUp, arrows) are often more reliable for page-level scrolling.",
371
379
  inputSchema: { clicks: z.number().int().describe("wheel clicks") },
372
380
  },
373
381
  async ({ clicks }) => {
@@ -397,8 +405,31 @@ async function main() {
397
405
  inputSchema: { handle: z.number() },
398
406
  },
399
407
  async ({ handle }) => {
400
- await client.windowActivate(handle);
401
- return text(`activated window ${handle}`);
408
+ // handle-based activation can raise without focusing on macOS; fall back
409
+ // to app-name activation (App.Activate, macOS-only, no-op elsewhere via
410
+ // pcall). Decided relay-side: this process may run on a different
411
+ // machine than the relay, so process.platform is the wrong signal.
412
+ const r = (await client.luaExec(`
413
+ local h = ${handle}
414
+ Window.Activate(h)
415
+ Sleep(150)
416
+ if Window.IsActive(h) then return { ok = true } end
417
+ local name
418
+ for _, w in ipairs(Window.List()) do
419
+ if w.handle == h then name = w.process; break end
420
+ end
421
+ if not name then return { ok = false, err = "window handle not found" } end
422
+ pcall(function() App.Activate(name) end)
423
+ Sleep(150)
424
+ return { ok = Window.IsActive(h), name = name }
425
+ `)) as { ok?: boolean; name?: string; err?: string };
426
+ if (r.ok)
427
+ return text(
428
+ `activated window ${handle}${r.name ? ` via app "${r.name}"` : ""}`,
429
+ );
430
+ return text(
431
+ `WARNING: window ${handle} ${r.err ?? "may not be focused"} — verify with active_window or a screenshot`,
432
+ );
402
433
  },
403
434
  );
404
435
 
@@ -445,7 +476,8 @@ async function main() {
445
476
  "reliable, and it sidesteps multi-monitor guessing. Use it to: launch apps (`System.ExecDetached(\"cmd\", {\"/c\",\"start\",\"\",url})`), " +
446
477
  "wait for and place windows on a known display (`local h=Window.Wait(title, ms); Window.Move(h, x, y, w, h)`), " +
447
478
  "run shell commands (`System.Exec(cmd) -> {exit,stdout,stderr}`), find UI by color (`Screen.SearchForColor(region,hex)`), " +
448
- "type, click, read pixels, manage processes. Namespaces: System, HID, Input, Screen, Window, Process, File, Clipboard, Net, Macro, Env, Log. " +
479
+ "type, click, read pixels, manage processes. Namespaces: System, HID, Input, Screen, Window, App, Process, File, Clipboard, Net, Macro, Env, Log; global Sleep(ms). " +
480
+ "Call `lua_docs` for exact signatures BEFORE writing nontrivial scripts — do not guess APIs. " +
449
481
  "Fall back to `screenshot` only for genuinely visual reasoning the script cannot resolve. End the script with `return <value>` to get data back.",
450
482
  inputSchema: {
451
483
  source: z
@@ -461,6 +493,19 @@ async function main() {
461
493
  },
462
494
  );
463
495
 
496
+ register(
497
+ "lua_docs",
498
+ {
499
+ description:
500
+ "Return the full Luau SDK type definitions for run_lua: every namespace, function signature, and type. " +
501
+ "Read this before writing any nontrivial run_lua script instead of guessing APIs.",
502
+ },
503
+ // byte-identical copy of packages/lua-sdk/types/rebind.d.luau, shipped in
504
+ // the package; tests/lua-docs-sync.test.ts guards against drift
505
+ async () =>
506
+ text(await Bun.file(new URL("./rebind.d.luau", import.meta.url)).text()),
507
+ );
508
+
464
509
  await server.connect(new StdioServerTransport());
465
510
  // stdout carries the MCP protocol — log to stderr only
466
511
  console.error(
@@ -0,0 +1,698 @@
1
+ -- rebind sdk type definitions for luau language server
2
+ -- provides autocomplete, hover docs, and type checking for all sdk namespaces.
3
+ -- reference this file in your .luaurc: { "languageMode": "strict", "paths": ["types"] }
4
+
5
+ -- handle types
6
+
7
+ export type TaskHandle = {
8
+ Cancel: (self: TaskHandle) -> (),
9
+ IsRunning: (self: TaskHandle) -> boolean,
10
+ }
11
+
12
+ export type TimerHandle = {
13
+ Cancel: (self: TimerHandle) -> (),
14
+ Pause: (self: TimerHandle) -> (),
15
+ Resume: (self: TimerHandle) -> (),
16
+ }
17
+
18
+ export type MacroHandle = {
19
+ Stop: (self: MacroHandle) -> (),
20
+ Pause: (self: MacroHandle) -> (),
21
+ Resume: (self: MacroHandle) -> (),
22
+ IsPlaying: (self: MacroHandle) -> boolean,
23
+ GetProgress: (self: MacroHandle) -> number,
24
+ }
25
+
26
+ export type BindHandle = {
27
+ unbind: (self: BindHandle) -> (),
28
+ disable: (self: BindHandle) -> (),
29
+ enable: (self: BindHandle) -> (),
30
+ enabled: boolean,
31
+ }
32
+
33
+ export type ServerHandle = {
34
+ port: number,
35
+ Stop: (self: ServerHandle) -> (),
36
+ }
37
+
38
+ -- WebSocket: server-side per-connection handle passed to OnConnect/OnMessage/OnClose.
39
+ -- `id` is a monotonic identifier unique to this connection.
40
+ export type WsClient = {
41
+ id: number,
42
+ Send: (self: WsClient, text: string) -> (),
43
+ SendBinary: (self: WsClient, bytes: string) -> (),
44
+ Close: (self: WsClient) -> (),
45
+ }
46
+
47
+ -- WebSocket: server handle returned by Net.WSListen.
48
+ export type WsServerHandle = {
49
+ port: number,
50
+ Broadcast: (self: WsServerHandle, text: string) -> (),
51
+ BroadcastBinary: (self: WsServerHandle, bytes: string) -> (),
52
+ ClientCount: (self: WsServerHandle) -> number,
53
+ Stop: (self: WsServerHandle) -> (),
54
+ }
55
+
56
+ -- WebSocket: outbound-connection handle returned by Net.WSConnect.
57
+ export type WsConnectHandle = {
58
+ Send: (self: WsConnectHandle, text: string) -> (),
59
+ SendBinary: (self: WsConnectHandle, bytes: string) -> (),
60
+ Close: (self: WsConnectHandle) -> (),
61
+ }
62
+
63
+ -- WebSocket: server event-handler table passed to Net.WSListen.
64
+ -- All fields are optional; handlers that are absent are never called.
65
+ export type WsListenHandlers = {
66
+ OnConnect: ((client: WsClient) -> ())?,
67
+ OnMessage: ((client: WsClient, payload: string, isBinary: boolean) -> ())?,
68
+ OnClose: ((client: WsClient) -> ())?,
69
+ }
70
+
71
+ -- WebSocket: client event-handler table passed to Net.WSConnect.
72
+ export type WsConnectHandlers = {
73
+ OnOpen: (() -> ())?,
74
+ OnMessage: ((payload: string, isBinary: boolean) -> ())?,
75
+ OnClose: (() -> ())?,
76
+ }
77
+
78
+ export type PipeHandle = {
79
+ name: string,
80
+ size: number,
81
+ capacity: number,
82
+ Read: (self: PipeHandle) -> string?,
83
+ Write: (self: PipeHandle, data: string) -> (),
84
+ Close: (self: PipeHandle) -> (),
85
+ }
86
+
87
+ -- data types
88
+
89
+ export type WindowInfo = {
90
+ title: string,
91
+ process: string,
92
+ x: number,
93
+ y: number,
94
+ width: number,
95
+ height: number,
96
+ }
97
+
98
+ export type WindowEntry = {
99
+ handle: number,
100
+ title: string,
101
+ process: string,
102
+ x: number,
103
+ y: number,
104
+ width: number,
105
+ height: number,
106
+ }
107
+
108
+ export type WindowPos = {
109
+ x: number,
110
+ y: number,
111
+ width: number,
112
+ height: number,
113
+ }
114
+
115
+ export type MousePos = {
116
+ x: number,
117
+ y: number,
118
+ }
119
+
120
+ export type ModifierState = {
121
+ ctrl: boolean,
122
+ shift: boolean,
123
+ alt: boolean,
124
+ win: boolean,
125
+ }
126
+
127
+ export type HttpResponse = {
128
+ status: number,
129
+ body: string,
130
+ headers: { [string]: string },
131
+ }
132
+
133
+ -- `body` may contain arbitrary bytes (Luau strings are byte strings).
134
+ export type HttpRequest = {
135
+ method: string,
136
+ path: string,
137
+ body: string,
138
+ headers: { [string]: string },
139
+ }
140
+
141
+ -- `body` may contain arbitrary bytes; set a Content-Type header for binary.
142
+ export type HttpResponseSpec = {
143
+ status: number?,
144
+ body: string?,
145
+ headers: { [string]: string }?,
146
+ }
147
+
148
+ export type HttpOptions = {
149
+ timeout: number?,
150
+ }
151
+
152
+ export type HttpRequestOptions = {
153
+ method: string,
154
+ url: string,
155
+ body: string?,
156
+ headers: { [string]: string }?,
157
+ timeout: number?,
158
+ }
159
+
160
+ -- macro action types
161
+
162
+ export type MacroMoveAction = {
163
+ x: number,
164
+ y: number,
165
+ delay: number,
166
+ }
167
+
168
+ export type MacroExplicitAction = {
169
+ action: string,
170
+ code: string?,
171
+ dx: number?,
172
+ dy: number?,
173
+ x: number?,
174
+ y: number?,
175
+ text: string?,
176
+ amount: number?,
177
+ holdMs: number?,
178
+ charDelay: number?,
179
+ delay: number,
180
+ }
181
+
182
+ export type MacroAction = MacroMoveAction | MacroExplicitAction
183
+
184
+ -- ui widget option types
185
+
186
+ export type ToggleOpts = {
187
+ label: string?,
188
+ }
189
+
190
+ export type SliderOpts = {
191
+ label: string?,
192
+ min: number?,
193
+ max: number?,
194
+ step: number?,
195
+ suffix: string?,
196
+ tooltip: string?,
197
+ group: string?,
198
+ tab: string?,
199
+ showIf: string?,
200
+ }
201
+
202
+ export type KeybindOpts = {
203
+ label: string?,
204
+ }
205
+
206
+ export type SelectOpts = {
207
+ label: string?,
208
+ }
209
+
210
+ export type TextOpts = {
211
+ label: string?,
212
+ placeholder: string?,
213
+ maxLength: number?,
214
+ tooltip: string?,
215
+ group: string?,
216
+ tab: string?,
217
+ showIf: string?,
218
+ }
219
+
220
+ export type ColorOpts = {
221
+ label: string?,
222
+ tooltip: string?,
223
+ group: string?,
224
+ tab: string?,
225
+ showIf: string?,
226
+ }
227
+
228
+ export type RecordOpts = {
229
+ ignore_mouse: boolean?,
230
+ ignore_keyboard: boolean?,
231
+ precision: string?,
232
+ }
233
+
234
+ -- ui proxy: returned by UI.Schema, supports dynamic field access
235
+ -- cfg.key reads the current value, cfg.key = value writes it
236
+ export type UiProxy = { [string]: any }
237
+
238
+ -- bind config for table-style binding
239
+ export type BindConfig = {
240
+ when: (() -> boolean)?,
241
+ action: (() -> boolean?)?,
242
+ release: (() -> ())?,
243
+ }
244
+
245
+ -- runtime identity table
246
+ export type RebindInfo = {
247
+ min_sdk: string,
248
+ tick_rate: number,
249
+ version: string,
250
+ name: string,
251
+ runtime_uuid: string,
252
+ id: string?,
253
+ instance: string,
254
+ }
255
+
256
+ -- global functions
257
+
258
+ declare function Run(fn: () -> ()): TaskHandle
259
+ -- RunAsync was removed. Use Run() directly.
260
+ declare function Sleep(ms: number): ()
261
+ declare function After(ms: number, fn: () -> ()): TaskHandle
262
+ declare function Async(fn: (...any) -> ...any): (...any) -> ...any
263
+ declare function print(...: any): ()
264
+ declare function require(module: string): any
265
+
266
+ -- global tables
267
+
268
+ declare _REBIND: RebindInfo
269
+
270
+ -- system namespace
271
+
272
+ export type ExecOptions = {
273
+ timeout: number?,
274
+ cwd: string?,
275
+ }
276
+
277
+ export type ExecResult = {
278
+ exit: number,
279
+ stdout: string,
280
+ stderr: string,
281
+ }
282
+
283
+ export type ExecDetachedOptions = {
284
+ cwd: string?,
285
+ }
286
+
287
+ declare System: {
288
+ Time: () -> number,
289
+ Mouse: () -> (number, number),
290
+ Screen: () -> (number, number),
291
+ Window: () -> WindowInfo,
292
+ Exec: (cmd: string, options: ExecOptions?) -> ExecResult,
293
+ ExecDetached: (cmd: string, args: { string }?, options: ExecDetachedOptions?) -> number,
294
+ }
295
+
296
+ -- hid namespace
297
+
298
+ declare HID: {
299
+ Down: (code: string) -> (),
300
+ Up: (code: string) -> (),
301
+ Press: (code: string, holdMs: number?) -> (),
302
+ -- fire a chord in one synchronous call (press L→R, release R→L). no sleep,
303
+ -- so callable directly from a Bind action / OnDown. modifier tokens accept
304
+ -- macOS aliases: "cmd", "opt"/"option", plus "ctrl"/"shift"/"alt"/"win".
305
+ Combo: (code: string) -> (),
306
+ -- instant whole-string insertion (native; no coroutine). For a human-like
307
+ -- per-character typewriter effect use Typewriter (coroutine-only).
308
+ Type: (text: string) -> (),
309
+ Typewriter: (text: string, delayMs: number?) -> (),
310
+ Move: (dx: number, dy: number) -> (),
311
+ MoveTo: (x: number, y: number) -> (),
312
+ Scroll: (amount: number) -> (),
313
+ SetMouseMode: (mode: string) -> (),
314
+ GetMouseMode: () -> string,
315
+ }
316
+
317
+ -- input namespace
318
+
319
+ declare Input: {
320
+ IsDown: (code: string) -> boolean,
321
+ GetDuration: (code: string) -> number,
322
+ GetActiveKeys: () -> { string },
323
+ GetMousePos: () -> MousePos,
324
+ GetModifiers: () -> ModifierState,
325
+ }
326
+
327
+ -- ui namespace
328
+
329
+ declare UI: {
330
+ Schema: (descriptors: { [string]: any }) -> UiProxy,
331
+ Toggle: (default: boolean, opts: ToggleOpts?) -> any,
332
+ Slider: (default: number, opts: SliderOpts?) -> any,
333
+ Keybind: (default: string, opts: KeybindOpts?) -> any,
334
+ Select: (default: string, choices: { string }, opts: SelectOpts?) -> any,
335
+ Text: (default: string, opts: TextOpts?) -> any,
336
+ Color: (default: string, opts: ColorOpts?) -> any,
337
+ Get: (id: string) -> any,
338
+ Set: (id: string, value: any) -> (),
339
+ GetAll: () -> { [string]: any },
340
+ GetSchema: () -> { any },
341
+ Notify: (text: string, variant: string?) -> (),
342
+ }
343
+
344
+ -- bind namespace (callable table)
345
+
346
+ declare Bind: typeof(setmetatable({} :: {
347
+ Toggle: (key: string, uiId: string) -> BindHandle,
348
+ Remap: (from: string, to: string) -> BindHandle,
349
+ }, {} :: {
350
+ __call: (self: any, key: string, config: (() -> boolean?) | BindConfig) -> BindHandle,
351
+ }))
352
+
353
+ -- timer namespace
354
+
355
+ declare Timer: {
356
+ After: (ms: number, callback: () -> ()) -> TimerHandle,
357
+ Every: (ms: number, callback: () -> ()) -> TimerHandle,
358
+ CancelAll: () -> (),
359
+ }
360
+
361
+ -- macro namespace
362
+
363
+ declare Macro: {
364
+ Play: (macro: { MacroAction }, speed: number?, mode: string?) -> MacroHandle,
365
+ StopAll: () -> (),
366
+ Record: (options: RecordOpts?) -> (),
367
+ Finish: () -> { MacroAction },
368
+ Stream: (macro: { MacroAction }) -> (),
369
+ Abort: () -> (),
370
+ }
371
+
372
+ -- math namespace
373
+
374
+ declare Math: {
375
+ Random: (min: number, max: number) -> number,
376
+ Gaussian: (mean: number, stdDev: number) -> number,
377
+ Scale: (macro: { MacroAction }, xFactor: number, yFactor: number) -> { MacroAction },
378
+ Spline: (macro: { MacroAction }, tension: number) -> { MacroAction },
379
+ Resample: (macro: { MacroAction }, intervalMs: number) -> { MacroAction },
380
+ TimeComp: (macro: { MacroAction }, targetMs: number) -> { MacroAction },
381
+ Interpolate: (macro: { MacroAction }, intervalMs: number, mode: string?) -> { MacroAction },
382
+ }
383
+
384
+ -- log namespace
385
+
386
+ declare Log: {
387
+ Info: (msg: string) -> (),
388
+ Warn: (msg: string) -> (),
389
+ Error: (msg: string) -> (),
390
+ Debug: (msg: string) -> (),
391
+ }
392
+
393
+ -- json namespace
394
+
395
+ declare JSON: {
396
+ Parse: (s: string) -> any,
397
+ Stringify: (value: any) -> string,
398
+ }
399
+
400
+ -- process namespace
401
+
402
+ export type ProcessEntry = {
403
+ pid: number,
404
+ name: string,
405
+ }
406
+
407
+ declare Process: {
408
+ Exists: (name: string) -> number?,
409
+ List: (name: string?) -> { ProcessEntry },
410
+ Kill: (pid: number) -> boolean,
411
+ }
412
+
413
+ -- screen namespace
414
+
415
+ export type PixelMatch = {
416
+ x: number,
417
+ y: number,
418
+ }
419
+
420
+ export type MonitorEntry = {
421
+ index: number,
422
+ x: number,
423
+ y: number,
424
+ width: number,
425
+ height: number,
426
+ primary: boolean,
427
+ }
428
+
429
+ declare Screen: {
430
+ GetPixelColor: (x: number?, y: number?) -> string,
431
+ SearchForColor: (region: {number}, color: string, tolerance: number?) -> PixelMatch?,
432
+ List: () -> { MonitorEntry },
433
+ }
434
+
435
+ -- window namespace
436
+
437
+ declare Window: {
438
+ Find: (title: string) -> number?,
439
+ List: (title: string?) -> { WindowEntry },
440
+ GetTitle: (handle: number?) -> string,
441
+ GetClass: (handle: number?) -> string,
442
+ GetPos: (handle: number?) -> WindowPos,
443
+ GetPID: (handle: number?) -> number,
444
+ Activate: (handle: number) -> (),
445
+ Move: (handle: number, x: number?, y: number?, width: number?, height: number?) -> (),
446
+ SetAlwaysOnTop: (handle: number, enabled: boolean) -> (),
447
+ SetTransparency: (handle: number, alpha: number) -> (),
448
+ SetTitle: (handle: number, title: string) -> (),
449
+ Minimize: (handle: number?) -> (),
450
+ Maximize: (handle: number?) -> (),
451
+ Restore: (handle: number?) -> (),
452
+ Hide: (handle: number?) -> (),
453
+ Show: (handle: number?) -> (),
454
+ Close: (handle: number?) -> (),
455
+ Kill: (handle: number?) -> (),
456
+ IsVisible: (handle: number) -> boolean,
457
+ IsActive: (handle: number?) -> boolean,
458
+ Wait: (title: string, timeout: number?) -> number?,
459
+ WaitActive: (title: string, timeout: number?) -> boolean,
460
+ WaitClose: (title: string, timeout: number?) -> boolean,
461
+ }
462
+
463
+ -- app namespace: application-level control (Keyboard Maestro's Application
464
+ -- Control). names match case-insensitively by app display name. Front/IsRunning/
465
+ -- Activate are permission-free; Hide/Quit/IsHidden drive an AppleEvent and
466
+ -- prompt for macOS Automation permission on first use.
467
+
468
+ export type AppInfo = {
469
+ name: string,
470
+ pid: number,
471
+ }
472
+
473
+ declare App: {
474
+ Front: () -> AppInfo?,
475
+ IsFront: (name: string) -> boolean,
476
+ IsRunning: (name: string) -> boolean,
477
+ IsHidden: (name: string) -> boolean,
478
+ Activate: (name: string) -> (),
479
+ Hide: (name: string) -> (),
480
+ Quit: (name: string) -> (),
481
+ }
482
+
483
+ -- net namespace
484
+
485
+ declare Net: {
486
+ Get: (url: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
487
+ Post: (url: string, body: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
488
+ Put: (url: string, body: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
489
+ Patch: (url: string, body: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
490
+ Delete: (url: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
491
+ Head: (url: string, headers: { [string]: string }?, options: HttpOptions?) -> HttpResponse,
492
+ Request: (options: HttpRequestOptions) -> HttpResponse,
493
+ Listen: (port: number, handler: (request: HttpRequest) -> HttpResponseSpec | string) -> ServerHandle,
494
+ WSListen: (port: number, handlers: WsListenHandlers) -> WsServerHandle,
495
+ WSConnect: (url: string, handlers: WsConnectHandlers) -> WsConnectHandle,
496
+ }
497
+
498
+ -- pipe namespace
499
+
500
+ declare Pipe: {
501
+ Open: (name: string, options: { size: number? }?) -> PipeHandle,
502
+ }
503
+
504
+ -- file namespace
505
+
506
+ declare File: {
507
+ Read: (path: string) -> string,
508
+ ReadBytes: (path: string) -> string,
509
+ Write: (path: string, content: string) -> (),
510
+ Append: (path: string, content: string) -> (),
511
+ Exists: (path: string) -> boolean,
512
+ Delete: (path: string) -> boolean,
513
+ List: (path: string?) -> { string },
514
+ MkDir: (path: string) -> boolean,
515
+ RmDir: (path: string) -> (),
516
+ ReadJSON: (path: string) -> any,
517
+ WriteJSON: (path: string, value: any) -> (),
518
+ GetScriptDir: () -> string,
519
+ GetSize: (path: string) -> number,
520
+ GetTime: (path: string) -> number,
521
+ Copy: (src: string, dst: string) -> (),
522
+ Move: (src: string, dst: string) -> (),
523
+ IsDir: (path: string) -> boolean,
524
+ IsFile: (path: string) -> boolean,
525
+ }
526
+
527
+ -- audio namespace
528
+
529
+ export type PlayOptions = {
530
+ volume: number?,
531
+ loop: boolean?,
532
+ }
533
+
534
+ export type SoundHandle = {
535
+ Stop: (self: SoundHandle) -> (),
536
+ Pause: (self: SoundHandle) -> (),
537
+ Resume: (self: SoundHandle) -> (),
538
+ IsPlaying: (self: SoundHandle) -> boolean,
539
+ SetVolume: (self: SoundHandle, vol: number) -> (),
540
+ GetVolume: (self: SoundHandle) -> number,
541
+ }
542
+
543
+ declare Audio: {
544
+ Beep: () -> (),
545
+ Play: (path: string, options: PlayOptions?) -> SoundHandle,
546
+ StopAll: () -> (),
547
+ SetMasterVolume: (vol: number) -> (),
548
+ GetMasterVolume: () -> number,
549
+ }
550
+
551
+ -- dialog namespace
552
+
553
+ export type DialogMessageOptions = {
554
+ title: string?,
555
+ level: string?,
556
+ }
557
+
558
+ export type DialogFileFilter = {
559
+ name: string,
560
+ extensions: { string },
561
+ }
562
+
563
+ export type DialogFileOptions = {
564
+ title: string?,
565
+ location: string?,
566
+ filters: { DialogFileFilter }?,
567
+ }
568
+
569
+ declare Dialog: {
570
+ Message: (text: string, options: DialogMessageOptions?) -> (),
571
+ Confirm: (text: string, options: DialogMessageOptions?) -> boolean,
572
+ OpenFile: (options: DialogFileOptions?) -> string?,
573
+ OpenDir: (options: DialogFileOptions?) -> string?,
574
+ SaveFile: (options: DialogFileOptions?) -> string?,
575
+ }
576
+
577
+ -- clipboard namespace
578
+
579
+ declare Clipboard: {
580
+ Get: () -> string?,
581
+ Set: (text: string) -> (),
582
+ }
583
+
584
+ -- script namespace
585
+
586
+ declare Script: {
587
+ Exit: (reason: string?) -> (),
588
+ Reload: () -> (),
589
+ }
590
+
591
+ -- regex namespace
592
+
593
+ export type RegexMatch = {
594
+ match: string,
595
+ captures: { string },
596
+ start: number,
597
+ finish: number,
598
+ }
599
+
600
+ declare Regex: {
601
+ IsMatch: (text: string, pattern: string) -> boolean,
602
+ Find: (text: string, pattern: string) -> RegexMatch?,
603
+ FindAll: (text: string, pattern: string) -> { RegexMatch },
604
+ Replace: (text: string, pattern: string, replacement: string) -> string,
605
+ ReplaceAll: (text: string, pattern: string, replacement: string) -> string,
606
+ Split: (text: string, pattern: string) -> { string },
607
+ }
608
+
609
+ -- config namespace
610
+
611
+ declare Config: {
612
+ ParseTOML: (text: string) -> { [string]: any },
613
+ ToTOML: (value: { [string]: any }) -> string,
614
+ ReadTOML: (path: string) -> { [string]: any },
615
+ WriteTOML: (path: string, value: { [string]: any }) -> (),
616
+ }
617
+
618
+ -- hash namespace
619
+
620
+ declare Hash: {
621
+ MD5: (data: string) -> string,
622
+ SHA1: (data: string) -> string,
623
+ SHA256: (data: string) -> string,
624
+ SHA512: (data: string) -> string,
625
+ CRC32: (data: string) -> number,
626
+ HMAC: (algo: string, key: string, data: string) -> string,
627
+ }
628
+
629
+ -- codec namespace
630
+
631
+ declare Codec: {
632
+ Base64: (data: string) -> string,
633
+ Base64Decode: (str: string) -> string,
634
+ Hex: (data: string) -> string,
635
+ HexDecode: (str: string) -> string,
636
+ }
637
+
638
+ -- env namespace
639
+
640
+ declare Env: {
641
+ Get: (name: string) -> string?,
642
+ Set: (name: string, value: string) -> (),
643
+ Home: () -> string?,
644
+ Config: () -> string?,
645
+ Data: () -> string?,
646
+ Desktop: () -> string?,
647
+ Documents: () -> string?,
648
+ Downloads: () -> string?,
649
+ AppData: () -> string?,
650
+ Temp: () -> string?,
651
+ }
652
+
653
+ -- registry namespace (windows only)
654
+
655
+ declare Registry: {
656
+ Read: (keyPath: string, valueName: string) -> string | number,
657
+ Write: (keyPath: string, type: string, valueName: string, value: any) -> (),
658
+ DeleteValue: (keyPath: string, valueName: string) -> (),
659
+ DeleteKey: (keyPath: string) -> (),
660
+ CreateKey: (keyPath: string) -> (),
661
+ }
662
+
663
+ -- valid key names for input hooks (OnDown, OnUp):
664
+ --
665
+ -- letters: A-Z
666
+ -- numbers: 0-9
667
+ -- function: F1-F12
668
+ -- mouse: Mouse1 (left), Mouse2 (right), Mouse3 (middle), Mouse4, Mouse5
669
+ -- modifiers: LCtrl, RCtrl, LShift, RShift, LAlt, RAlt, LWin, RWin
670
+ -- navigation: Up, Down, Left, Right, Home, End, PageUp, PageDown, Insert, Delete
671
+ -- editing: Backspace, Tab, Enter, Space, Escape
672
+ -- punctuation: Minus, Equal, LeftBrace, RightBrace, Backslash, Semicolon,
673
+ -- Apostrophe, Grave, Comma, Period, Slash
674
+ -- locks: CapsLock, ScrollLock, NumLock
675
+ -- system: PrintScreen, Pause, Menu
676
+ -- numpad: Kp0-Kp9, KpPlus, KpMinus, KpMultiply, KpDivide, KpEnter, KpDot
677
+ --
678
+ -- HID output only (HID.Down, HID.Press, etc.):
679
+ -- function: F13-F24
680
+ -- media: MediaNext, MediaPrev, MediaStop, MediaPlay, VolumeUp, VolumeDown, Mute
681
+ -- aliases: Numpad0-9, NP0-9, NPAdd, NPSubtract, NPMultiply, NPDivide, NPEnter,
682
+ -- NPDecimal, Ctrl, Shift, Alt, Win, Meta, Del, PgUp, PgDn, etc.
683
+
684
+ -- hooks: declare these as global functions in your script.
685
+ -- uncomment the ones you use; the runtime calls them when events occur.
686
+
687
+ -- declare function OnStart(): ()
688
+ -- declare function OnStop(): ()
689
+ -- declare function OnFocus(window: WindowInfo): ()
690
+ -- declare function OnBlur(window: WindowInfo): ()
691
+ -- declare function OnTick(dtMs: number): () -- ms elapsed since the previous OnTick (0 on the first)
692
+ -- declare function OnDown(key: string): boolean?
693
+ -- declare function OnUp(key: string, durationMs: number): boolean?
694
+ -- declare function OnMove(dx: number, dy: number): boolean? -- return value only used with mouse_block=true (hardware mode only)
695
+ -- declare function OnScroll(delta: number): boolean?
696
+ -- declare function OnScrollH(delta: number): boolean?
697
+ -- declare function OnError(): ()
698
+ -- declare function OnReload(): ()