openclaw-cascade-plugin 1.0.12 → 1.0.14

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 (80) hide show
  1. package/dist/grpc-client.d.ts +17 -0
  2. package/dist/grpc-client.d.ts.map +1 -0
  3. package/dist/grpc-client.js +154 -0
  4. package/dist/grpc-client.js.map +1 -0
  5. package/dist/index.d.ts +2 -3
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +14 -54
  8. package/dist/index.js.map +1 -1
  9. package/dist/test-utils/mocks.d.ts +6 -4
  10. package/dist/test-utils/mocks.d.ts.map +1 -1
  11. package/dist/test-utils/mocks.js +24 -14
  12. package/dist/test-utils/mocks.js.map +1 -1
  13. package/dist/tools/desktop-automation.d.ts +2 -7
  14. package/dist/tools/desktop-automation.d.ts.map +1 -1
  15. package/dist/tools/desktop-automation.js +64 -123
  16. package/dist/tools/desktop-automation.js.map +1 -1
  17. package/dist/tools/index.d.ts +3 -10
  18. package/dist/tools/index.d.ts.map +1 -1
  19. package/dist/tools/index.js +3 -17
  20. package/dist/tools/index.js.map +1 -1
  21. package/openclaw.plugin.json +1 -1
  22. package/package.json +13 -2
  23. package/proto/cascade.proto +297 -0
  24. package/PHASE1_SUMMARY.md +0 -191
  25. package/PHASE3_SUMMARY.md +0 -195
  26. package/dist/cascade-client.d.ts +0 -53
  27. package/dist/cascade-client.d.ts.map +0 -1
  28. package/dist/cascade-client.js +0 -179
  29. package/dist/cascade-client.js.map +0 -1
  30. package/dist/python-manager.d.ts +0 -59
  31. package/dist/python-manager.d.ts.map +0 -1
  32. package/dist/python-manager.js +0 -190
  33. package/dist/python-manager.js.map +0 -1
  34. package/dist/tools/api-tools.d.ts +0 -9
  35. package/dist/tools/api-tools.d.ts.map +0 -1
  36. package/dist/tools/api-tools.js +0 -102
  37. package/dist/tools/api-tools.js.map +0 -1
  38. package/dist/tools/sandbox-tools.d.ts +0 -9
  39. package/dist/tools/sandbox-tools.d.ts.map +0 -1
  40. package/dist/tools/sandbox-tools.js +0 -79
  41. package/dist/tools/sandbox-tools.js.map +0 -1
  42. package/dist/tools/web-automation.d.ts +0 -9
  43. package/dist/tools/web-automation.d.ts.map +0 -1
  44. package/dist/tools/web-automation.js +0 -471
  45. package/dist/tools/web-automation.js.map +0 -1
  46. package/jest.setup.js +0 -19
  47. package/openclaw-cascade-plugin-1.0.0.tgz +0 -0
  48. package/openclaw-cascade-plugin-1.0.10.tgz +0 -0
  49. package/openclaw-cascade-plugin-1.0.11.tgz +0 -0
  50. package/openclaw-cascade-plugin-1.0.12.tgz +0 -0
  51. package/openclaw-cascade-plugin-1.0.4.tgz +0 -0
  52. package/openclaw-cascade-plugin-1.0.6.tgz +0 -0
  53. package/openclaw-cascade-plugin-1.0.7.tgz +0 -0
  54. package/openclaw-cascade-plugin-1.0.8.tgz +0 -0
  55. package/openclaw-cascade-plugin-1.0.9.tgz +0 -0
  56. package/scripts/postinstall.js +0 -84
  57. package/src/a2a-client.ts +0 -66
  58. package/src/cascade-client.test.ts +0 -400
  59. package/src/cascade-client.ts +0 -198
  60. package/src/config.test.ts +0 -189
  61. package/src/config.ts +0 -137
  62. package/src/index.ts +0 -202
  63. package/src/python-manager.test.ts +0 -187
  64. package/src/python-manager.ts +0 -230
  65. package/src/test-utils/helpers.ts +0 -107
  66. package/src/test-utils/index.ts +0 -2
  67. package/src/test-utils/mocks.ts +0 -101
  68. package/src/tools/a2a-tools.ts +0 -162
  69. package/src/tools/api-tools.ts +0 -110
  70. package/src/tools/desktop-automation.test.ts +0 -308
  71. package/src/tools/desktop-automation.ts +0 -366
  72. package/src/tools/index.ts +0 -13
  73. package/src/tools/response-helpers.ts +0 -78
  74. package/src/tools/sandbox-tools.ts +0 -83
  75. package/src/tools/tool-registry.ts +0 -51
  76. package/src/tools/web-automation.test.ts +0 -177
  77. package/src/tools/web-automation.ts +0 -518
  78. package/src/types/index.ts +0 -133
  79. package/src/wsl.ts +0 -53
  80. package/tsconfig.json +0 -27
@@ -1,308 +0,0 @@
1
- /**
2
- * Tests for Desktop Automation Tools
3
- */
4
-
5
- import { registerDesktopTools } from './desktop-automation';
6
- import { ToolRegistry } from './tool-registry';
7
- import { MockCascadeMcpClient } from '../test-utils';
8
-
9
- describe('Desktop Automation Tools', () => {
10
- let registry: ToolRegistry;
11
- let mockClient: MockCascadeMcpClient;
12
-
13
- beforeEach(() => {
14
- registry = new ToolRegistry();
15
- mockClient = new MockCascadeMcpClient();
16
- registerDesktopTools(registry, async () => mockClient as any);
17
- });
18
-
19
- describe('cascade_click_element', () => {
20
- test('should be registered', () => {
21
- expect(registry.has('cascade_click_element')).toBe(true);
22
- });
23
-
24
- test('should click element by ID', async () => {
25
- // Arrange
26
- mockClient.registerMockTool('click_element', () => ({ success: true }));
27
-
28
- // Act
29
- const result = await registry.call('cascade_click_element', {
30
- platform_source: 'WINDOWS',
31
- id: 'button1'
32
- });
33
-
34
- // Assert
35
- expect(mockClient.callTool).toHaveBeenCalledWith('click_element', {
36
- platform_source: 'WINDOWS',
37
- id: 'button1'
38
- });
39
- expect(result.content[0].text).toContain('success');
40
- });
41
-
42
- test('should handle click failure', async () => {
43
- // Arrange
44
- mockClient.simulateError(new Error('Element not found'));
45
-
46
- // Act
47
- const result = await registry.call('cascade_click_element', {
48
- platform_source: 'WINDOWS',
49
- id: 'nonexistent'
50
- });
51
-
52
- // Assert
53
- expect(result.isError).toBe(true);
54
- expect(result.content[0].text).toContain('Element not found');
55
- });
56
-
57
- test('should require platform_source', async () => {
58
- // Act
59
- const result = await registry.call('cascade_click_element', {
60
- id: 'button1'
61
- });
62
-
63
- // Assert
64
- expect(result.isError).toBe(true);
65
- expect(result.content[0].text).toContain('platform_source is required');
66
- });
67
- });
68
-
69
- describe('cascade_type_text', () => {
70
- test('should be registered', () => {
71
- expect(registry.has('cascade_type_text')).toBe(true);
72
- });
73
-
74
- test('should type text into element', async () => {
75
- // Arrange
76
- mockClient.registerMockTool('type_text', () => ({ success: true }));
77
-
78
- // Act
79
- await registry.call('cascade_type_text', {
80
- selector: { platform_source: 'WINDOWS', id: 'input1' },
81
- text: 'Hello World'
82
- });
83
-
84
- // Assert
85
- expect(mockClient.callTool).toHaveBeenCalledWith('type_text', {
86
- selector: { platform_source: 'WINDOWS', id: 'input1' },
87
- text: 'Hello World'
88
- });
89
- });
90
-
91
- test('should require selector', async () => {
92
- // Act
93
- const result = await registry.call('cascade_type_text', {
94
- text: 'Hello'
95
- });
96
-
97
- // Assert
98
- expect(result.isError).toBe(true);
99
- expect(result.content[0].text).toContain('selector');
100
- });
101
-
102
- test('should require text', async () => {
103
- // Act
104
- const result = await registry.call('cascade_type_text', {
105
- selector: { platform_source: 'WINDOWS' }
106
- });
107
-
108
- // Assert
109
- expect(result.isError).toBe(true);
110
- expect(result.content[0].text).toContain('text is required');
111
- });
112
- });
113
-
114
- describe('cascade_get_semantic_tree', () => {
115
- test('should be registered', () => {
116
- expect(registry.has('cascade_get_semantic_tree')).toBe(true);
117
- });
118
-
119
- test('should return semantic tree', async () => {
120
- // Arrange
121
- mockClient.registerMockTool('get_semantic_tree', () => ({
122
- elements: [
123
- { id: '1', name: 'Button', control_type: 'BUTTON' },
124
- { id: '2', name: 'Input', control_type: 'INPUT' }
125
- ]
126
- }));
127
-
128
- // Act
129
- const result = await registry.call('cascade_get_semantic_tree', {});
130
-
131
- // Assert
132
- expect(mockClient.callTool).toHaveBeenCalledWith('get_semantic_tree', {});
133
- expect(result.content[0].text).toContain('Button');
134
- expect(result.content[0].text).toContain('Input');
135
- });
136
-
137
- test('should handle empty tree', async () => {
138
- // Arrange
139
- mockClient.registerMockTool('get_semantic_tree', () => ({
140
- elements: []
141
- }));
142
-
143
- // Act
144
- const result = await registry.call('cascade_get_semantic_tree', {});
145
-
146
- // Assert
147
- expect(result.content[0].text).toContain('elements');
148
- });
149
- });
150
-
151
- describe('cascade_get_screenshot', () => {
152
- test('should be registered', () => {
153
- expect(registry.has('cascade_get_screenshot')).toBe(true);
154
- });
155
-
156
- test('should return embedded screenshot when small', async () => {
157
- // Arrange
158
- const smallImage = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';
159
- mockClient.registerMockTool('get_screenshot', () => ({
160
- image: smallImage,
161
- format: 'PNG',
162
- marks: [{ element_id: '1', label: 'A' }]
163
- }));
164
-
165
- // Act
166
- const result = await registry.call('cascade_get_screenshot', {});
167
-
168
- // Assert
169
- expect(result.content[0].type).toBe('image');
170
- expect(result.content[0].source.data).toBe(smallImage);
171
- });
172
-
173
- test('should save large screenshot to disk', async () => {
174
- // Arrange
175
- const largeImage = 'A'.repeat(5000000); // 5MB base64 = ~3.75MB actual
176
- const diskRegistry = new ToolRegistry();
177
- registerDesktopTools(diskRegistry, async () => mockClient as any, { screenshotMode: 'disk' } as any);
178
-
179
- mockClient.registerMockTool('get_screenshot', () => ({
180
- image: largeImage,
181
- format: 'PNG',
182
- marks: []
183
- }));
184
-
185
- // Act
186
- const result = await diskRegistry.call('cascade_get_screenshot', {});
187
-
188
- // Assert
189
- expect(result.content[0].type).toBe('text');
190
- expect(result.content[0].text).toContain('saved');
191
- });
192
- });
193
-
194
- describe('cascade_start_app', () => {
195
- test('should be registered', () => {
196
- expect(registry.has('cascade_start_app')).toBe(true);
197
- });
198
-
199
- test('should start application', async () => {
200
- // Arrange
201
- mockClient.registerMockTool('start_app', () => ({ success: true }));
202
-
203
- // Act
204
- const result = await registry.call('cascade_start_app', {
205
- app_name: 'notepad'
206
- });
207
-
208
- // Assert
209
- expect(mockClient.callTool).toHaveBeenCalledWith('start_app', {
210
- app_name: 'notepad'
211
- });
212
- expect(result.content[0].text).toContain('success');
213
- });
214
-
215
- test('should require app_name', async () => {
216
- // Act
217
- const result = await registry.call('cascade_start_app', {});
218
-
219
- // Assert
220
- expect(result.isError).toBe(true);
221
- expect(result.content[0].text).toContain('app_name is required');
222
- });
223
- });
224
-
225
- describe('cascade_hover_element', () => {
226
- test('should be registered', () => {
227
- expect(registry.has('cascade_hover_element')).toBe(true);
228
- });
229
-
230
- test('should hover over element', async () => {
231
- // Arrange
232
- mockClient.registerMockTool('hover_element', () => ({ success: true }));
233
-
234
- // Act
235
- await registry.call('cascade_hover_element', {
236
- selector: { platform_source: 'WINDOWS', id: 'button1' }
237
- });
238
-
239
- // Assert
240
- expect(mockClient.callTool).toHaveBeenCalledWith('hover_element', {
241
- selector: { platform_source: 'WINDOWS', id: 'button1' }
242
- });
243
- });
244
- });
245
-
246
- describe('cascade_focus_element', () => {
247
- test('should be registered', () => {
248
- expect(registry.has('cascade_focus_element')).toBe(true);
249
- });
250
-
251
- test('should focus on element', async () => {
252
- // Arrange
253
- mockClient.registerMockTool('focus_element', () => ({ success: true }));
254
-
255
- // Act
256
- await registry.call('cascade_focus_element', {
257
- selector: { platform_source: 'WINDOWS', id: 'input1' }
258
- });
259
-
260
- // Assert
261
- expect(mockClient.callTool).toHaveBeenCalledWith('focus_element', {
262
- selector: { platform_source: 'WINDOWS', id: 'input1' }
263
- });
264
- });
265
- });
266
-
267
- describe('cascade_scroll_element', () => {
268
- test('should be registered', () => {
269
- expect(registry.has('cascade_scroll_element')).toBe(true);
270
- });
271
-
272
- test('should scroll element', async () => {
273
- // Arrange
274
- mockClient.registerMockTool('scroll_element', () => ({ success: true }));
275
-
276
- // Act
277
- await registry.call('cascade_scroll_element', {
278
- selector: { platform_source: 'WINDOWS', id: 'scrollable' }
279
- });
280
-
281
- // Assert
282
- expect(mockClient.callTool).toHaveBeenCalledWith('scroll_element', {
283
- selector: { platform_source: 'WINDOWS', id: 'scrollable' }
284
- });
285
- });
286
- });
287
-
288
- describe('cascade_wait_visible', () => {
289
- test('should be registered', () => {
290
- expect(registry.has('cascade_wait_visible')).toBe(true);
291
- });
292
-
293
- test('should wait for element visibility', async () => {
294
- // Arrange
295
- mockClient.registerMockTool('wait_visible', () => ({ success: true }));
296
-
297
- // Act
298
- await registry.call('cascade_wait_visible', {
299
- selector: { platform_source: 'WINDOWS', id: 'loading' }
300
- });
301
-
302
- // Assert
303
- expect(mockClient.callTool).toHaveBeenCalledWith('wait_visible', {
304
- selector: { platform_source: 'WINDOWS', id: 'loading' }
305
- });
306
- });
307
- });
308
- });
@@ -1,366 +0,0 @@
1
- /**
2
- * Desktop Automation Tools
3
- *
4
- * 9 tools for controlling Windows desktop applications
5
- */
6
-
7
- import { ToolRegistry } from './tool-registry';
8
- import { CascadeMcpClient } from '../cascade-client';
9
- import { ToolResponse, CascadePluginConfig } from '../types';
10
- import { errorResponse, formatSuccess, imageResponse } from './response-helpers';
11
- import { writeFile, mkdir } from 'fs/promises';
12
- import { join } from 'path';
13
- import { homedir } from 'os';
14
-
15
- // Max size for embedded images (4MB)
16
- const MAX_EMBED_SIZE = 4 * 1024 * 1024;
17
-
18
- export function registerDesktopTools(
19
- registry: ToolRegistry,
20
- getClient: () => Promise<CascadeMcpClient>,
21
- config?: CascadePluginConfig
22
- ): void {
23
- const screenshotMode = config?.screenshotMode || 'auto';
24
- const screenshotDir = config?.screenshotDir || join(homedir(), '.openclaw', 'screenshots');
25
-
26
- // 1. cascade_click_element
27
- registry.register({
28
- name: 'cascade_click_element',
29
- description: 'Click on a UI element on the desktop or in an application',
30
- inputSchema: {
31
- type: 'object',
32
- properties: {
33
- platform_source: {
34
- type: 'string',
35
- enum: ['WINDOWS', 'JAVA', 'WEB'],
36
- description: 'Platform type (Windows desktop, Java app, or web)'
37
- },
38
- id: { type: 'string', description: 'Element ID if known' },
39
- name: { type: 'string', description: 'Element name/label' },
40
- control_type: {
41
- type: 'string',
42
- enum: ['BUTTON', 'INPUT', 'COMBO', 'MENU', 'TREE', 'TABLE', 'CUSTOM'],
43
- description: 'Control type'
44
- },
45
- path: {
46
- type: 'array',
47
- items: { type: 'string' },
48
- description: 'Path components for navigation'
49
- },
50
- index: { type: 'integer', description: 'Index if multiple matches' },
51
- text_hint: { type: 'string', description: 'Text hint for element' }
52
- },
53
- required: ['platform_source']
54
- },
55
- handler: async (args): Promise<ToolResponse> => {
56
- try {
57
- if (!args.platform_source) {
58
- return errorResponse('platform_source is required');
59
- }
60
-
61
- const result = await (await getClient()).callTool('click_element', args);
62
- return formatSuccess(result);
63
- } catch (error) {
64
- return errorResponse(
65
- error instanceof Error ? error.message : 'Failed to click element',
66
- 'Try using cascade_get_semantic_tree first to identify the correct element'
67
- );
68
- }
69
- }
70
- });
71
-
72
- // 2. cascade_type_text
73
- registry.register({
74
- name: 'cascade_type_text',
75
- description: 'Type text into a UI element (input field, text area, etc.)',
76
- inputSchema: {
77
- type: 'object',
78
- properties: {
79
- selector: {
80
- type: 'object',
81
- description: 'Element selector',
82
- properties: {
83
- platform_source: {
84
- type: 'string',
85
- enum: ['WINDOWS', 'JAVA', 'WEB']
86
- },
87
- id: { type: 'string' },
88
- name: { type: 'string' },
89
- control_type: {
90
- type: 'string',
91
- enum: ['BUTTON', 'INPUT', 'COMBO', 'MENU', 'TREE', 'TABLE', 'CUSTOM']
92
- },
93
- path: { type: 'array', items: { type: 'string' } },
94
- index: { type: 'integer' },
95
- text_hint: { type: 'string' }
96
- },
97
- required: ['platform_source']
98
- },
99
- text: {
100
- type: 'string',
101
- description: 'Text to type'
102
- }
103
- },
104
- required: ['selector', 'text']
105
- },
106
- handler: async (args): Promise<ToolResponse> => {
107
- try {
108
- if (!args.selector) {
109
- return errorResponse('selector is required');
110
- }
111
- if (!args.text) {
112
- return errorResponse('text is required');
113
- }
114
-
115
- const result = await (await getClient()).callTool('type_text', args);
116
- return formatSuccess(result);
117
- } catch (error) {
118
- return errorResponse(
119
- error instanceof Error ? error.message : 'Failed to type text'
120
- );
121
- }
122
- }
123
- });
124
-
125
- // 3. cascade_get_semantic_tree
126
- registry.register({
127
- name: 'cascade_get_semantic_tree',
128
- description: 'Get the UI element structure of the current window or application',
129
- inputSchema: {
130
- type: 'object',
131
- properties: { _placeholder: { type: "boolean", description: "Ignore this field" } }
132
- },
133
- handler: async (): Promise<ToolResponse> => {
134
- try {
135
- const result = await (await getClient()).callTool('get_semantic_tree', {});
136
- return formatSuccess(result);
137
- } catch (error) {
138
- return errorResponse(
139
- error instanceof Error ? error.message : 'Failed to get semantic tree'
140
- );
141
- }
142
- }
143
- });
144
-
145
- // 4. cascade_get_screenshot
146
- registry.register({
147
- name: 'cascade_get_screenshot',
148
- description: 'Capture a screenshot of the current screen with element annotations',
149
- inputSchema: {
150
- type: 'object',
151
- properties: { _placeholder: { type: "boolean", description: "Ignore this field" } }
152
- },
153
- handler: async (): Promise<ToolResponse> => {
154
- try {
155
- const result = await (await getClient()).callTool('get_screenshot', {});
156
-
157
- if (!result.image) {
158
- return errorResponse('No image data received');
159
- }
160
-
161
- const imageSize = Buffer.from(result.image, 'base64').length;
162
- const shouldEmbed = screenshotMode === 'embed' ||
163
- (screenshotMode === 'auto' && imageSize < MAX_EMBED_SIZE);
164
-
165
- if (shouldEmbed) {
166
- return imageResponse(
167
- result.image,
168
- result.format?.toLowerCase() === 'jpeg' ? 'jpeg' : 'png',
169
- `Screenshot captured (${(imageSize / 1024).toFixed(1)} KB)`
170
- );
171
- } else {
172
- // Save to disk
173
- await mkdir(screenshotDir, { recursive: true });
174
- const filename = `cascade-${Date.now()}.${result.format?.toLowerCase() || 'png'}`;
175
- const filepath = join(screenshotDir, filename);
176
- await writeFile(filepath, Buffer.from(result.image, 'base64'));
177
-
178
- return formatSuccess({
179
- saved_to: filepath,
180
- size_kb: (imageSize / 1024).toFixed(1),
181
- marks: result.marks
182
- });
183
- }
184
- } catch (error) {
185
- return errorResponse(
186
- error instanceof Error ? error.message : 'Failed to capture screenshot'
187
- );
188
- }
189
- }
190
- });
191
-
192
- // 5. cascade_start_app
193
- registry.register({
194
- name: 'cascade_start_app',
195
- description: 'Start an application by name',
196
- inputSchema: {
197
- type: 'object',
198
- properties: {
199
- app_name: {
200
- type: 'string',
201
- description: 'Application name or executable (e.g., notepad, calc, excel)'
202
- }
203
- },
204
- required: ['app_name']
205
- },
206
- handler: async (args): Promise<ToolResponse> => {
207
- try {
208
- if (!args.app_name) {
209
- return errorResponse('app_name is required');
210
- }
211
-
212
- const result = await (await getClient()).callTool('start_app', args);
213
- return formatSuccess(result);
214
- } catch (error) {
215
- return errorResponse(
216
- error instanceof Error ? error.message : 'Failed to start application',
217
- 'Verify the app name is correct and the application is installed'
218
- );
219
- }
220
- }
221
- });
222
-
223
- // 6. cascade_hover_element
224
- registry.register({
225
- name: 'cascade_hover_element',
226
- description: 'Hover over a UI element',
227
- inputSchema: {
228
- type: 'object',
229
- properties: {
230
- selector: {
231
- type: 'object',
232
- description: 'Element selector',
233
- properties: {
234
- platform_source: { type: 'string', enum: ['WINDOWS', 'JAVA', 'WEB'] },
235
- id: { type: 'string' },
236
- name: { type: 'string' },
237
- control_type: { type: 'string' },
238
- path: { type: 'array', items: { type: 'string' } },
239
- index: { type: 'integer' },
240
- text_hint: { type: 'string' }
241
- },
242
- required: ['platform_source']
243
- }
244
- },
245
- required: ['selector']
246
- },
247
- handler: async (args): Promise<ToolResponse> => {
248
- try {
249
- const result = await (await getClient()).callTool('hover_element', args);
250
- return formatSuccess(result);
251
- } catch (error) {
252
- return errorResponse(
253
- error instanceof Error ? error.message : 'Failed to hover element'
254
- );
255
- }
256
- }
257
- });
258
-
259
- // 7. cascade_focus_element
260
- registry.register({
261
- name: 'cascade_focus_element',
262
- description: 'Focus on a UI element',
263
- inputSchema: {
264
- type: 'object',
265
- properties: {
266
- selector: {
267
- type: 'object',
268
- description: 'Element selector',
269
- properties: {
270
- platform_source: { type: 'string', enum: ['WINDOWS', 'JAVA', 'WEB'] },
271
- id: { type: 'string' },
272
- name: { type: 'string' },
273
- control_type: { type: 'string' },
274
- path: { type: 'array', items: { type: 'string' } },
275
- index: { type: 'integer' },
276
- text_hint: { type: 'string' }
277
- },
278
- required: ['platform_source']
279
- }
280
- },
281
- required: ['selector']
282
- },
283
- handler: async (args): Promise<ToolResponse> => {
284
- try {
285
- const result = await (await getClient()).callTool('focus_element', args);
286
- return formatSuccess(result);
287
- } catch (error) {
288
- return errorResponse(
289
- error instanceof Error ? error.message : 'Failed to focus element'
290
- );
291
- }
292
- }
293
- });
294
-
295
- // 8. cascade_scroll_element
296
- registry.register({
297
- name: 'cascade_scroll_element',
298
- description: 'Scroll a UI element',
299
- inputSchema: {
300
- type: 'object',
301
- properties: {
302
- selector: {
303
- type: 'object',
304
- description: 'Element selector',
305
- properties: {
306
- platform_source: { type: 'string', enum: ['WINDOWS', 'JAVA', 'WEB'] },
307
- id: { type: 'string' },
308
- name: { type: 'string' },
309
- control_type: { type: 'string' },
310
- path: { type: 'array', items: { type: 'string' } },
311
- index: { type: 'integer' },
312
- text_hint: { type: 'string' }
313
- },
314
- required: ['platform_source']
315
- }
316
- },
317
- required: ['selector']
318
- },
319
- handler: async (args): Promise<ToolResponse> => {
320
- try {
321
- const result = await (await getClient()).callTool('scroll_element', args);
322
- return formatSuccess(result);
323
- } catch (error) {
324
- return errorResponse(
325
- error instanceof Error ? error.message : 'Failed to scroll element'
326
- );
327
- }
328
- }
329
- });
330
-
331
- // 9. cascade_wait_visible
332
- registry.register({
333
- name: 'cascade_wait_visible',
334
- description: 'Wait for a UI element to become visible',
335
- inputSchema: {
336
- type: 'object',
337
- properties: {
338
- selector: {
339
- type: 'object',
340
- description: 'Element selector',
341
- properties: {
342
- platform_source: { type: 'string', enum: ['WINDOWS', 'JAVA', 'WEB'] },
343
- id: { type: 'string' },
344
- name: { type: 'string' },
345
- control_type: { type: 'string' },
346
- path: { type: 'array', items: { type: 'string' } },
347
- index: { type: 'integer' },
348
- text_hint: { type: 'string' }
349
- },
350
- required: ['platform_source']
351
- }
352
- },
353
- required: ['selector']
354
- },
355
- handler: async (args): Promise<ToolResponse> => {
356
- try {
357
- const result = await (await getClient()).callTool('wait_visible', args);
358
- return formatSuccess(result);
359
- } catch (error) {
360
- return errorResponse(
361
- error instanceof Error ? error.message : 'Failed to wait for element'
362
- );
363
- }
364
- }
365
- });
366
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * Tools Index
3
- *
4
- * Export all tool registration functions
5
- */
6
-
7
- export { registerDesktopTools } from './desktop-automation';
8
- export { registerWebTools } from './web-automation';
9
- export { registerApiTools } from './api-tools';
10
- export { registerSandboxTools } from './sandbox-tools';
11
- export { registerA2ATools } from './a2a-tools';
12
- // Note: ToolRegistry class is not exported from main index to avoid conflict with ToolRegistry interface
13
- export * from './response-helpers';