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,164 @@
1
+ /**
2
+ * UI Automation Module
3
+ *
4
+ * Comprehensive Windows UI automation using semantic element discovery,
5
+ * SendInput API for reliable input, and PowerShell for system integration.
6
+ *
7
+ * @module ui-automation
8
+ *
9
+ * @example
10
+ * const ui = require('./ui-automation');
11
+ *
12
+ * // Find and click a button by text
13
+ * await ui.click({ text: 'Submit' });
14
+ *
15
+ * // Type in a text field
16
+ * await ui.click({ automationId: 'searchBox' });
17
+ * await ui.typeText('Hello world');
18
+ *
19
+ * // Wait for element and click
20
+ * await ui.waitAndClick({ text: 'OK' }, { timeout: 5000 });
21
+ *
22
+ * // Take screenshot
23
+ * await ui.screenshot({ path: 'capture.png' });
24
+ */
25
+
26
+ // Configuration
27
+ const { CONFIG, CONTROL_TYPES } = require('./config');
28
+
29
+ // Core utilities
30
+ const { sleep, debug, log, executePowerShellScript } = require('./core');
31
+
32
+ // Element operations
33
+ const {
34
+ findElements,
35
+ findElement,
36
+ waitForElement,
37
+ waitForElementGone
38
+ } = require('./elements');
39
+
40
+ // Mouse operations
41
+ const {
42
+ moveMouse,
43
+ getMousePosition,
44
+ clickAt,
45
+ doubleClickAt,
46
+ drag,
47
+ scroll,
48
+ scrollUp,
49
+ scrollDown,
50
+ scrollLeft,
51
+ scrollRight,
52
+ } = require('./mouse');
53
+
54
+ // Keyboard operations
55
+ const {
56
+ typeText,
57
+ sendKeys,
58
+ keyDown,
59
+ keyUp,
60
+ VK,
61
+ } = require('./keyboard');
62
+
63
+ // Window operations
64
+ const {
65
+ getActiveWindow,
66
+ findWindows,
67
+ focusWindow,
68
+ minimizeWindow,
69
+ maximizeWindow,
70
+ restoreWindow,
71
+ } = require('./window');
72
+
73
+ // High-level interactions
74
+ const {
75
+ click,
76
+ clickByText,
77
+ clickByAutomationId,
78
+ rightClick,
79
+ doubleClick,
80
+ clickElement,
81
+ invokeElement,
82
+ fillField,
83
+ selectDropdownItem,
84
+ waitForWindow,
85
+ clickSequence,
86
+ hover,
87
+ waitAndClick,
88
+ clickAndWaitFor,
89
+ selectFromDropdown,
90
+ } = require('./interactions');
91
+
92
+ // Screenshot
93
+ const {
94
+ screenshot,
95
+ screenshotActiveWindow,
96
+ screenshotElement,
97
+ } = require('./screenshot');
98
+
99
+ module.exports = {
100
+ // Configuration
101
+ CONFIG,
102
+ CONTROL_TYPES,
103
+
104
+ // Core utilities
105
+ sleep,
106
+ debug,
107
+ log,
108
+ executePowerShellScript,
109
+
110
+ // Element operations
111
+ findElements,
112
+ findElement,
113
+ waitForElement,
114
+ waitForElementGone,
115
+
116
+ // Mouse operations - low level
117
+ moveMouse,
118
+ getMousePosition,
119
+ clickAt,
120
+ doubleClickAt,
121
+ drag,
122
+ scroll,
123
+ scrollUp,
124
+ scrollDown,
125
+ scrollLeft,
126
+ scrollRight,
127
+
128
+ // Keyboard operations
129
+ typeText,
130
+ sendKeys,
131
+ keyDown,
132
+ keyUp,
133
+ VK,
134
+
135
+ // Window operations
136
+ getActiveWindow,
137
+ findWindows,
138
+ focusWindow,
139
+ minimizeWindow,
140
+ maximizeWindow,
141
+ restoreWindow,
142
+
143
+ // High-level interactions (element-based clicks)
144
+ click,
145
+ clickByText,
146
+ clickByAutomationId,
147
+ rightClick,
148
+ doubleClick,
149
+ clickElement,
150
+ invokeElement,
151
+ fillField,
152
+ selectDropdownItem,
153
+ waitForWindow,
154
+ clickSequence,
155
+ hover,
156
+ waitAndClick,
157
+ clickAndWaitFor,
158
+ selectFromDropdown,
159
+
160
+ // Screenshot
161
+ screenshot,
162
+ screenshotActiveWindow,
163
+ screenshotElement,
164
+ };
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Element Click Interactions
3
+ *
4
+ * Click on UI elements by criteria (text, automationId, etc.)
5
+ * @module ui-automation/interactions/element-click
6
+ */
7
+
8
+ const { findElement, waitForElement } = require('../elements');
9
+ const { clickAt, doubleClickAt } = require('../mouse');
10
+ const { executePowerShellScript } = require('../core/powershell');
11
+ const { log, sleep } = require('../core/helpers');
12
+
13
+ /**
14
+ * Click on an element found by criteria
15
+ *
16
+ * @param {Object} criteria - Element search criteria
17
+ * @param {string} [criteria.text] - Element text/name
18
+ * @param {string} [criteria.automationId] - Automation ID
19
+ * @param {string} [criteria.controlType] - Control type
20
+ * @param {string} [criteria.className] - Class name
21
+ * @param {string} [criteria.windowTitle] - Window title to search in
22
+ * @param {Object} [options] - Click options
23
+ * @param {boolean} [options.doubleClick=false] - Double click instead
24
+ * @param {string} [options.button='left'] - Mouse button
25
+ * @param {boolean} [options.focusWindow=true] - Focus window first
26
+ * @param {number} [options.waitTimeout=0] - Wait for element (ms, 0 = no wait)
27
+ * @returns {Promise<{success: boolean, element: Object|null}>}
28
+ */
29
+ async function click(criteria, options = {}) {
30
+ const {
31
+ doubleClick = false,
32
+ button = 'left',
33
+ focusWindow = true,
34
+ waitTimeout = 0,
35
+ } = options;
36
+
37
+ // Find or wait for element
38
+ let findResult;
39
+ if (waitTimeout > 0) {
40
+ findResult = await waitForElement(criteria, { timeout: waitTimeout });
41
+ } else {
42
+ findResult = await findElement(criteria);
43
+ }
44
+
45
+ // Extract element from result
46
+ const element = findResult?.element;
47
+
48
+ if (!element || !element.bounds) {
49
+ log(`click: Element not found for criteria: ${JSON.stringify(criteria)}`, 'warn');
50
+ return { success: false, element: null, error: findResult?.error || 'Element not found' };
51
+ }
52
+
53
+ // Calculate center point
54
+ const bounds = element.bounds;
55
+ const x = bounds.x + bounds.width / 2;
56
+ const y = bounds.y + bounds.height / 2;
57
+
58
+ // Focus window if needed
59
+ if (focusWindow && element.windowHwnd) {
60
+ const { focusWindow: doFocus } = require('../window');
61
+ await doFocus(element.windowHwnd);
62
+ await sleep(50);
63
+ }
64
+
65
+ // Click
66
+ const clickFn = doubleClick ? doubleClickAt : clickAt;
67
+ const clickResult = await clickFn(x, y, { button, focusWindow: false });
68
+
69
+ log(`click on "${element.name || element.automationId}" at (${Math.round(x)}, ${Math.round(y)}) - ${clickResult.success ? 'success' : 'failed'}`);
70
+
71
+ return { success: clickResult.success, element };
72
+ }
73
+
74
+ /**
75
+ * Click element by text
76
+ *
77
+ * @param {string} text - Element text to find
78
+ * @param {Object} [options] - Click options
79
+ * @returns {Promise<{success: boolean, element: Object|null}>}
80
+ */
81
+ async function clickByText(text, options = {}) {
82
+ return click({ text }, options);
83
+ }
84
+
85
+ /**
86
+ * Click element by automation ID
87
+ *
88
+ * @param {string} automationId - Automation ID
89
+ * @param {Object} [options] - Click options
90
+ * @returns {Promise<{success: boolean, element: Object|null}>}
91
+ */
92
+ async function clickByAutomationId(automationId, options = {}) {
93
+ return click({ automationId }, options);
94
+ }
95
+
96
+ /**
97
+ * Right-click on an element
98
+ *
99
+ * @param {Object} criteria - Element search criteria
100
+ * @param {Object} [options] - Additional options
101
+ * @returns {Promise<{success: boolean, element: Object|null}>}
102
+ */
103
+ async function rightClick(criteria, options = {}) {
104
+ return click(criteria, { ...options, button: 'right' });
105
+ }
106
+
107
+ /**
108
+ * Double-click on an element
109
+ *
110
+ * @param {Object} criteria - Element search criteria
111
+ * @param {Object} [options] - Additional options
112
+ * @returns {Promise<{success: boolean, element: Object|null}>}
113
+ */
114
+ async function doubleClick(criteria, options = {}) {
115
+ return click(criteria, { ...options, doubleClick: true });
116
+ }
117
+
118
+ /**
119
+ * Click on an element object directly (low-level)
120
+ *
121
+ * @param {Object} element - Element with bounds property
122
+ * @param {Object} [options] - Click options
123
+ * @param {string} [options.button='left'] - Mouse button
124
+ * @param {boolean} [options.useInvoke=true] - Try Invoke pattern first
125
+ * @returns {Promise<{success: boolean, method: string, error?: string}>}
126
+ */
127
+ async function clickElement(element, options = {}) {
128
+ const { button = 'left', useInvoke = true } = options;
129
+
130
+ if (!element || !element.bounds) {
131
+ return { success: false, error: 'Invalid element' };
132
+ }
133
+
134
+ const bounds = element.bounds;
135
+ const centerX = bounds.x + bounds.width / 2;
136
+ const centerY = bounds.y + bounds.height / 2;
137
+
138
+ // Strategy 1: Try Invoke pattern for buttons
139
+ if (useInvoke && element.patterns?.includes('InvokePatternIdentifiers.Pattern')) {
140
+ log(`Attempting Invoke pattern for "${element.name}"`);
141
+ const invokeResult = await invokeElement(element);
142
+ if (invokeResult.success) {
143
+ return { success: true, method: 'invoke', element };
144
+ }
145
+ }
146
+
147
+ // Strategy 2: Click
148
+ log(`Clicking "${element.name}" at (${centerX}, ${centerY})`);
149
+ const clickResult = await clickAt(centerX, centerY, { button, focusWindow: true });
150
+
151
+ return {
152
+ success: clickResult.success,
153
+ method: 'sendInput',
154
+ element,
155
+ coordinates: clickResult.coordinates,
156
+ };
157
+ }
158
+
159
+ /**
160
+ * Invoke an element using UI Automation Invoke pattern
161
+ * Works directly with buttons without simulating mouse clicks
162
+ *
163
+ * @param {Object} element - Element to invoke
164
+ * @returns {Promise<{success: boolean, error?: string}>}
165
+ */
166
+ async function invokeElement(element) {
167
+ const searchName = (element.name || '').replace(/"/g, '`"');
168
+
169
+ const psScript = `
170
+ Add-Type -AssemblyName UIAutomationClient
171
+ Add-Type -AssemblyName UIAutomationTypes
172
+
173
+ $root = [System.Windows.Automation.AutomationElement]::RootElement
174
+ $condition = [System.Windows.Automation.PropertyCondition]::new(
175
+ [System.Windows.Automation.AutomationElement]::NameProperty,
176
+ "${searchName}"
177
+ )
178
+ $element = $root.FindFirst([System.Windows.Automation.TreeScope]::Descendants, $condition)
179
+
180
+ if ($element -eq $null) {
181
+ Write-Output '{"success": false, "error": "Element not found"}'
182
+ exit
183
+ }
184
+
185
+ try {
186
+ $invokePattern = $element.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern)
187
+ $invokePattern.Invoke()
188
+ Write-Output '{"success": true, "method": "invoke"}'
189
+ } catch {
190
+ Write-Output "{\\"success\\": false, \\"error\\": \\"$($_.Exception.Message)\\"}"
191
+ }
192
+ `;
193
+
194
+ const result = await executePowerShellScript(psScript);
195
+
196
+ try {
197
+ return JSON.parse(result.stdout.trim());
198
+ } catch {
199
+ return { success: false, error: result.error || 'Parse error' };
200
+ }
201
+ }
202
+
203
+ module.exports = {
204
+ click,
205
+ clickByText,
206
+ clickByAutomationId,
207
+ rightClick,
208
+ doubleClick,
209
+ clickElement,
210
+ invokeElement,
211
+ };
@@ -0,0 +1,230 @@
1
+ /**
2
+ * High-Level UI Interactions
3
+ *
4
+ * Complex automation workflows and convenience functions.
5
+ * @module ui-automation/interactions/high-level
6
+ */
7
+
8
+ const { findElement, findElements, waitForElement } = require('../elements');
9
+ const { click, clickByText } = require('./element-click');
10
+ const { typeText, sendKeys } = require('../keyboard');
11
+ const { focusWindow, findWindows } = require('../window');
12
+ const { log, sleep } = require('../core/helpers');
13
+
14
+ /**
15
+ * Fill a text field by clicking it then typing
16
+ *
17
+ * @param {Object} criteria - Element search criteria
18
+ * @param {string} text - Text to type
19
+ * @param {Object} [options] - Options
20
+ * @param {boolean} [options.clear=true] - Clear field first (Ctrl+A)
21
+ * @returns {Promise<{success: boolean}>}
22
+ */
23
+ async function fillField(criteria, text, options = {}) {
24
+ const { clear = true } = options;
25
+
26
+ // Click the field
27
+ const clickResult = await click(criteria);
28
+ if (!clickResult.success) {
29
+ return { success: false };
30
+ }
31
+
32
+ await sleep(50);
33
+
34
+ // Clear if requested
35
+ if (clear) {
36
+ await sendKeys('^a');
37
+ await sleep(20);
38
+ }
39
+
40
+ // Type text
41
+ const typeResult = await typeText(text);
42
+ return { success: typeResult.success };
43
+ }
44
+
45
+ /**
46
+ * Select an item from a dropdown/combobox
47
+ *
48
+ * @param {Object} dropdownCriteria - Criteria to find the dropdown
49
+ * @param {string|Object} itemCriteria - Item text or criteria
50
+ * @param {Object} [options] - Options
51
+ * @param {number} [options.itemWait=1000] - Time to wait for dropdown items to appear
52
+ * @returns {Promise<{success: boolean}>}
53
+ */
54
+ async function selectDropdownItem(dropdownCriteria, itemCriteria, options = {}) {
55
+ const { itemWait = 1000 } = options;
56
+
57
+ // Click dropdown to open
58
+ const openResult = await click(dropdownCriteria);
59
+ if (!openResult.success) {
60
+ log('selectDropdownItem: Failed to open dropdown', 'warn');
61
+ return { success: false };
62
+ }
63
+
64
+ await sleep(itemWait);
65
+
66
+ // Click item
67
+ const itemQuery = typeof itemCriteria === 'string'
68
+ ? { text: itemCriteria }
69
+ : itemCriteria;
70
+
71
+ const itemResult = await click(itemQuery);
72
+ return { success: itemResult.success };
73
+ }
74
+
75
+ /**
76
+ * Wait for a window and focus it
77
+ *
78
+ * @param {string|Object} criteria - Window title or search criteria
79
+ * @param {Object} [options] - Options
80
+ * @param {number} [options.timeout=10000] - Timeout in ms
81
+ * @param {number} [options.pollInterval=500] - Poll interval in ms
82
+ * @returns {Promise<{success: boolean, window: Object|null}>}
83
+ */
84
+ async function waitForWindow(criteria, options = {}) {
85
+ const { timeout = 10000, pollInterval = 500 } = options;
86
+ const searchCriteria = typeof criteria === 'string' ? { title: criteria } : criteria;
87
+
88
+ const startTime = Date.now();
89
+
90
+ while (Date.now() - startTime < timeout) {
91
+ const windows = await findWindows(searchCriteria);
92
+ if (windows.length > 0) {
93
+ const result = await focusWindow(windows[0].hwnd);
94
+ return { success: result.success, window: windows[0] };
95
+ }
96
+ await sleep(pollInterval);
97
+ }
98
+
99
+ log(`waitForWindow: Timeout waiting for window`, 'warn');
100
+ return { success: false, window: null };
101
+ }
102
+
103
+ /**
104
+ * Click a sequence of elements in order
105
+ *
106
+ * @param {Array<Object>} steps - Array of {criteria, options?, delay?}
107
+ * @returns {Promise<{success: boolean, completedSteps: number}>}
108
+ */
109
+ async function clickSequence(steps) {
110
+ let completedSteps = 0;
111
+
112
+ for (const step of steps) {
113
+ const { criteria, options = {}, delay = 200 } = step;
114
+
115
+ const result = await click(criteria, options);
116
+ if (!result.success) {
117
+ log(`clickSequence: Failed at step ${completedSteps + 1}`, 'warn');
118
+ return { success: false, completedSteps };
119
+ }
120
+
121
+ completedSteps++;
122
+ await sleep(delay);
123
+ }
124
+
125
+ return { success: true, completedSteps };
126
+ }
127
+
128
+ /**
129
+ * Perform hover over an element
130
+ *
131
+ * @param {Object} criteria - Element search criteria
132
+ * @param {Object} [options] - Options
133
+ * @param {number} [options.duration=500] - How long to hover in ms
134
+ * @returns {Promise<{success: boolean, element: Object|null}>}
135
+ */
136
+ async function hover(criteria, options = {}) {
137
+ const { duration = 500 } = options;
138
+ const { moveMouse } = require('../mouse');
139
+
140
+ const element = await findElement(criteria);
141
+ if (!element) {
142
+ return { success: false, element: null };
143
+ }
144
+
145
+ const bounds = element.bounds;
146
+ const x = bounds.x + bounds.width / 2;
147
+ const y = bounds.y + bounds.height / 2;
148
+
149
+ await moveMouse(x, y);
150
+ await sleep(duration);
151
+
152
+ return { success: true, element };
153
+ }
154
+
155
+ /**
156
+ * Wait for element and click
157
+ * Convenience wrapper combining wait + click
158
+ *
159
+ * @param {Object} criteria - Element search criteria
160
+ * @param {Object} [options] - Options
161
+ * @param {number} [options.timeout=5000] - Wait timeout
162
+ * @returns {Promise<{success: boolean, element: Object|null}>}
163
+ */
164
+ async function waitAndClick(criteria, options = {}) {
165
+ const { timeout = 5000, ...clickOptions } = options;
166
+ return click(criteria, { ...clickOptions, waitTimeout: timeout });
167
+ }
168
+
169
+ /**
170
+ * Click an element then wait for another element to appear
171
+ *
172
+ * @param {Object} clickCriteria - Element to click
173
+ * @param {Object} waitCriteria - Element to wait for
174
+ * @param {number} [timeout=10000] - Wait timeout
175
+ * @returns {Promise<{success: boolean, clickedElement?: Object, resultElement?: Object, error?: string}>}
176
+ */
177
+ async function clickAndWaitFor(clickCriteria, waitCriteria, timeout = 10000) {
178
+ const clickResult = await click(clickCriteria);
179
+ if (!clickResult.success) {
180
+ return { success: false, error: `Click failed: ${clickResult.error || 'Element not found'}` };
181
+ }
182
+
183
+ const waitResult = await waitForElement(waitCriteria, { timeout });
184
+ return {
185
+ success: !!waitResult,
186
+ clickedElement: clickResult.element,
187
+ resultElement: waitResult,
188
+ error: waitResult ? undefined : 'Wait timeout',
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Select from a dropdown/combobox (alias for selectDropdownItem)
194
+ *
195
+ * @param {Object} dropdownCriteria - Dropdown element criteria
196
+ * @param {string} optionText - Text of option to select
197
+ * @param {number} [timeout=5000] - Wait timeout for options
198
+ * @returns {Promise<{success: boolean, error?: string}>}
199
+ */
200
+ async function selectFromDropdown(dropdownCriteria, optionText, timeout = 5000) {
201
+ // Click the dropdown to open it
202
+ const openResult = await click(dropdownCriteria);
203
+ if (!openResult.success) {
204
+ return { success: false, error: `Failed to open dropdown` };
205
+ }
206
+
207
+ await sleep(200);
208
+
209
+ // Find and click the option
210
+ const optionResult = await waitAndClick({ text: optionText }, { timeout });
211
+ if (!optionResult.success) {
212
+ // Try to close dropdown if option not found
213
+ const { sendKeys } = require('../keyboard');
214
+ await sendKeys('{ESC}');
215
+ return { success: false, error: `Option "${optionText}" not found` };
216
+ }
217
+
218
+ return { success: true, selectedOption: optionText };
219
+ }
220
+
221
+ module.exports = {
222
+ fillField,
223
+ selectDropdownItem,
224
+ waitForWindow,
225
+ clickSequence,
226
+ hover,
227
+ waitAndClick,
228
+ clickAndWaitFor,
229
+ selectFromDropdown,
230
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Interactions Module
3
+ *
4
+ * @module ui-automation/interactions
5
+ */
6
+
7
+ const {
8
+ click,
9
+ clickByText,
10
+ clickByAutomationId,
11
+ rightClick,
12
+ doubleClick,
13
+ clickElement,
14
+ invokeElement,
15
+ } = require('./element-click');
16
+
17
+ const {
18
+ fillField,
19
+ selectDropdownItem,
20
+ waitForWindow,
21
+ clickSequence,
22
+ hover,
23
+ waitAndClick,
24
+ clickAndWaitFor,
25
+ selectFromDropdown,
26
+ } = require('./high-level');
27
+
28
+ module.exports = {
29
+ // Element clicks
30
+ click,
31
+ clickByText,
32
+ clickByAutomationId,
33
+ rightClick,
34
+ doubleClick,
35
+ clickElement,
36
+ invokeElement,
37
+
38
+ // High-level interactions
39
+ fillField,
40
+ selectDropdownItem,
41
+ waitForWindow,
42
+ clickSequence,
43
+ hover,
44
+ waitAndClick,
45
+ clickAndWaitFor,
46
+ selectFromDropdown,
47
+ };
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Keyboard Module
3
+ *
4
+ * @module ui-automation/keyboard
5
+ */
6
+
7
+ const { typeText, sendKeys, keyDown, keyUp, VK } = require('./input');
8
+
9
+ module.exports = {
10
+ typeText,
11
+ sendKeys,
12
+ keyDown,
13
+ keyUp,
14
+ VK,
15
+ };