copilot-liku-cli 0.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 (71) hide show
  1. package/ARCHITECTURE.md +411 -0
  2. package/CONFIGURATION.md +302 -0
  3. package/CONTRIBUTING.md +225 -0
  4. package/ELECTRON_README.md +121 -0
  5. package/INSTALLATION.md +350 -0
  6. package/LICENSE.md +1 -0
  7. package/PROJECT_STATUS.md +229 -0
  8. package/QUICKSTART.md +255 -0
  9. package/README.md +167 -0
  10. package/TESTING.md +274 -0
  11. package/package.json +61 -0
  12. package/scripts/start.js +30 -0
  13. package/src/assets/tray-icon.png +0 -0
  14. package/src/cli/commands/agent.js +327 -0
  15. package/src/cli/commands/click.js +108 -0
  16. package/src/cli/commands/drag.js +85 -0
  17. package/src/cli/commands/find.js +109 -0
  18. package/src/cli/commands/keys.js +132 -0
  19. package/src/cli/commands/mouse.js +79 -0
  20. package/src/cli/commands/repl.js +290 -0
  21. package/src/cli/commands/screenshot.js +72 -0
  22. package/src/cli/commands/scroll.js +74 -0
  23. package/src/cli/commands/start.js +67 -0
  24. package/src/cli/commands/type.js +57 -0
  25. package/src/cli/commands/wait.js +84 -0
  26. package/src/cli/commands/window.js +104 -0
  27. package/src/cli/liku.js +249 -0
  28. package/src/cli/util/output.js +174 -0
  29. package/src/main/agents/base-agent.js +410 -0
  30. package/src/main/agents/builder.js +484 -0
  31. package/src/main/agents/index.js +62 -0
  32. package/src/main/agents/orchestrator.js +362 -0
  33. package/src/main/agents/researcher.js +511 -0
  34. package/src/main/agents/state-manager.js +344 -0
  35. package/src/main/agents/supervisor.js +365 -0
  36. package/src/main/agents/verifier.js +452 -0
  37. package/src/main/ai-service.js +1633 -0
  38. package/src/main/index.js +2208 -0
  39. package/src/main/inspect-service.js +467 -0
  40. package/src/main/system-automation.js +1186 -0
  41. package/src/main/ui-automation/config.js +76 -0
  42. package/src/main/ui-automation/core/helpers.js +41 -0
  43. package/src/main/ui-automation/core/index.js +15 -0
  44. package/src/main/ui-automation/core/powershell.js +82 -0
  45. package/src/main/ui-automation/elements/finder.js +274 -0
  46. package/src/main/ui-automation/elements/index.js +14 -0
  47. package/src/main/ui-automation/elements/wait.js +66 -0
  48. package/src/main/ui-automation/index.js +164 -0
  49. package/src/main/ui-automation/interactions/element-click.js +211 -0
  50. package/src/main/ui-automation/interactions/high-level.js +230 -0
  51. package/src/main/ui-automation/interactions/index.js +47 -0
  52. package/src/main/ui-automation/keyboard/index.js +15 -0
  53. package/src/main/ui-automation/keyboard/input.js +179 -0
  54. package/src/main/ui-automation/mouse/click.js +186 -0
  55. package/src/main/ui-automation/mouse/drag.js +88 -0
  56. package/src/main/ui-automation/mouse/index.js +30 -0
  57. package/src/main/ui-automation/mouse/movement.js +51 -0
  58. package/src/main/ui-automation/mouse/scroll.js +116 -0
  59. package/src/main/ui-automation/screenshot.js +183 -0
  60. package/src/main/ui-automation/window/index.js +23 -0
  61. package/src/main/ui-automation/window/manager.js +305 -0
  62. package/src/main/utils/time.js +62 -0
  63. package/src/main/visual-awareness.js +597 -0
  64. package/src/renderer/chat/chat.js +671 -0
  65. package/src/renderer/chat/index.html +725 -0
  66. package/src/renderer/chat/preload.js +112 -0
  67. package/src/renderer/overlay/index.html +648 -0
  68. package/src/renderer/overlay/overlay.js +782 -0
  69. package/src/renderer/overlay/preload.js +90 -0
  70. package/src/shared/grid-math.js +82 -0
  71. package/src/shared/inspect-types.js +230 -0
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Keyboard Input Module
3
+ *
4
+ * Type text and send key combinations.
5
+ * @module ui-automation/keyboard
6
+ */
7
+
8
+ const { executePowerShellScript } = require('../core/powershell');
9
+ const { log, sleep } = require('../core/helpers');
10
+
11
+ /**
12
+ * Type text character by character
13
+ *
14
+ * @param {string} text - Text to type
15
+ * @param {Object} [options] - Type options
16
+ * @param {number} [options.delay=50] - Delay between characters in ms
17
+ * @returns {Promise<{success: boolean}>}
18
+ */
19
+ async function typeText(text, options = {}) {
20
+ const { delay = 50 } = options;
21
+
22
+ // Escape special chars for PowerShell
23
+ const escapedText = text
24
+ .replace(/\\/g, '\\\\')
25
+ .replace(/'/g, "''")
26
+ .replace(/`/g, '``');
27
+
28
+ const psScript = `
29
+ Add-Type -AssemblyName System.Windows.Forms
30
+ $text = '${escapedText}'
31
+ foreach ($char in $text.ToCharArray()) {
32
+ [System.Windows.Forms.SendKeys]::SendWait($char)
33
+ Start-Sleep -Milliseconds ${delay}
34
+ }
35
+ Write-Output "typed"
36
+ `;
37
+
38
+ const result = await executePowerShellScript(psScript);
39
+ const success = result.stdout.includes('typed');
40
+ log(`TypeText "${text.substring(0, 20)}${text.length > 20 ? '...' : ''}" - ${success ? 'success' : 'failed'}`);
41
+
42
+ return { success };
43
+ }
44
+
45
+ /**
46
+ * Send keyboard shortcut or key combination
47
+ *
48
+ * Uses SendKeys format:
49
+ * - ^ = Ctrl
50
+ * - % = Alt
51
+ * - + = Shift
52
+ * - {ENTER}, {TAB}, {ESC}, {DELETE}, {BACKSPACE}
53
+ * - {F1}-{F12}
54
+ * - {UP}, {DOWN}, {LEFT}, {RIGHT}
55
+ * - {HOME}, {END}, {PGUP}, {PGDN}
56
+ *
57
+ * @param {string} keys - Key combination in SendKeys format
58
+ * @returns {Promise<{success: boolean}>}
59
+ */
60
+ async function sendKeys(keys) {
61
+ const psScript = `
62
+ Add-Type -AssemblyName System.Windows.Forms
63
+ [System.Windows.Forms.SendKeys]::SendWait('${keys.replace(/'/g, "''")}')
64
+ Write-Output "sent"
65
+ `;
66
+
67
+ const result = await executePowerShellScript(psScript);
68
+ const success = result.stdout.includes('sent');
69
+ log(`SendKeys "${keys}" - ${success ? 'success' : 'failed'}`);
70
+
71
+ return { success };
72
+ }
73
+
74
+ /**
75
+ * Press a key down (for holding modifiers)
76
+ *
77
+ * @param {number} vkCode - Virtual key code
78
+ * @returns {Promise<{success: boolean}>}
79
+ */
80
+ async function keyDown(vkCode) {
81
+ const psScript = `
82
+ Add-Type -TypeDefinition @'
83
+ using System;
84
+ using System.Runtime.InteropServices;
85
+
86
+ public class KeyboardHelper {
87
+ [StructLayout(LayoutKind.Sequential)]
88
+ public struct INPUT { public uint type; public KEYBDINPUT ki; ulong padding; }
89
+
90
+ [StructLayout(LayoutKind.Sequential)]
91
+ public struct KEYBDINPUT {
92
+ public ushort wVk, wScan; public uint dwFlags, time; public IntPtr dwExtraInfo;
93
+ }
94
+
95
+ [DllImport("user32.dll")]
96
+ public static extern uint SendInput(uint n, INPUT[] inputs, int size);
97
+
98
+ public static void KeyDown(ushort vk) {
99
+ var inp = new INPUT { type = 1, ki = new KEYBDINPUT { wVk = vk } };
100
+ SendInput(1, new[] { inp }, Marshal.SizeOf(typeof(INPUT)));
101
+ }
102
+ }
103
+ '@
104
+ [KeyboardHelper]::KeyDown(${vkCode})
105
+ Write-Output "down"
106
+ `;
107
+
108
+ const result = await executePowerShellScript(psScript);
109
+ return { success: result.stdout.includes('down') };
110
+ }
111
+
112
+ /**
113
+ * Release a key
114
+ *
115
+ * @param {number} vkCode - Virtual key code
116
+ * @returns {Promise<{success: boolean}>}
117
+ */
118
+ async function keyUp(vkCode) {
119
+ const psScript = `
120
+ Add-Type -TypeDefinition @'
121
+ using System;
122
+ using System.Runtime.InteropServices;
123
+
124
+ public class KeyboardHelper {
125
+ [StructLayout(LayoutKind.Sequential)]
126
+ public struct INPUT { public uint type; public KEYBDINPUT ki; ulong padding; }
127
+
128
+ [StructLayout(LayoutKind.Sequential)]
129
+ public struct KEYBDINPUT {
130
+ public ushort wVk, wScan; public uint dwFlags, time; public IntPtr dwExtraInfo;
131
+ }
132
+
133
+ [DllImport("user32.dll")]
134
+ public static extern uint SendInput(uint n, INPUT[] inputs, int size);
135
+
136
+ public static void KeyUp(ushort vk) {
137
+ var inp = new INPUT { type = 1, ki = new KEYBDINPUT { wVk = vk, dwFlags = 0x0002 } };
138
+ SendInput(1, new[] { inp }, Marshal.SizeOf(typeof(INPUT)));
139
+ }
140
+ }
141
+ '@
142
+ [KeyboardHelper]::KeyUp(${vkCode})
143
+ Write-Output "up"
144
+ `;
145
+
146
+ const result = await executePowerShellScript(psScript);
147
+ return { success: result.stdout.includes('up') };
148
+ }
149
+
150
+ /**
151
+ * Common virtual key codes
152
+ */
153
+ const VK = {
154
+ SHIFT: 0x10,
155
+ CTRL: 0x11,
156
+ ALT: 0x12,
157
+ ENTER: 0x0D,
158
+ TAB: 0x09,
159
+ ESC: 0x1B,
160
+ SPACE: 0x20,
161
+ BACKSPACE: 0x08,
162
+ DELETE: 0x2E,
163
+ LEFT: 0x25,
164
+ UP: 0x26,
165
+ RIGHT: 0x27,
166
+ DOWN: 0x28,
167
+ HOME: 0x24,
168
+ END: 0x23,
169
+ PAGEUP: 0x21,
170
+ PAGEDOWN: 0x22,
171
+ };
172
+
173
+ module.exports = {
174
+ typeText,
175
+ sendKeys,
176
+ keyDown,
177
+ keyUp,
178
+ VK,
179
+ };
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Mouse Click Operations
3
+ *
4
+ * Click and double-click with window focus handling.
5
+ * @module ui-automation/mouse/click
6
+ */
7
+
8
+ const { CONFIG } = require('../config');
9
+ const { executePowerShellScript } = require('../core/powershell');
10
+ const { sleep, log } = require('../core/helpers');
11
+
12
+ /**
13
+ * Click at coordinates using SendInput (most reliable)
14
+ *
15
+ * @param {number} x - X coordinate
16
+ * @param {number} y - Y coordinate
17
+ * @param {'left'|'right'|'middle'} [button='left'] - Mouse button
18
+ * @param {Object} [options] - Click options
19
+ * @param {boolean} [options.focusWindow=true] - Focus window before clicking
20
+ * @returns {Promise<{success: boolean, coordinates: {x: number, y: number}}>}
21
+ */
22
+ async function clickAt(x, y, button = 'left', options = {}) {
23
+ x = Math.round(x);
24
+ y = Math.round(y);
25
+ const { focusWindow = true } = options;
26
+
27
+ const buttonFlags = {
28
+ left: { down: '0x0002', up: '0x0004' },
29
+ right: { down: '0x0008', up: '0x0010' },
30
+ middle: { down: '0x0020', up: '0x0040' },
31
+ };
32
+
33
+ const flags = buttonFlags[button] || buttonFlags.left;
34
+
35
+ const psScript = `
36
+ Add-Type -AssemblyName System.Windows.Forms
37
+ Add-Type -TypeDefinition @'
38
+ using System;
39
+ using System.Runtime.InteropServices;
40
+ using System.Text;
41
+
42
+ public class MouseHelper {
43
+ [StructLayout(LayoutKind.Sequential)]
44
+ public struct INPUT {
45
+ public uint type;
46
+ public MOUSEINPUT mi;
47
+ }
48
+
49
+ [StructLayout(LayoutKind.Sequential)]
50
+ public struct MOUSEINPUT {
51
+ public int dx;
52
+ public int dy;
53
+ public uint mouseData;
54
+ public uint dwFlags;
55
+ public uint time;
56
+ public IntPtr dwExtraInfo;
57
+ }
58
+
59
+ [DllImport("user32.dll", SetLastError = true)]
60
+ public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
61
+
62
+ [DllImport("user32.dll")]
63
+ public static extern IntPtr WindowFromPoint(int x, int y);
64
+
65
+ [DllImport("user32.dll")]
66
+ public static extern IntPtr GetAncestor(IntPtr hwnd, uint gaFlags);
67
+
68
+ [DllImport("user32.dll")]
69
+ public static extern bool SetForegroundWindow(IntPtr hWnd);
70
+
71
+ [DllImport("user32.dll")]
72
+ public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
73
+
74
+ [DllImport("user32.dll")]
75
+ public static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr lpdwProcessId);
76
+
77
+ [DllImport("kernel32.dll")]
78
+ public static extern uint GetCurrentThreadId();
79
+
80
+ [DllImport("user32.dll")]
81
+ public static extern IntPtr GetForegroundWindow();
82
+
83
+ [DllImport("user32.dll")]
84
+ public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
85
+
86
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
87
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
88
+
89
+ public const int GWL_EXSTYLE = -20;
90
+ public const int WS_EX_LAYERED = 0x80000;
91
+ public const uint GA_ROOT = 2;
92
+
93
+ public static IntPtr GetRealWindow(int x, int y) {
94
+ IntPtr hwnd = WindowFromPoint(x, y);
95
+ if (hwnd == IntPtr.Zero) return IntPtr.Zero;
96
+
97
+ // Skip transparent overlays
98
+ for (int i = 0; i < 10; i++) {
99
+ int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
100
+ bool isLayered = (exStyle & WS_EX_LAYERED) != 0;
101
+
102
+ StringBuilder sb = new StringBuilder(256);
103
+ GetWindowText(hwnd, sb, 256);
104
+ string title = sb.ToString();
105
+
106
+ // Skip layered windows with no title (likely overlays)
107
+ if (!isLayered || !string.IsNullOrEmpty(title)) {
108
+ return GetAncestor(hwnd, GA_ROOT);
109
+ }
110
+
111
+ IntPtr parent = GetAncestor(hwnd, 1);
112
+ if (parent == IntPtr.Zero || parent == hwnd) break;
113
+ hwnd = parent;
114
+ }
115
+
116
+ return GetAncestor(hwnd, GA_ROOT);
117
+ }
118
+
119
+ public static void ForceForeground(IntPtr hwnd) {
120
+ IntPtr fg = GetForegroundWindow();
121
+ uint fgThread = GetWindowThreadProcessId(fg, IntPtr.Zero);
122
+ uint curThread = GetCurrentThreadId();
123
+
124
+ if (fgThread != curThread) {
125
+ AttachThreadInput(curThread, fgThread, true);
126
+ SetForegroundWindow(hwnd);
127
+ AttachThreadInput(curThread, fgThread, false);
128
+ } else {
129
+ SetForegroundWindow(hwnd);
130
+ }
131
+ }
132
+
133
+ public static void Click(uint downFlag, uint upFlag) {
134
+ var down = new INPUT { type = 0, mi = new MOUSEINPUT { dwFlags = downFlag } };
135
+ var up = new INPUT { type = 0, mi = new MOUSEINPUT { dwFlags = upFlag } };
136
+ SendInput(1, new[] { down }, Marshal.SizeOf(typeof(INPUT)));
137
+ System.Threading.Thread.Sleep(30);
138
+ SendInput(1, new[] { up }, Marshal.SizeOf(typeof(INPUT)));
139
+ }
140
+ }
141
+ '@
142
+
143
+ # Move cursor
144
+ [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y})
145
+ Start-Sleep -Milliseconds ${CONFIG.CLICK_DELAY}
146
+
147
+ ${focusWindow ? `
148
+ # Focus the window under cursor
149
+ $hwnd = [MouseHelper]::GetRealWindow(${x}, ${y})
150
+ if ($hwnd -ne [IntPtr]::Zero) {
151
+ [MouseHelper]::ForceForeground($hwnd)
152
+ Start-Sleep -Milliseconds ${CONFIG.FOCUS_DELAY}
153
+ }
154
+ ` : ''}
155
+
156
+ # Click
157
+ [MouseHelper]::Click(${flags.down}, ${flags.up})
158
+ Write-Output "clicked"
159
+ `;
160
+
161
+ const result = await executePowerShellScript(psScript);
162
+
163
+ const success = result.stdout.includes('clicked');
164
+ log(`${button} click at (${x}, ${y}) - ${success ? 'success' : 'failed'}`);
165
+
166
+ return { success, coordinates: { x, y } };
167
+ }
168
+
169
+ /**
170
+ * Double-click at coordinates
171
+ *
172
+ * @param {number} x - X coordinate
173
+ * @param {number} y - Y coordinate
174
+ * @param {'left'|'right'} [button='left'] - Mouse button
175
+ * @returns {Promise<{success: boolean, coordinates: {x: number, y: number}}>}
176
+ */
177
+ async function doubleClickAt(x, y, button = 'left') {
178
+ await clickAt(x, y, button);
179
+ await sleep(50);
180
+ return await clickAt(x, y, button);
181
+ }
182
+
183
+ module.exports = {
184
+ clickAt,
185
+ doubleClickAt,
186
+ };
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Mouse Drag Operations
3
+ *
4
+ * Drag from one point to another.
5
+ * @module ui-automation/mouse/drag
6
+ */
7
+
8
+ const { executePowerShellScript } = require('../core/powershell');
9
+ const { log } = require('../core/helpers');
10
+
11
+ /**
12
+ * Drag from one point to another
13
+ *
14
+ * @param {number} fromX - Start X coordinate
15
+ * @param {number} fromY - Start Y coordinate
16
+ * @param {number} toX - End X coordinate
17
+ * @param {number} toY - End Y coordinate
18
+ * @param {Object} [options] - Drag options
19
+ * @param {number} [options.steps=10] - Number of intermediate steps
20
+ * @param {number} [options.stepDelay=10] - Delay between steps in ms
21
+ * @returns {Promise<{success: boolean}>}
22
+ */
23
+ async function drag(fromX, fromY, toX, toY, options = {}) {
24
+ const { steps = 10, stepDelay = 10 } = options;
25
+
26
+ const psScript = `
27
+ Add-Type -AssemblyName System.Windows.Forms
28
+ Add-Type -TypeDefinition @'
29
+ using System;
30
+ using System.Runtime.InteropServices;
31
+
32
+ public class DragHelper {
33
+ [StructLayout(LayoutKind.Sequential)]
34
+ public struct INPUT { public uint type; public MOUSEINPUT mi; }
35
+
36
+ [StructLayout(LayoutKind.Sequential)]
37
+ public struct MOUSEINPUT {
38
+ public int dx, dy; public uint mouseData, dwFlags, time; public IntPtr dwExtraInfo;
39
+ }
40
+
41
+ [DllImport("user32.dll")]
42
+ public static extern uint SendInput(uint n, INPUT[] inputs, int size);
43
+
44
+ public static void MouseDown() {
45
+ var inp = new INPUT { type = 0, mi = new MOUSEINPUT { dwFlags = 0x0002 } };
46
+ SendInput(1, new[] { inp }, Marshal.SizeOf(typeof(INPUT)));
47
+ }
48
+
49
+ public static void MouseUp() {
50
+ var inp = new INPUT { type = 0, mi = new MOUSEINPUT { dwFlags = 0x0004 } };
51
+ SendInput(1, new[] { inp }, Marshal.SizeOf(typeof(INPUT)));
52
+ }
53
+ }
54
+ '@
55
+
56
+ # Move to start
57
+ [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${Math.round(fromX)}, ${Math.round(fromY)})
58
+ Start-Sleep -Milliseconds 50
59
+
60
+ # Press down
61
+ [DragHelper]::MouseDown()
62
+ Start-Sleep -Milliseconds 50
63
+
64
+ # Move in steps
65
+ $steps = ${steps}
66
+ for ($i = 1; $i -le $steps; $i++) {
67
+ $progress = $i / $steps
68
+ $x = [int](${Math.round(fromX)} + (${Math.round(toX)} - ${Math.round(fromX)}) * $progress)
69
+ $y = [int](${Math.round(fromY)} + (${Math.round(toY)} - ${Math.round(fromY)}) * $progress)
70
+ [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point($x, $y)
71
+ Start-Sleep -Milliseconds ${stepDelay}
72
+ }
73
+
74
+ # Release
75
+ [DragHelper]::MouseUp()
76
+ Write-Output "dragged"
77
+ `;
78
+
79
+ const result = await executePowerShellScript(psScript);
80
+ const success = result.stdout.includes('dragged');
81
+ log(`Drag from (${fromX}, ${fromY}) to (${toX}, ${toY}) - ${success ? 'success' : 'failed'}`);
82
+
83
+ return { success };
84
+ }
85
+
86
+ module.exports = {
87
+ drag,
88
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Mouse Operations Module
3
+ *
4
+ * @module ui-automation/mouse
5
+ */
6
+
7
+ const { moveMouse, getMousePosition } = require('./movement');
8
+ const { clickAt, doubleClickAt } = require('./click');
9
+ const { drag } = require('./drag');
10
+ const { scroll, scrollUp, scrollDown, scrollLeft, scrollRight } = require('./scroll');
11
+
12
+ module.exports = {
13
+ // Movement
14
+ moveMouse,
15
+ getMousePosition,
16
+
17
+ // Clicks
18
+ clickAt,
19
+ doubleClickAt,
20
+
21
+ // Drag
22
+ drag,
23
+
24
+ // Scrolling
25
+ scroll,
26
+ scrollUp,
27
+ scrollDown,
28
+ scrollLeft,
29
+ scrollRight,
30
+ };
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Mouse Movement
3
+ *
4
+ * Basic mouse position and movement functions.
5
+ * @module ui-automation/mouse/movement
6
+ */
7
+
8
+ const { executePowerShellScript } = require('../core/powershell');
9
+ const { log } = require('../core/helpers');
10
+
11
+ /**
12
+ * Move mouse to coordinates
13
+ *
14
+ * @param {number} x - X coordinate
15
+ * @param {number} y - Y coordinate
16
+ * @returns {Promise<void>}
17
+ */
18
+ async function moveMouse(x, y) {
19
+ x = Math.round(x);
20
+ y = Math.round(y);
21
+
22
+ const script = `
23
+ Add-Type -AssemblyName System.Windows.Forms
24
+ [System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${x}, ${y})
25
+ `;
26
+ await executePowerShellScript(script);
27
+ log(`Mouse moved to (${x}, ${y})`);
28
+ }
29
+
30
+ /**
31
+ * Get current mouse position
32
+ *
33
+ * @returns {Promise<{x: number, y: number}>}
34
+ */
35
+ async function getMousePosition() {
36
+ const result = await executePowerShellScript(`
37
+ Add-Type -AssemblyName System.Windows.Forms
38
+ $pos = [System.Windows.Forms.Cursor]::Position
39
+ Write-Output "$($pos.X),$($pos.Y)"
40
+ `);
41
+ const output = (result.stdout || '').trim();
42
+ const parts = output.split(',');
43
+ const x = parseInt(parts[0], 10) || 0;
44
+ const y = parseInt(parts[1], 10) || 0;
45
+ return { x, y };
46
+ }
47
+
48
+ module.exports = {
49
+ moveMouse,
50
+ getMousePosition,
51
+ };
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Mouse Scroll Operations
3
+ *
4
+ * Vertical and horizontal scrolling.
5
+ * @module ui-automation/mouse/scroll
6
+ */
7
+
8
+ const { executePowerShellScript } = require('../core/powershell');
9
+ const { log } = require('../core/helpers');
10
+
11
+ /**
12
+ * Scroll the mouse wheel
13
+ *
14
+ * @param {number} [amount=3] - Lines to scroll (positive = down, negative = up)
15
+ * @param {Object} [options] - Scroll options
16
+ * @param {number} [options.x] - X coordinate (current position if omitted)
17
+ * @param {number} [options.y] - Y coordinate (current position if omitted)
18
+ * @param {boolean} [options.horizontal=false] - Horizontal scroll instead of vertical
19
+ * @returns {Promise<{success: boolean}>}
20
+ */
21
+ async function scroll(amount = 3, options = {}) {
22
+ const { x, y, horizontal = false } = options;
23
+
24
+ // WHEEL_DELTA = 120 per "click"
25
+ const wheelDelta = Math.round(amount * 120);
26
+
27
+ const psScript = `
28
+ Add-Type -TypeDefinition @'
29
+ using System;
30
+ using System.Runtime.InteropServices;
31
+
32
+ public class ScrollHelper {
33
+ [StructLayout(LayoutKind.Sequential)]
34
+ public struct INPUT { public uint type; public MOUSEINPUT mi; }
35
+
36
+ [StructLayout(LayoutKind.Sequential)]
37
+ public struct MOUSEINPUT {
38
+ public int dx, dy; public uint mouseData, dwFlags, time; public IntPtr dwExtraInfo;
39
+ }
40
+
41
+ [DllImport("user32.dll")]
42
+ public static extern uint SendInput(uint n, INPUT[] inputs, int size);
43
+
44
+ [DllImport("user32.dll")]
45
+ public static extern bool GetCursorPos(out System.Drawing.Point pt);
46
+
47
+ public static void Scroll(int delta, bool horizontal) {
48
+ // MOUSEEVENTF_WHEEL = 0x0800, MOUSEEVENTF_HWHEEL = 0x01000
49
+ uint flags = horizontal ? 0x01000u : 0x0800u;
50
+ var inp = new INPUT {
51
+ type = 0,
52
+ mi = new MOUSEINPUT { mouseData = (uint)delta, dwFlags = flags }
53
+ };
54
+ SendInput(1, new[] { inp }, Marshal.SizeOf(typeof(INPUT)));
55
+ }
56
+ }
57
+ '@
58
+
59
+ Add-Type -AssemblyName System.Windows.Forms
60
+
61
+ ${x !== undefined && y !== undefined ? `[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(${Math.round(x)}, ${Math.round(y)}); Start-Sleep -Milliseconds 50` : '# Use current position'}
62
+
63
+ [ScrollHelper]::Scroll(${-wheelDelta}, $${horizontal})
64
+ Write-Output "scrolled"
65
+ `;
66
+
67
+ const result = await executePowerShellScript(psScript);
68
+ const success = result.stdout.includes('scrolled');
69
+ log(`Scroll ${horizontal ? 'horizontal' : 'vertical'} amount=${amount} - ${success ? 'success' : 'failed'}`);
70
+
71
+ return { success };
72
+ }
73
+
74
+ /**
75
+ * Scroll up
76
+ * @param {number} [lines=3] - Lines to scroll
77
+ * @returns {Promise<{success: boolean}>}
78
+ */
79
+ async function scrollUp(lines = 3) {
80
+ return scroll(-Math.abs(lines));
81
+ }
82
+
83
+ /**
84
+ * Scroll down
85
+ * @param {number} [lines=3] - Lines to scroll
86
+ * @returns {Promise<{success: boolean}>}
87
+ */
88
+ async function scrollDown(lines = 3) {
89
+ return scroll(Math.abs(lines));
90
+ }
91
+
92
+ /**
93
+ * Scroll left
94
+ * @param {number} [amount=3] - Amount to scroll
95
+ * @returns {Promise<{success: boolean}>}
96
+ */
97
+ async function scrollLeft(amount = 3) {
98
+ return scroll(-Math.abs(amount), { horizontal: true });
99
+ }
100
+
101
+ /**
102
+ * Scroll right
103
+ * @param {number} [amount=3] - Amount to scroll
104
+ * @returns {Promise<{success: boolean}>}
105
+ */
106
+ async function scrollRight(amount = 3) {
107
+ return scroll(Math.abs(amount), { horizontal: true });
108
+ }
109
+
110
+ module.exports = {
111
+ scroll,
112
+ scrollUp,
113
+ scrollDown,
114
+ scrollLeft,
115
+ scrollRight,
116
+ };