stelo 1.0.1

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.
Files changed (141) hide show
  1. package/LICENSE +184 -0
  2. package/README.md +853 -0
  3. package/dist/accessibility.d.ts +227 -0
  4. package/dist/accessibility.d.ts.map +1 -0
  5. package/dist/accessibility.js +602 -0
  6. package/dist/accessibility.js.map +1 -0
  7. package/dist/agent.d.ts +870 -0
  8. package/dist/agent.d.ts.map +1 -0
  9. package/dist/agent.js +1107 -0
  10. package/dist/agent.js.map +1 -0
  11. package/dist/audio-stream.d.ts +114 -0
  12. package/dist/audio-stream.d.ts.map +1 -0
  13. package/dist/audio-stream.js +167 -0
  14. package/dist/audio-stream.js.map +1 -0
  15. package/dist/clipboard.d.ts +99 -0
  16. package/dist/clipboard.d.ts.map +1 -0
  17. package/dist/clipboard.js +352 -0
  18. package/dist/clipboard.js.map +1 -0
  19. package/dist/config.d.ts +183 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +477 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/context.d.ts +213 -0
  24. package/dist/context.d.ts.map +1 -0
  25. package/dist/context.js +387 -0
  26. package/dist/context.js.map +1 -0
  27. package/dist/cortex.d.ts +548 -0
  28. package/dist/cortex.d.ts.map +1 -0
  29. package/dist/cortex.js +1479 -0
  30. package/dist/cortex.js.map +1 -0
  31. package/dist/errors.d.ts +133 -0
  32. package/dist/errors.d.ts.map +1 -0
  33. package/dist/errors.js +278 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/events.d.ts +227 -0
  36. package/dist/events.d.ts.map +1 -0
  37. package/dist/events.js +429 -0
  38. package/dist/events.js.map +1 -0
  39. package/dist/executor.d.ts +212 -0
  40. package/dist/executor.d.ts.map +1 -0
  41. package/dist/executor.js +545 -0
  42. package/dist/executor.js.map +1 -0
  43. package/dist/index.d.ts +69 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +167 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/integration.d.ts +159 -0
  48. package/dist/integration.d.ts.map +1 -0
  49. package/dist/integration.js +533 -0
  50. package/dist/integration.js.map +1 -0
  51. package/dist/keyboard.d.ts +276 -0
  52. package/dist/keyboard.d.ts.map +1 -0
  53. package/dist/keyboard.js +404 -0
  54. package/dist/keyboard.js.map +1 -0
  55. package/dist/logger.d.ts +198 -0
  56. package/dist/logger.d.ts.map +1 -0
  57. package/dist/logger.js +516 -0
  58. package/dist/logger.js.map +1 -0
  59. package/dist/middleware.d.ts +183 -0
  60. package/dist/middleware.d.ts.map +1 -0
  61. package/dist/middleware.js +493 -0
  62. package/dist/middleware.js.map +1 -0
  63. package/dist/monitor.d.ts +136 -0
  64. package/dist/monitor.d.ts.map +1 -0
  65. package/dist/monitor.js +341 -0
  66. package/dist/monitor.js.map +1 -0
  67. package/dist/mouse.d.ts +290 -0
  68. package/dist/mouse.d.ts.map +1 -0
  69. package/dist/mouse.js +466 -0
  70. package/dist/mouse.js.map +1 -0
  71. package/dist/plugin.d.ts +157 -0
  72. package/dist/plugin.d.ts.map +1 -0
  73. package/dist/plugin.js +409 -0
  74. package/dist/plugin.js.map +1 -0
  75. package/dist/process.d.ts +106 -0
  76. package/dist/process.d.ts.map +1 -0
  77. package/dist/process.js +326 -0
  78. package/dist/process.js.map +1 -0
  79. package/dist/recorder.d.ts +100 -0
  80. package/dist/recorder.d.ts.map +1 -0
  81. package/dist/recorder.js +258 -0
  82. package/dist/recorder.js.map +1 -0
  83. package/dist/safety.d.ts +59 -0
  84. package/dist/safety.d.ts.map +1 -0
  85. package/dist/safety.js +98 -0
  86. package/dist/safety.js.map +1 -0
  87. package/dist/scheduler.d.ts +152 -0
  88. package/dist/scheduler.d.ts.map +1 -0
  89. package/dist/scheduler.js +615 -0
  90. package/dist/scheduler.js.map +1 -0
  91. package/dist/screen.d.ts +96 -0
  92. package/dist/screen.d.ts.map +1 -0
  93. package/dist/screen.js +154 -0
  94. package/dist/screen.js.map +1 -0
  95. package/dist/session.d.ts +209 -0
  96. package/dist/session.d.ts.map +1 -0
  97. package/dist/session.js +479 -0
  98. package/dist/session.js.map +1 -0
  99. package/dist/stream.d.ts +168 -0
  100. package/dist/stream.d.ts.map +1 -0
  101. package/dist/stream.js +298 -0
  102. package/dist/stream.js.map +1 -0
  103. package/dist/telemetry.d.ts +223 -0
  104. package/dist/telemetry.d.ts.map +1 -0
  105. package/dist/telemetry.js +433 -0
  106. package/dist/telemetry.js.map +1 -0
  107. package/dist/types.d.ts +165 -0
  108. package/dist/types.d.ts.map +1 -0
  109. package/dist/types.js +8 -0
  110. package/dist/types.js.map +1 -0
  111. package/dist/utils/bezier.d.ts +51 -0
  112. package/dist/utils/bezier.d.ts.map +1 -0
  113. package/dist/utils/bezier.js +117 -0
  114. package/dist/utils/bezier.js.map +1 -0
  115. package/dist/utils/helpers.d.ts +90 -0
  116. package/dist/utils/helpers.d.ts.map +1 -0
  117. package/dist/utils/helpers.js +143 -0
  118. package/dist/utils/helpers.js.map +1 -0
  119. package/dist/utils/index.d.ts +4 -0
  120. package/dist/utils/index.d.ts.map +1 -0
  121. package/dist/utils/index.js +18 -0
  122. package/dist/utils/index.js.map +1 -0
  123. package/dist/validation.d.ts +254 -0
  124. package/dist/validation.d.ts.map +1 -0
  125. package/dist/validation.js +478 -0
  126. package/dist/validation.js.map +1 -0
  127. package/dist/vision.d.ts +719 -0
  128. package/dist/vision.d.ts.map +1 -0
  129. package/dist/vision.js +1197 -0
  130. package/dist/vision.js.map +1 -0
  131. package/dist/window.d.ts +80 -0
  132. package/dist/window.d.ts.map +1 -0
  133. package/dist/window.js +170 -0
  134. package/dist/window.js.map +1 -0
  135. package/dist/workflow.d.ts +224 -0
  136. package/dist/workflow.d.ts.map +1 -0
  137. package/dist/workflow.js +578 -0
  138. package/dist/workflow.js.map +1 -0
  139. package/index.d.ts +840 -0
  140. package/index.js +495 -0
  141. package/package.json +91 -0
package/README.md ADDED
@@ -0,0 +1,853 @@
1
+ <div align="center">
2
+
3
+ # Stelo
4
+
5
+ ### The Most Advanced Universal Desktop Automation Framework
6
+
7
+ [![npm](https://img.shields.io/npm/v/stelo?style=flat-square&color=CB3837)](https://www.npmjs.com/package/stelo)
8
+ [![License: Apache--2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg?style=flat-square)](LICENSE)
9
+ [![Windows](https://img.shields.io/badge/Windows-0078D6?style=flat-square&logo=windows&logoColor=white)](.)
10
+ [![macOS](https://img.shields.io/badge/macOS-000000?style=flat-square&logo=apple&logoColor=white)](.)
11
+ [![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black)](.)
12
+
13
+ **Mouse · Keyboard · Screen · Window · Recorder · Safety**
14
+
15
+ *Sub-millisecond native performance powered by Rust + napi-rs*
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## Why Stelo?
22
+
23
+ | Feature | RobotJS | nutjs | **Stelo** |
24
+ |---|---|---|---|
25
+ | Active maintenance | ❌ | ⚠️ | ✅ |
26
+ | Cross-platform | ✅ | ✅ | ✅ |
27
+ | Native performance | ✅ | ❌ (screen slow) | ✅ Rust |
28
+ | Smooth mouse movement | ❌ | ✅ basic | ✅ Bezier + Wind-Mouse |
29
+ | **Async non-blocking movement** | ❌ | ❌ | ✅ |
30
+ | **Real-time cursor streaming** | ❌ | ❌ | ✅ |
31
+ | **Parallel action execution** | ❌ | ❌ | ✅ |
32
+ | Humanized input | ❌ | ❌ | ✅ |
33
+ | Window management | ❌ | ✅ | ✅ |
34
+ | Screen capture | ✅ slow | ✅ | ✅ fast |
35
+ | Automation recorder | ❌ | ❌ | ✅ |
36
+ | Safety / failsafe | ❌ | ❌ | ✅ |
37
+ | TypeScript-first | ❌ | ✅ | ✅ |
38
+ | Prebuilt binaries | ❌ (rebuild) | ✅ | ✅ napi-rs |
39
+ | **Enterprise telemetry** | ❌ | ❌ | ✅ |
40
+ | **Circuit breakers** | ❌ | ❌ | ✅ |
41
+ | **Audit logging** | ❌ | ❌ | ✅ |
42
+ | **Structured errors** | ❌ | ❌ | ✅ |
43
+ | **Screen diffing** | ❌ | ❌ | ✅ native Rust |
44
+ | **Change detection** | ❌ | ❌ | ✅ |
45
+ | **Action verification** | ❌ | ❌ | ✅ |
46
+ | **Grid analysis** | ❌ | ❌ | ✅ |
47
+ | **Perceptual hashing** | ❌ | ❌ | ✅ |
48
+ | **Action batching** | ❌ | ❌ | ✅ |
49
+ | **Real-time agent control** | ❌ | ❌ | ✅ |
50
+ | **Streaming cursor control** | ❌ | ❌ | ✅ |
51
+ | **Gesture recording** | ❌ | ❌ | ✅ |
52
+
53
+ ---
54
+
55
+ ## Quick Start
56
+
57
+ ```bash
58
+ npm install stelo
59
+ ```
60
+
61
+ ```typescript
62
+ import { mouse, keyboard, screen } from 'stelo';
63
+
64
+ // Move mouse smoothly with bezier curve
65
+ await mouse.moveSmoothly(500, 400, { duration: 800, curve: 'bezier' });
66
+
67
+ // Click, type, hotkey
68
+ mouse.click();
69
+ keyboard.type('Hello from Stelo!');
70
+ keyboard.hotkey('ctrl', 's');
71
+
72
+ // Screen analysis
73
+ const color = screen.getPixelColor(100, 200);
74
+ console.log(color.hex); // '#3B82F6'
75
+ ```
76
+
77
+ > **Node.js ≥ 18** required. Prebuilt binaries available — no compiler needed.
78
+
79
+ ---
80
+
81
+ ## Built for Computer-Use Agents
82
+
83
+ Stelo is the premier SDK for building autonomous desktop agents. Every design decision prioritizes the needs of vision-language models and computer-use systems:
84
+
85
+ **🎯 Native Resolution Everywhere**
86
+ - Forces Per-Monitor DPI Awareness V2 on Windows
87
+ - Screenshot coordinates = mouse coordinates = vision model coordinates
88
+ - Zero drift, zero scaling math, single coordinate space end-to-end
89
+
90
+ **👁 Vision Primitives (Rust-native)**
91
+ - **Screen diffing**: Detect what changed between frames
92
+ - **Action verification**: Confirm clicks/keypresses actually worked
93
+ - **Wait for stable**: Pause until animations complete
94
+ - **Grid analysis**: Efficiently identify regions of interest for vision models
95
+ - **Perceptual hashing**: Fast similarity checks without full pixel comparison
96
+ - **Color clustering**: Find UI elements like buttons by color
97
+
98
+ **⚡ Subsecond Feedback Loop**
99
+ - Native Rust screen capture (10-50ms full screen)
100
+ - BGRA capture mode (skip color conversion for vision pipelines)
101
+ - Humanized input that evades bot detection
102
+
103
+ ```typescript
104
+ import { vision, mouse, screen } from 'stelo';
105
+
106
+ // Agent workflow: observe → act → verify → repeat
107
+ const before = vision.captureReference();
108
+ await mouse.click(button.x, button.y);
109
+
110
+ const result = await vision.verifyAction(
111
+ async () => {}, // Already clicked
112
+ 0.5, // Require 0.5% visual change
113
+ 2000
114
+ );
115
+
116
+ if (!result.verified) {
117
+ // No visual feedback - click may have failed
118
+ // Agent can retry or try alternative approach
119
+ }
120
+
121
+ // Wait for any animations to complete before next action
122
+ await vision.waitForStable(0.1, 200, 5000);
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Real-Time Agent Control
128
+
129
+ For AI agents that need to control mouse and keyboard in real-time with minimal latency, Stelo provides a dedicated `agent` module optimized for continuous control loops:
130
+
131
+ **🚀 Non-Blocking Real-Time Movement**
132
+ - Cursor moves visually on-screen in real-time — no teleporting
133
+ - Event loop stays free during movement — do other things in parallel
134
+ - Cancel movements mid-flight, redirect cursor seamlessly
135
+ - All movement is cancellable via `MovementHandle`
136
+
137
+ **⚡ Parallel Action Execution**
138
+ - Run multiple operations simultaneously via `agent.parallel()`
139
+ - Move mouse while monitoring screen; type while waiting for UI changes
140
+ - Zero blocking — everything is async/non-blocking
141
+
142
+ **🔄 Streaming Cursor Control**
143
+ - Create persistent cursor streams with `agent.createCursorStream()`
144
+ - Send continuous target updates — cursor smoothly follows in real-time
145
+ - Velocity-based control for joystick/AI-style steering
146
+ - Perfect for vision-language models that output continuous coordinates
147
+
148
+ **🎯 Verification-First Design**
149
+ - Every action can verify it had the expected visual effect
150
+ - Know immediately if a click "worked" or needs retry
151
+ - Essential for robust autonomous agents
152
+
153
+ ```typescript
154
+ import { mouse, keyboard, agent, screen } from 'stelo';
155
+
156
+ // ── Non-Blocking Smooth Movement ────────────────────────────────────
157
+ // The cursor visually moves on-screen. No teleporting. No blocking.
158
+
159
+ await mouse.moveSmoothAsync(500, 400, { duration: 600 });
160
+
161
+ // Cancel mid-flight
162
+ const handle = mouse.moveSmoothAsync(800, 600);
163
+ setTimeout(() => handle.cancel(), 200);
164
+ await handle.promise;
165
+
166
+ // Humanized movement with jitter and overshoot — also non-blocking
167
+ await mouse.moveHumanizedAsync(500, 300, {
168
+ duration: 800,
169
+ jitter: 0.5,
170
+ }).promise;
171
+
172
+ // ── Parallel Operations ─────────────────────────────────────────────
173
+ // Move mouse while monitoring screen — simultaneously
174
+
175
+ const result = await agent.parallel({
176
+ move: async () => {
177
+ await mouse.moveSmoothAsync(500, 300, { duration: 600 }).promise;
178
+ },
179
+ monitor: async () => {
180
+ await new Promise(r => setTimeout(r, 300));
181
+ return screen.capture();
182
+ },
183
+ });
184
+
185
+ // ── Streaming Cursor Control ────────────────────────────────────────
186
+ // For continuous real-time control by AI models
187
+
188
+ const cursor = agent.createCursorStream(120);
189
+
190
+ cursor.moveTo(500, 300); // Smooth movement to target
191
+ setTimeout(() => cursor.moveTo(800, 600), 200); // Redirect mid-flight
192
+ cursor.setVelocity(200, -100); // Velocity-based steering
193
+ cursor.stop(); // Stop all movement
194
+ cursor.destroy(); // Release resources
195
+
196
+ // ── Smooth Click & Type ─────────────────────────────────────────────
197
+ // Visible cursor movement + click + type — all in one async call
198
+
199
+ await agent.smoothClickAndType(500, 300, 'search query', {
200
+ duration: 400,
201
+ });
202
+
203
+ // ── Non-Blocking Typing ─────────────────────────────────────────────
204
+ // Type while doing other things simultaneously
205
+
206
+ await Promise.all([
207
+ keyboard.typeHumanizedAsync('Hello World').promise,
208
+ (async () => {
209
+ await new Promise(r => setTimeout(r, 100));
210
+ return screen.capture(); // Capture while typing
211
+ })(),
212
+ ]);
213
+
214
+ // ── Action Batching ─────────────────────────────────────────────────
215
+ // Execute multiple actions atomically in one native call
216
+
217
+ const batch = agent.executeBatch([
218
+ { type: 'mouseClickAt', x: 500, y: 300 },
219
+ { type: 'waitForStable', stableMs: 200 },
220
+ { type: 'type', text: 'search query' },
221
+ { type: 'keyPress', key: 'Enter' },
222
+ { type: 'waitForChange', timeout: 3000 }
223
+ ]);
224
+
225
+ // ── Fluent Sequence Builder ─────────────────────────────────────────
226
+ const workflow = agent.sequence()
227
+ .clickAt(500, 300)
228
+ .waitForStable()
229
+ .type('Hello World')
230
+ .press('Enter')
231
+ .waitForChange()
232
+ .executeAsync(); // Non-blocking version
233
+
234
+ // ── Verification ────────────────────────────────────────────────────
235
+ const verified = await agent.moveClickVerify(500, 300, {
236
+ moveDuration: 400,
237
+ minChangePercent: 0.5,
238
+ });
239
+ if (!verified.verified) {
240
+ console.log('Click had no visual effect - retry needed');
241
+ }
242
+ ```
243
+
244
+ **Supported Batch Actions:**
245
+ | Type | Description | Parameters |
246
+ |------|-------------|------------|
247
+ | `mouseMove` | Instant move | `x, y` |
248
+ | `mouseMoveRel` | Relative move | `dx, dy` |
249
+ | `mouseMoveSmooth` | Animated move | `x, y, duration?` |
250
+ | `mouseClick` | Click at current pos | `button?` |
251
+ | `mouseClickAt` | Move and click | `x, y, button?` |
252
+ | `mouseDoubleClick` | Double click | `button?` |
253
+ | `mouseDown/Up` | Press/release | `button?` |
254
+ | `mouseScroll` | Scroll wheel | `amount, horizontal?` |
255
+ | `mouseDrag` | Drag to position | `toX, toY, button?` |
256
+ | `type` | Type text instantly | `text` |
257
+ | `typeHumanized` | Type naturally | `text, minDelay?, maxDelay?` |
258
+ | `keyPress` | Press and release | `key` |
259
+ | `keyDown/Up` | Hold/release key | `key` |
260
+ | `hotkey` | Key combination | `keys[]` |
261
+ | `delay` | Wait duration | `ms` |
262
+ | `waitForChange` | Wait for visual change | `threshold?, timeout?, region?` |
263
+ | `waitForStable` | Wait for stability | `threshold?, stableMs?, timeout?, region?` |
264
+
265
+ ---
266
+
267
+ ## Installation
268
+
269
+ ```bash
270
+ # npm
271
+ npm install stelo
272
+
273
+ # yarn
274
+ yarn add stelo
275
+
276
+ # pnpm
277
+ pnpm add stelo
278
+ ```
279
+
280
+ ### Supported Platforms
281
+
282
+ | OS | Arch | Package |
283
+ |---|---|---|
284
+ | Windows | x64 | `stelo-win32-x64-msvc` |
285
+ | Windows | arm64 | `stelo-win32-arm64-msvc` |
286
+ | macOS | x64 (Intel) | `stelo-darwin-x64` |
287
+ | macOS | arm64 (Apple Silicon) | `stelo-darwin-arm64` |
288
+ | Linux | x64 (glibc) | `stelo-linux-x64-gnu` |
289
+ | Linux | x64 (musl) | `stelo-linux-x64-musl` |
290
+ | Linux | arm64 (glibc) | `stelo-linux-arm64-gnu` |
291
+ | Linux | arm64 (musl) | `stelo-linux-arm64-musl` |
292
+
293
+ Platform packages are auto-installed via `optionalDependencies`.
294
+
295
+ ---
296
+
297
+ ## API Overview
298
+
299
+ ### 🖱 Mouse
300
+
301
+ ```typescript
302
+ import { mouse } from 'stelo';
303
+
304
+ // Position
305
+ mouse.move(x, y); // instant teleport
306
+ const { x, y } = mouse.getPosition(); // current position
307
+ console.log(mouse.x, mouse.y); // shorthand getters
308
+
309
+ // Smooth movement
310
+ await mouse.moveSmoothly(x, y, {
311
+ duration: 500, // ms
312
+ curve: 'bezier' | 'easeInOut' | 'linear',
313
+ });
314
+ await mouse.moveHumanized(x, y); // wind-mouse algorithm
315
+
316
+ // Clicks
317
+ mouse.click(); // left click
318
+ mouse.click('right'); // right click
319
+ mouse.click('middle'); // middle click
320
+ mouse.doubleClick();
321
+ mouse.tripleClick();
322
+ mouse.moveAndClick(x, y); // move + click in one
323
+
324
+ // Press / release
325
+ mouse.down('left');
326
+ mouse.up('left');
327
+
328
+ // Scroll
329
+ mouse.scroll(3, 'up'); // 3 clicks up
330
+ mouse.scroll(5, 'down');
331
+ mouse.scroll(2, 'left'); // horizontal
332
+
333
+ // Drag
334
+ mouse.drag(fromX, fromY, toX, toY);
335
+ mouse.drag(fromX, fromY, toX, toY, 'right'); // right-button drag
336
+ ```
337
+
338
+ ### ⌨️ Keyboard
339
+
340
+ ```typescript
341
+ import { keyboard } from 'stelo';
342
+
343
+ // Typing
344
+ keyboard.type('Hello World'); // instant
345
+ await keyboard.typeHumanized('Hello', { // natural speed
346
+ minDelay: 40,
347
+ maxDelay: 120,
348
+ });
349
+
350
+ // Key operations
351
+ keyboard.press('enter'); // tap a key
352
+ keyboard.down('shift'); // hold
353
+ keyboard.up('shift'); // release
354
+ keyboard.tap('backspace', 5); // repeat N times
355
+
356
+ // Hotkeys
357
+ keyboard.hotkey('ctrl', 'c'); // copy
358
+ keyboard.hotkey('ctrl', 'shift', 'p'); // multi-key combo
359
+
360
+ // Convenience shortcuts
361
+ keyboard.enter();
362
+ keyboard.tab();
363
+ keyboard.escape();
364
+ keyboard.backspace();
365
+ keyboard.selectAll(); // ctrl+a / cmd+a
366
+ keyboard.copy(); // ctrl+c / cmd+c
367
+ keyboard.paste(); // ctrl+v / cmd+v
368
+ keyboard.cut(); // ctrl+x / cmd+x
369
+ keyboard.undo(); // ctrl+z / cmd+z
370
+ keyboard.redo(); // ctrl+y / cmd+shift+z
371
+ keyboard.save(); // ctrl+s / cmd+s
372
+
373
+ // Query
374
+ const keys = keyboard.allKeys(); // all supported key names
375
+ const pressed = keyboard.isPressed('shift'); // is key currently held?
376
+ ```
377
+
378
+ ### 🖥 Screen
379
+
380
+ ```typescript
381
+ import { screen } from 'stelo';
382
+
383
+ // Dimensions
384
+ const { width, height } = screen.getSize();
385
+
386
+ // Pixel colour
387
+ const color = screen.getPixelColor(x, y);
388
+ // → { r: 59, g: 130, b: 246, hex: '#3B82F6' }
389
+
390
+ // Capture
391
+ const img = screen.capture(); // full screen
392
+ const region = screen.capture({ // specific region
393
+ x: 100, y: 100, width: 400, height: 300,
394
+ });
395
+ // img.data is a Buffer of RGBA pixels
396
+
397
+ // All displays
398
+ const displays = screen.getAllDisplays();
399
+ // → [{ id, x, y, width, height, isPrimary, scaleFactor }]
400
+
401
+ // Colour search
402
+ const point = screen.findColor('#FF0000', { tolerance: 10 });
403
+ const matches = screen.pixelMatches(x, y, '#FF0000', 5);
404
+
405
+ // Wait for colour
406
+ await screen.waitForColor(x, y, '#00FF00', {
407
+ tolerance: 10,
408
+ timeoutMs: 5000,
409
+ intervalMs: 100,
410
+ });
411
+ ```
412
+
413
+ ### 🪟 Window
414
+
415
+ ```typescript
416
+ import { appWindow } from 'stelo';
417
+
418
+ // Query
419
+ const active = appWindow.getActive();
420
+ const all = appWindow.getAll();
421
+ const found = appWindow.find('Notepad');
422
+
423
+ // Focus
424
+ appWindow.focus(windowId);
425
+ appWindow.focusByTitle('Calculator');
426
+
427
+ // Geometry
428
+ appWindow.resize(id, 800, 600);
429
+ appWindow.moveTo(id, 100, 100);
430
+ appWindow.setBounds(id, { x: 0, y: 0, width: 1024, height: 768 });
431
+
432
+ // State
433
+ appWindow.minimize(id);
434
+ appWindow.maximize(id);
435
+ appWindow.restore(id);
436
+ appWindow.close(id);
437
+
438
+ // Wait for window to appear
439
+ const win = await appWindow.waitFor('MyApp', 10000);
440
+ ```
441
+
442
+ ### 🎬 Recorder
443
+
444
+ ```typescript
445
+ import { recorder } from 'stelo';
446
+
447
+ // Build a sequence
448
+ const steps = recorder.sequence()
449
+ .moveTo(100, 200)
450
+ .click()
451
+ .delay(200)
452
+ .type('hello')
453
+ .press('enter')
454
+ .hotkey('ctrl', 's')
455
+ .build();
456
+
457
+ // Play it back
458
+ await recorder.play(steps);
459
+ await recorder.play(steps, { speed: 2.0 }); // 2× speed
460
+
461
+ // Serialize / restore
462
+ const json = recorder.toJSON(steps);
463
+ const restored = recorder.fromJSON(json);
464
+ ```
465
+
466
+ ### 🛡 Safety
467
+
468
+ ```typescript
469
+ import { safety } from 'stelo';
470
+
471
+ // Failsafe: move mouse to any screen corner → emergency stop
472
+ safety.enableFailsafe();
473
+ safety.enableFailsafe(10); // 10px threshold
474
+
475
+ // Rate limiting
476
+ safety.setRateLimit(200); // max 200 actions/sec
477
+
478
+ // Emergency stop / reset
479
+ safety.emergencyStop();
480
+ console.log(safety.isStopped()); // true
481
+ safety.reset();
482
+
483
+ // Configure all at once
484
+ safety.configure({
485
+ failsafe: true,
486
+ failsafeThreshold: 5,
487
+ rateLimit: 500,
488
+ });
489
+ ```
490
+
491
+ ### 🏢 Enterprise Features
492
+
493
+ Stelo includes enterprise-grade utilities for production deployments.
494
+
495
+ #### Telemetry & Observability
496
+
497
+ ```typescript
498
+ import { telemetry } from 'stelo';
499
+
500
+ // Enable telemetry
501
+ telemetry.enable();
502
+
503
+ // Subscribe to events
504
+ telemetry.onEvent((event) => {
505
+ console.log(`[${event.severity}] ${event.operation}: ${event.message}`);
506
+ });
507
+
508
+ // Track operations with timing
509
+ await telemetry.trackAsync('my-operation', async () => {
510
+ await mouse.moveSmoothly(500, 400);
511
+ });
512
+
513
+ // Get metrics
514
+ const metrics = telemetry.getMetrics();
515
+ // → { totalOps, successRate, avgLatencyMs, p95LatencyMs, ... }
516
+
517
+ // Health check
518
+ const health = await telemetry.healthCheck();
519
+ // → { status: 'healthy', checks: [...], timestamp: '...' }
520
+ ```
521
+
522
+ #### Circuit Breaker (Fault Tolerance)
523
+
524
+ ```typescript
525
+ import { CircuitBreaker } from 'stelo';
526
+
527
+ const breaker = new CircuitBreaker('external-service', {
528
+ failureThreshold: 5,
529
+ resetTimeoutMs: 30000,
530
+ });
531
+
532
+ try {
533
+ await breaker.execute(async () => {
534
+ return await riskyOperation();
535
+ });
536
+ } catch (e) {
537
+ if (breaker.getState() === 'open') {
538
+ console.log('Circuit is open, service unavailable');
539
+ }
540
+ }
541
+ ```
542
+
543
+ #### Validation & Input Checking
544
+
545
+ ```typescript
546
+ import { validate, ValidationError } from 'stelo';
547
+
548
+ // Validate coordinates
549
+ validate.coordinate(x, 'x');
550
+ validate.coordinate(y, 'y');
551
+
552
+ // Validate within screen bounds
553
+ const screenSize = screen.getSize();
554
+ validate.inBounds({ x, y }, screenSize);
555
+
556
+ // Safe validation (returns Result instead of throwing)
557
+ const result = validate.safe.coordinate(x, 'x');
558
+ if (!result.ok) {
559
+ console.error(result.error.message);
560
+ }
561
+
562
+ // Validate regions
563
+ validate.region({ x: 0, y: 0, width: 100, height: 100 });
564
+ ```
565
+
566
+ #### Audit Logging & Security
567
+
568
+ ```typescript
569
+ import { security } from 'stelo';
570
+
571
+ // Enable audit logging
572
+ security.enableAudit();
573
+
574
+ // Subscribe to audit events
575
+ security.onAudit((entry) => {
576
+ console.log(`[AUDIT] ${entry.operation}: ${entry.success ? 'OK' : 'FAIL'}`);
577
+ });
578
+
579
+ // Get audit log
580
+ const log = security.getAuditLog(100); // last 100 entries
581
+
582
+ // Sanitize user input before typing
583
+ const safeText = security.sanitizeText(userInput);
584
+ keyboard.type(safeText);
585
+
586
+ // Detect sandboxed environments
587
+ const { sandboxed, indicators } = security.detectSandbox();
588
+ ```
589
+
590
+ #### Enhanced Error Handling
591
+
592
+ ```typescript
593
+ import { SteloError, ErrorCode, retryWithBackoff } from 'stelo';
594
+
595
+ try {
596
+ await mouse.move(x, y);
597
+ } catch (e) {
598
+ if (e instanceof SteloError) {
599
+ console.log(`Error ${e.code}: ${e.message}`);
600
+ console.log('Recovery hints:', e.hints);
601
+ console.log('Diagnostics:', e.diagnostics);
602
+
603
+ // Generate detailed error report
604
+ console.log(e.toReport());
605
+ }
606
+ }
607
+
608
+ // Retry with exponential backoff
609
+ const result = await retryWithBackoff(
610
+ () => riskyOperation(),
611
+ { maxAttempts: 5, initialDelayMs: 100 }
612
+ );
613
+ ```
614
+
615
+ #### Rate Limiting
616
+
617
+ ```typescript
618
+ import { RateLimiter } from 'stelo';
619
+
620
+ // Token bucket rate limiter
621
+ const limiter = new RateLimiter(100, 10); // 100 max, 10/sec refill
622
+
623
+ if (limiter.tryConsume()) {
624
+ await doOperation();
625
+ } else {
626
+ console.log('Rate limited, try again later');
627
+ }
628
+ ```
629
+
630
+ ### � Vision & Agent Primitives
631
+
632
+ Advanced screen analysis primitives designed for vision-based desktop automation.
633
+
634
+ #### Screen Diffing & Change Detection
635
+
636
+ ```typescript
637
+ import { vision, mouse } from 'stelo';
638
+
639
+ // Take reference screenshot
640
+ const before = vision.captureReference();
641
+
642
+ // Perform action
643
+ await mouse.click(500, 400);
644
+
645
+ // Compare: did the screen change?
646
+ const diff = vision.diff(before);
647
+ console.log(`${diff.changePercentage}% changed`);
648
+ if (diff.changedBounds) {
649
+ console.log('Change occurred at:', diff.changedBounds);
650
+ }
651
+ ```
652
+
653
+ #### Action Verification
654
+
655
+ ```typescript
656
+ // Verify an action caused visual change
657
+ const result = await vision.verifyAction(
658
+ async () => { await mouse.click(100, 200); },
659
+ 0.5, // require at least 0.5% change
660
+ 2000 // timeout
661
+ );
662
+
663
+ if (!result.verified) {
664
+ console.log('Button click had no effect - retry?');
665
+ }
666
+ ```
667
+
668
+ #### Wait for Screen Stability
669
+
670
+ ```typescript
671
+ // Wait for animations/transitions to complete
672
+ mouse.click();
673
+ await vision.waitForStable(
674
+ 0.1, // max 0.1% change considered "stable"
675
+ 200, // must be stable for 200ms
676
+ 5000 // timeout
677
+ );
678
+ // Screen is now stable - safe to continue
679
+ ```
680
+
681
+ #### Grid Analysis for Vision Models
682
+
683
+ ```typescript
684
+ // Analyze screen as a grid (efficient for vision model region selection)
685
+ const grid = vision.analyzeGrid(16, 9); // 16x9 grid
686
+
687
+ // Find cells likely containing text or UI
688
+ const textCells = grid.cells.filter(c => c.likelyText);
689
+ const uiCells = grid.cells.filter(c => c.likelyUI);
690
+
691
+ // Click the center of cell [3, 2]
692
+ const center = vision.gridCellCenter(grid, 3, 2);
693
+ if (center) await mouse.click(center.x, center.y);
694
+ ```
695
+
696
+ #### Perceptual Hashing
697
+
698
+ ```typescript
699
+ // Fast similarity check using perceptual hashes
700
+ const hash1 = vision.perceptualHash();
701
+ await performAction();
702
+ const hash2 = vision.perceptualHash();
703
+
704
+ const distance = vision.hashDistance(hash1, hash2);
705
+ if (distance < 5) {
706
+ console.log('Screen looks mostly the same');
707
+ } else if (distance > 20) {
708
+ console.log('Screen changed significantly');
709
+ }
710
+ ```
711
+
712
+ #### Color Cluster Detection
713
+
714
+ ```typescript
715
+ // Find UI elements by color (e.g., buttons)
716
+ const blueClusters = vision.findColorClusters(
717
+ { r: 0, g: 120, b: 215 }, // Windows accent blue
718
+ 40, // tolerance
719
+ 50 // min 50 pixels
720
+ );
721
+
722
+ if (blueClusters.length > 0) {
723
+ // Click center of first blue region
724
+ const btn = blueClusters[0];
725
+ mouse.click(btn.x + btn.width / 2, btn.y + btn.height / 2);
726
+ }
727
+ ```
728
+
729
+ ### Agent (Real-Time Control)
730
+
731
+ Low-latency primitives for controlling mouse and keyboard in real-time.
732
+
733
+ #### Action Batching
734
+
735
+ ```typescript
736
+ import { agent } from 'stelo';
737
+
738
+ // Execute multiple actions atomically - minimal latency
739
+ const result = agent.executeBatch([
740
+ { type: 'mouseClickAt', x: 500, y: 300 },
741
+ { type: 'waitForStable', stableMs: 200 },
742
+ { type: 'type', text: 'Hello World' },
743
+ { type: 'keyPress', key: 'Enter' }
744
+ ], { stopOnError: true });
745
+
746
+ // Inspect results
747
+ console.log(`${result.successCount}/${result.results.length} succeeded`);
748
+ console.log(`Total time: ${result.totalDurationMs}ms`);
749
+ ```
750
+
751
+ #### Click with Verification
752
+
753
+ ```typescript
754
+ // Click and confirm the screen changed
755
+ const result = agent.clickAndVerify(500, 300, {
756
+ button: 'left',
757
+ minChangePercent: 0.5,
758
+ timeoutMs: 2000,
759
+ region: { x: 400, y: 200, width: 200, height: 200 }
760
+ });
761
+
762
+ if (!result.verified) {
763
+ console.log('Click had no visual effect');
764
+ }
765
+ ```
766
+
767
+ #### Fluent Sequence Builder
768
+
769
+ ```typescript
770
+ // Chain actions with a fluent API
771
+ const result = agent.sequence()
772
+ .clickAt(500, 300)
773
+ .waitForStable()
774
+ .type('search query')
775
+ .press('Enter')
776
+ .waitForChange({ timeout: 3000 })
777
+ .hotkey('ctrl', 'a')
778
+ .execute();
779
+ ```
780
+
781
+ #### Gesture Recording & Playback
782
+
783
+ ```typescript
784
+ // Record mouse movements
785
+ const trail = agent.recordMouseTrail(3000, 60); // 3 sec at 60Hz
786
+
787
+ // Later, replay the gesture
788
+ agent.replayMouseTrail(trail, 0.5); // Half speed
789
+ ```
790
+
791
+ #### Error Recovery
792
+
793
+ ```typescript
794
+ // Release all held modifier keys (error recovery)
795
+ agent.releaseAllModifiers();
796
+
797
+ // Type and wait for autocomplete/validation to finish
798
+ const stable = agent.typeAndWaitStable('hello@example.com', {
799
+ stabilityThreshold: 0.1,
800
+ stableDurationMs: 200,
801
+ timeoutMs: 3000
802
+ });
803
+ ```
804
+
805
+ ### 🛠 Utilities
806
+
807
+ ```typescript
808
+ import { delay, retry, waitUntil, batch, bezier } from 'stelo';
809
+
810
+ await delay(500); // sleep
811
+
812
+ const result = await retry(() => riskyOp(), { // auto-retry
813
+ maxAttempts: 5,
814
+ delayMs: 200,
815
+ backoffMultiplier: 1.5,
816
+ });
817
+
818
+ await waitUntil(() => isReady(), { // poll
819
+ timeoutMs: 10000,
820
+ intervalMs: 100,
821
+ });
822
+
823
+ await batch(tasks, { concurrency: 3 }); // parallel with limit
824
+
825
+ const pt = bezier.cubic(p0, p1, p2, p3, 0.5); // bezier evaluation
826
+ ```
827
+
828
+ ---
829
+
830
+ ---
831
+
832
+ ## FAQ
833
+
834
+ ### Does Stelo require a C++ compiler?
835
+ **No.** Prebuilt binaries are published for all supported platforms. If you're building from source, you need **Rust** (not C++).
836
+
837
+ ### How does humanized movement work?
838
+ Stelo implements the **Wind Mouse** algorithm — a physics-inspired model that simulates human hand tremor, acceleration, and overshoot. Combined with cubic bezier curves and arc-length parameterization, mouse paths look indistinguishable from real user input.
839
+
840
+ ### Is Stelo safe to use in production?
841
+ Yes. The safety module provides failsafe (mouse-to-corner abort), rate limiting, and emergency stop. Always enable failsafe in automation scripts.
842
+
843
+ ### Does Stelo work in headless / CI environments?
844
+ On Linux, use **Xvfb** (X Virtual Framebuffer) to run Stelo without a physical display. Windows and macOS require a desktop session.
845
+
846
+ ### What about Wayland on Linux?
847
+ Stelo currently uses X11 / XTest. It works under XWayland on most Wayland compositors. Native Wayland input injection is planned.
848
+
849
+ ---
850
+
851
+ ## License
852
+
853
+ [Apache-2.0](LICENSE) © Stelo Contributors