@minicor/mcp-server 2.0.0

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 (134) hide show
  1. package/README.md +169 -0
  2. package/dist/__tests__/diff.test.d.ts +2 -0
  3. package/dist/__tests__/diff.test.d.ts.map +1 -0
  4. package/dist/__tests__/diff.test.js +23 -0
  5. package/dist/__tests__/diff.test.js.map +1 -0
  6. package/dist/__tests__/helpers.test.d.ts +2 -0
  7. package/dist/__tests__/helpers.test.d.ts.map +1 -0
  8. package/dist/__tests__/helpers.test.js +70 -0
  9. package/dist/__tests__/helpers.test.js.map +1 -0
  10. package/dist/__tests__/inspect-scripts.test.d.ts +2 -0
  11. package/dist/__tests__/inspect-scripts.test.d.ts.map +1 -0
  12. package/dist/__tests__/inspect-scripts.test.js +66 -0
  13. package/dist/__tests__/inspect-scripts.test.js.map +1 -0
  14. package/dist/browser-client.d.ts +42 -0
  15. package/dist/browser-client.d.ts.map +1 -0
  16. package/dist/browser-client.js +66 -0
  17. package/dist/browser-client.js.map +1 -0
  18. package/dist/cli.d.ts +14 -0
  19. package/dist/cli.d.ts.map +1 -0
  20. package/dist/cli.js +256 -0
  21. package/dist/cli.js.map +1 -0
  22. package/dist/config.d.ts +21 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +57 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/diff.d.ts +7 -0
  27. package/dist/diff.d.ts.map +1 -0
  28. package/dist/diff.js +97 -0
  29. package/dist/diff.js.map +1 -0
  30. package/dist/helpers.d.ts +28 -0
  31. package/dist/helpers.d.ts.map +1 -0
  32. package/dist/helpers.js +91 -0
  33. package/dist/helpers.js.map +1 -0
  34. package/dist/index.d.ts +9 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +193 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/inspect-scripts.d.ts +18 -0
  39. package/dist/inspect-scripts.d.ts.map +1 -0
  40. package/dist/inspect-scripts.js +572 -0
  41. package/dist/inspect-scripts.js.map +1 -0
  42. package/dist/laminar-client.d.ts +160 -0
  43. package/dist/laminar-client.d.ts.map +1 -0
  44. package/dist/laminar-client.js +237 -0
  45. package/dist/laminar-client.js.map +1 -0
  46. package/dist/lds-client.d.ts +107 -0
  47. package/dist/lds-client.d.ts.map +1 -0
  48. package/dist/lds-client.js +81 -0
  49. package/dist/lds-client.js.map +1 -0
  50. package/dist/paths.d.ts +17 -0
  51. package/dist/paths.d.ts.map +1 -0
  52. package/dist/paths.js +46 -0
  53. package/dist/paths.js.map +1 -0
  54. package/dist/prompts/build-browser-rpa.d.ts +3 -0
  55. package/dist/prompts/build-browser-rpa.d.ts.map +1 -0
  56. package/dist/prompts/build-browser-rpa.js +90 -0
  57. package/dist/prompts/build-browser-rpa.js.map +1 -0
  58. package/dist/prompts/build-rpa.d.ts +3 -0
  59. package/dist/prompts/build-rpa.d.ts.map +1 -0
  60. package/dist/prompts/build-rpa.js +168 -0
  61. package/dist/prompts/build-rpa.js.map +1 -0
  62. package/dist/prompts/debug-execution.d.ts +3 -0
  63. package/dist/prompts/debug-execution.d.ts.map +1 -0
  64. package/dist/prompts/debug-execution.js +50 -0
  65. package/dist/prompts/debug-execution.js.map +1 -0
  66. package/dist/prompts/workflow-guide.d.ts +3 -0
  67. package/dist/prompts/workflow-guide.d.ts.map +1 -0
  68. package/dist/prompts/workflow-guide.js +175 -0
  69. package/dist/prompts/workflow-guide.js.map +1 -0
  70. package/dist/services.d.ts +61 -0
  71. package/dist/services.d.ts.map +1 -0
  72. package/dist/services.js +249 -0
  73. package/dist/services.js.map +1 -0
  74. package/dist/setup.d.ts +11 -0
  75. package/dist/setup.d.ts.map +1 -0
  76. package/dist/setup.js +790 -0
  77. package/dist/setup.js.map +1 -0
  78. package/dist/state.d.ts +23 -0
  79. package/dist/state.d.ts.map +1 -0
  80. package/dist/state.js +24 -0
  81. package/dist/state.js.map +1 -0
  82. package/dist/sync.d.ts +86 -0
  83. package/dist/sync.d.ts.map +1 -0
  84. package/dist/sync.js +394 -0
  85. package/dist/sync.js.map +1 -0
  86. package/dist/tools/browser.d.ts +3 -0
  87. package/dist/tools/browser.d.ts.map +1 -0
  88. package/dist/tools/browser.js +254 -0
  89. package/dist/tools/browser.js.map +1 -0
  90. package/dist/tools/config-stores.d.ts +3 -0
  91. package/dist/tools/config-stores.d.ts.map +1 -0
  92. package/dist/tools/config-stores.js +54 -0
  93. package/dist/tools/config-stores.js.map +1 -0
  94. package/dist/tools/core.d.ts +3 -0
  95. package/dist/tools/core.d.ts.map +1 -0
  96. package/dist/tools/core.js +202 -0
  97. package/dist/tools/core.js.map +1 -0
  98. package/dist/tools/cron.d.ts +3 -0
  99. package/dist/tools/cron.d.ts.map +1 -0
  100. package/dist/tools/cron.js +168 -0
  101. package/dist/tools/cron.js.map +1 -0
  102. package/dist/tools/elasticsearch.d.ts +3 -0
  103. package/dist/tools/elasticsearch.d.ts.map +1 -0
  104. package/dist/tools/elasticsearch.js +248 -0
  105. package/dist/tools/elasticsearch.js.map +1 -0
  106. package/dist/tools/issues.d.ts +3 -0
  107. package/dist/tools/issues.d.ts.map +1 -0
  108. package/dist/tools/issues.js +39 -0
  109. package/dist/tools/issues.js.map +1 -0
  110. package/dist/tools/stats.d.ts +3 -0
  111. package/dist/tools/stats.d.ts.map +1 -0
  112. package/dist/tools/stats.js +18 -0
  113. package/dist/tools/stats.js.map +1 -0
  114. package/dist/tools/sync-tools.d.ts +3 -0
  115. package/dist/tools/sync-tools.d.ts.map +1 -0
  116. package/dist/tools/sync-tools.js +121 -0
  117. package/dist/tools/sync-tools.js.map +1 -0
  118. package/dist/tools/vm-rpa.d.ts +3 -0
  119. package/dist/tools/vm-rpa.d.ts.map +1 -0
  120. package/dist/tools/vm-rpa.js +281 -0
  121. package/dist/tools/vm-rpa.js.map +1 -0
  122. package/dist/tools/vm.d.ts +3 -0
  123. package/dist/tools/vm.d.ts.map +1 -0
  124. package/dist/tools/vm.js +280 -0
  125. package/dist/tools/vm.js.map +1 -0
  126. package/dist/tools/workflow-ops.d.ts +3 -0
  127. package/dist/tools/workflow-ops.d.ts.map +1 -0
  128. package/dist/tools/workflow-ops.js +313 -0
  129. package/dist/tools/workflow-ops.js.map +1 -0
  130. package/dist/types.d.ts +14 -0
  131. package/dist/types.d.ts.map +1 -0
  132. package/dist/types.js +5 -0
  133. package/dist/types.js.map +1 -0
  134. package/package.json +58 -0
@@ -0,0 +1,572 @@
1
+ /**
2
+ * Python script generators for VM UI inspection.
3
+ *
4
+ * Each function returns a Python script string that, when executed on the VM
5
+ * via LDS /execute, prints structured JSON to stdout for the agent to parse.
6
+ */
7
+ export function generateInspectScript(params) {
8
+ const fw = params.framework ?? "auto";
9
+ if (fw === "jab") {
10
+ return generateJabScript(params);
11
+ }
12
+ if (fw === "pywinauto") {
13
+ return generatePywinautoScript(params);
14
+ }
15
+ // "auto" and "uiautomation" both use uiautomation
16
+ return generateUiautomationScript(params);
17
+ }
18
+ // ─── uiautomation scripts ────────────────────────────────────
19
+ function generateUiautomationScript(params) {
20
+ switch (params.mode) {
21
+ case "window_list":
22
+ return `
23
+ import json, uiautomation as auto
24
+
25
+ results = []
26
+ root = auto.GetRootControl()
27
+ for win in root.GetChildren():
28
+ try:
29
+ rect = win.BoundingRectangle
30
+ results.append({
31
+ "name": win.Name or "",
32
+ "controlType": win.ControlTypeName,
33
+ "className": win.ClassName,
34
+ "automationId": win.AutomationId,
35
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
36
+ "size": f"{rect.width()}x{rect.height()}"
37
+ })
38
+ except Exception:
39
+ pass
40
+ print(json.dumps({"windows": results, "count": len(results)}, indent=2))
41
+ `.trim();
42
+ case "screen_info":
43
+ return `
44
+ import json, ctypes
45
+
46
+ user32 = ctypes.windll.user32
47
+ w = user32.GetSystemMetrics(0)
48
+ h = user32.GetSystemMetrics(1)
49
+
50
+ try:
51
+ import uiautomation as auto
52
+ fg = auto.GetForegroundControl()
53
+ fg_rect = fg.BoundingRectangle
54
+ active = {
55
+ "name": fg.Name or "",
56
+ "controlType": fg.ControlTypeName,
57
+ "rect": {"left": fg_rect.left, "top": fg_rect.top, "right": fg_rect.right, "bottom": fg_rect.bottom}
58
+ }
59
+ except Exception:
60
+ active = None
61
+
62
+ dpi = ctypes.windll.shcore.GetScaleFactorForDevice(0) if hasattr(ctypes.windll, 'shcore') else 100
63
+ print(json.dumps({
64
+ "screenWidth": w,
65
+ "screenHeight": h,
66
+ "dpiScale": dpi,
67
+ "activeWindow": active
68
+ }, indent=2))
69
+ `.trim();
70
+ case "element_at_point":
71
+ return `
72
+ import json, uiautomation as auto
73
+
74
+ x, y = ${params.x ?? 0}, ${params.y ?? 0}
75
+ try:
76
+ ctrl = auto.ControlFromPoint(x, y)
77
+ rect = ctrl.BoundingRectangle
78
+ result = {
79
+ "name": ctrl.Name or "",
80
+ "controlType": ctrl.ControlTypeName,
81
+ "automationId": ctrl.AutomationId,
82
+ "className": ctrl.ClassName,
83
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
84
+ "size": f"{rect.width()}x{rect.height()}",
85
+ "center": {"x": rect.xcenter(), "y": rect.ycenter()},
86
+ "isEnabled": ctrl.IsEnabled,
87
+ "point": {"x": x, "y": y}
88
+ }
89
+
90
+ try:
91
+ parent = ctrl.GetParentControl()
92
+ if parent:
93
+ result["parent"] = {"name": parent.Name or "", "controlType": parent.ControlTypeName}
94
+ except Exception:
95
+ pass
96
+
97
+ print(json.dumps(result, indent=2))
98
+ except Exception as e:
99
+ print(json.dumps({"error": f"No element found at ({x}, {y}): {e}", "point": {"x": x, "y": y}}, indent=2))
100
+ `.trim();
101
+ case "element_tree": {
102
+ const maxDepth = params.depth ?? 3;
103
+ const titleFilter = params.windowTitle
104
+ ? JSON.stringify(params.windowTitle)
105
+ : "None";
106
+ return `
107
+ import json, uiautomation as auto
108
+
109
+ MAX_DEPTH = ${maxDepth}
110
+ TITLE_FILTER = ${titleFilter}
111
+
112
+ def build_tree(ctrl, depth=0):
113
+ if depth > MAX_DEPTH:
114
+ return None
115
+ try:
116
+ rect = ctrl.BoundingRectangle
117
+ node = {
118
+ "name": ctrl.Name or "",
119
+ "controlType": ctrl.ControlTypeName,
120
+ "automationId": ctrl.AutomationId,
121
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
122
+ }
123
+ children = []
124
+ for child in ctrl.GetChildren():
125
+ c = build_tree(child, depth + 1)
126
+ if c:
127
+ children.append(c)
128
+ if children:
129
+ node["children"] = children
130
+ return node
131
+ except Exception:
132
+ return None
133
+
134
+ if TITLE_FILTER:
135
+ win = auto.WindowControl(searchDepth=1, Name=TITLE_FILTER)
136
+ if not win.Exists(1, 0):
137
+ print(json.dumps({"error": f"Window '{TITLE_FILTER}' not found"}))
138
+ else:
139
+ tree = build_tree(win)
140
+ print(json.dumps({"root": tree}, indent=2))
141
+ else:
142
+ fg = auto.GetForegroundControl()
143
+ tree = build_tree(fg)
144
+ print(json.dumps({"root": tree, "windowName": fg.Name}, indent=2))
145
+ `.trim();
146
+ }
147
+ case "focused_element":
148
+ return `
149
+ import json, uiautomation as auto
150
+
151
+ ctrl = auto.GetFocusedControl()
152
+ rect = ctrl.BoundingRectangle
153
+ result = {
154
+ "name": ctrl.Name or "",
155
+ "controlType": ctrl.ControlTypeName,
156
+ "automationId": ctrl.AutomationId,
157
+ "className": ctrl.ClassName,
158
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
159
+ "size": f"{rect.width()}x{rect.height()}",
160
+ "center": {"x": rect.xcenter(), "y": rect.ycenter()},
161
+ "isEnabled": ctrl.IsEnabled
162
+ }
163
+
164
+ try:
165
+ parent = ctrl.GetParentControl()
166
+ if parent:
167
+ result["parent"] = {"name": parent.Name or "", "controlType": parent.ControlTypeName}
168
+ except Exception:
169
+ pass
170
+
171
+ print(json.dumps(result, indent=2))
172
+ `.trim();
173
+ default:
174
+ return `print("Unknown mode")`;
175
+ }
176
+ }
177
+ // ─── pywinauto scripts ───────────────────────────────────────
178
+ function generatePywinautoScript(params) {
179
+ switch (params.mode) {
180
+ case "window_list":
181
+ return `
182
+ import json
183
+ from pywinauto import Desktop
184
+
185
+ desktop = Desktop(backend="uia")
186
+ results = []
187
+ for win in desktop.windows():
188
+ try:
189
+ rect = win.rectangle()
190
+ results.append({
191
+ "name": win.window_text() or "",
192
+ "controlType": win.friendly_class_name(),
193
+ "className": win.class_name(),
194
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
195
+ "size": f"{rect.width()}x{rect.height()}",
196
+ "visible": win.is_visible(),
197
+ "enabled": win.is_enabled()
198
+ })
199
+ except Exception:
200
+ pass
201
+ print(json.dumps({"windows": results, "count": len(results)}, indent=2))
202
+ `.trim();
203
+ case "screen_info":
204
+ return `
205
+ import json, ctypes
206
+
207
+ user32 = ctypes.windll.user32
208
+ w = user32.GetSystemMetrics(0)
209
+ h = user32.GetSystemMetrics(1)
210
+
211
+ from pywinauto import Desktop
212
+ desktop = Desktop(backend="uia")
213
+ active = None
214
+ try:
215
+ fg = desktop.top_window()
216
+ rect = fg.rectangle()
217
+ active = {
218
+ "name": fg.window_text(),
219
+ "className": fg.class_name(),
220
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom}
221
+ }
222
+ except Exception:
223
+ pass
224
+
225
+ print(json.dumps({"screenWidth": w, "screenHeight": h, "activeWindow": active}, indent=2))
226
+ `.trim();
227
+ case "element_at_point":
228
+ return `
229
+ import json
230
+ from pywinauto import Desktop
231
+
232
+ x, y = ${params.x ?? 0}, ${params.y ?? 0}
233
+ desktop = Desktop(backend="uia")
234
+ elem = desktop.from_point(x, y)
235
+ rect = elem.rectangle()
236
+ result = {
237
+ "name": elem.window_text() or "",
238
+ "controlType": elem.friendly_class_name(),
239
+ "className": elem.class_name(),
240
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
241
+ "size": f"{rect.width()}x{rect.height()}",
242
+ "enabled": elem.is_enabled(),
243
+ "point": {"x": x, "y": y}
244
+ }
245
+ print(json.dumps(result, indent=2))
246
+ `.trim();
247
+ case "element_tree": {
248
+ const maxDepth = params.depth ?? 3;
249
+ const titleFilter = params.windowTitle
250
+ ? JSON.stringify(params.windowTitle)
251
+ : "None";
252
+ return `
253
+ import json
254
+ from pywinauto import Desktop
255
+
256
+ MAX_DEPTH = ${maxDepth}
257
+ TITLE_FILTER = ${titleFilter}
258
+
259
+ def build_tree(ctrl, depth=0):
260
+ if depth > MAX_DEPTH:
261
+ return None
262
+ try:
263
+ rect = ctrl.rectangle()
264
+ node = {
265
+ "name": ctrl.window_text() or "",
266
+ "controlType": ctrl.friendly_class_name(),
267
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
268
+ }
269
+ children = []
270
+ for child in ctrl.children():
271
+ c = build_tree(child, depth + 1)
272
+ if c:
273
+ children.append(c)
274
+ if children:
275
+ node["children"] = children
276
+ return node
277
+ except Exception:
278
+ return None
279
+
280
+ desktop = Desktop(backend="uia")
281
+ if TITLE_FILTER:
282
+ try:
283
+ win = desktop.window(title=TITLE_FILTER)
284
+ tree = build_tree(win)
285
+ print(json.dumps({"root": tree}, indent=2))
286
+ except Exception as e:
287
+ print(json.dumps({"error": f"Window '{TITLE_FILTER}' not found: {e}"}))
288
+ else:
289
+ win = desktop.top_window()
290
+ tree = build_tree(win)
291
+ print(json.dumps({"root": tree, "windowName": win.window_text()}, indent=2))
292
+ `.trim();
293
+ }
294
+ case "focused_element":
295
+ return `
296
+ import json
297
+ from pywinauto import Desktop
298
+
299
+ desktop = Desktop(backend="uia")
300
+ try:
301
+ win = desktop.top_window()
302
+ focused = win.get_focus()
303
+ rect = focused.rectangle()
304
+ result = {
305
+ "name": focused.window_text() or "",
306
+ "controlType": focused.friendly_class_name(),
307
+ "className": focused.class_name(),
308
+ "rect": {"left": rect.left, "top": rect.top, "right": rect.right, "bottom": rect.bottom},
309
+ "size": f"{rect.width()}x{rect.height()}",
310
+ "enabled": focused.is_enabled()
311
+ }
312
+ print(json.dumps(result, indent=2))
313
+ except Exception as e:
314
+ print(json.dumps({"error": f"Could not get focused element: {e}"}))
315
+ `.trim();
316
+ default:
317
+ return `print("Unknown mode")`;
318
+ }
319
+ }
320
+ // ─── Java Access Bridge scripts ──────────────────────────────
321
+ function generateJabScript(params) {
322
+ switch (params.mode) {
323
+ case "window_list":
324
+ return `
325
+ import json, queue, threading, ctypes, time
326
+ from ctypes import byref, wintypes
327
+ from JABWrapper.jab_wrapper import JavaAccessBridgeWrapper
328
+
329
+ GetMessage = ctypes.windll.user32.GetMessageW
330
+ TranslateMessage = ctypes.windll.user32.TranslateMessage
331
+ DispatchMessage = ctypes.windll.user32.DispatchMessageW
332
+
333
+ def pump_bg(pipe):
334
+ try:
335
+ jab = JavaAccessBridgeWrapper(ignore_callbacks=True)
336
+ pipe.put(jab)
337
+ msg = byref(wintypes.MSG())
338
+ while GetMessage(msg, 0, 0, 0) > 0:
339
+ TranslateMessage(msg)
340
+ DispatchMessage(msg)
341
+ except Exception as e:
342
+ pipe.put(None)
343
+
344
+ pipe = queue.Queue()
345
+ t = threading.Thread(target=pump_bg, daemon=True, args=[pipe])
346
+ t.start()
347
+ jab = pipe.get()
348
+ if not jab:
349
+ print(json.dumps({"error": "Failed to initialize Java Access Bridge"}))
350
+ else:
351
+ time.sleep(0.1)
352
+ windows = jab.get_windows()
353
+ results = []
354
+ for w in windows:
355
+ results.append({"title": w.title, "hwnd": w.hwnd})
356
+ jab.shutdown()
357
+ print(json.dumps({"javaWindows": results, "count": len(results)}, indent=2))
358
+ `.trim();
359
+ case "screen_info":
360
+ // JAB doesn't have screen info; fall back to basic ctypes
361
+ return `
362
+ import json, ctypes
363
+
364
+ user32 = ctypes.windll.user32
365
+ w = user32.GetSystemMetrics(0)
366
+ h = user32.GetSystemMetrics(1)
367
+ print(json.dumps({"screenWidth": w, "screenHeight": h, "note": "JAB does not provide screen DPI info"}, indent=2))
368
+ `.trim();
369
+ case "element_at_point": {
370
+ const x = params.x ?? 0;
371
+ const y = params.y ?? 0;
372
+ return `
373
+ import json, queue, threading, ctypes, time
374
+ from ctypes import byref, wintypes
375
+ from JABWrapper.jab_wrapper import JavaAccessBridgeWrapper
376
+
377
+ GetMessage = ctypes.windll.user32.GetMessageW
378
+ TranslateMessage = ctypes.windll.user32.TranslateMessage
379
+ DispatchMessage = ctypes.windll.user32.DispatchMessageW
380
+
381
+ def pump_bg(pipe):
382
+ try:
383
+ jab = JavaAccessBridgeWrapper(ignore_callbacks=True)
384
+ pipe.put(jab)
385
+ msg = byref(wintypes.MSG())
386
+ while GetMessage(msg, 0, 0, 0) > 0:
387
+ TranslateMessage(msg)
388
+ DispatchMessage(msg)
389
+ except Exception as e:
390
+ pipe.put(None)
391
+
392
+ pipe = queue.Queue()
393
+ t = threading.Thread(target=pump_bg, daemon=True, args=[pipe])
394
+ t.start()
395
+ jab = pipe.get()
396
+ if not jab:
397
+ print(json.dumps({"error": "Failed to initialize Java Access Bridge"}))
398
+ else:
399
+ time.sleep(0.1)
400
+ x, y = ${x}, ${y}
401
+ windows = jab.get_windows()
402
+ found = False
403
+ for w in windows:
404
+ try:
405
+ vm_id, root_ctx = jab.get_accessible_context_from_hwnd(w.hwnd)
406
+ jab.set_context(vm_id, root_ctx)
407
+ elem_ctx = jab.get_accessible_context_at(root_ctx, x, y)
408
+ if elem_ctx and elem_ctx.value:
409
+ info = jab.get_context_info(elem_ctx)
410
+ result = {
411
+ "name": info.name, "role": info.role, "description": info.description,
412
+ "states": info.states, "x": info.x, "y": info.y,
413
+ "width": info.width, "height": info.height,
414
+ "indexInParent": info.indexInParent, "childrenCount": info.childrenCount,
415
+ "window": w.title, "point": {"x": x, "y": y}
416
+ }
417
+ print(json.dumps(result, indent=2))
418
+ found = True
419
+ break
420
+ except Exception:
421
+ continue
422
+ if not found:
423
+ print(json.dumps({"error": "No Java element found at cursor position", "point": {"x": x, "y": y}}))
424
+ jab.shutdown()
425
+ `.trim();
426
+ }
427
+ case "element_tree": {
428
+ const maxDepth = params.depth ?? 3;
429
+ const titleFilter = params.windowTitle
430
+ ? JSON.stringify(params.windowTitle)
431
+ : "None";
432
+ return `
433
+ import json, queue, threading, ctypes, time
434
+ from ctypes import byref, wintypes
435
+ from JABWrapper.jab_wrapper import JavaAccessBridgeWrapper
436
+
437
+ GetMessage = ctypes.windll.user32.GetMessageW
438
+ TranslateMessage = ctypes.windll.user32.TranslateMessage
439
+ DispatchMessage = ctypes.windll.user32.DispatchMessageW
440
+
441
+ MAX_DEPTH = ${maxDepth}
442
+ TITLE_FILTER = ${titleFilter}
443
+
444
+ def pump_bg(pipe):
445
+ try:
446
+ jab = JavaAccessBridgeWrapper(ignore_callbacks=True)
447
+ pipe.put(jab)
448
+ msg = byref(wintypes.MSG())
449
+ while GetMessage(msg, 0, 0, 0) > 0:
450
+ TranslateMessage(msg)
451
+ DispatchMessage(msg)
452
+ except Exception as e:
453
+ pipe.put(None)
454
+
455
+ def build_tree(jab, ctx, depth=0):
456
+ if depth > MAX_DEPTH:
457
+ return None
458
+ try:
459
+ info = jab.get_context_info(ctx)
460
+ node = {"name": info.name, "role": info.role, "x": info.x, "y": info.y, "width": info.width, "height": info.height}
461
+ children = []
462
+ for i in range(info.childrenCount):
463
+ try:
464
+ child_ctx = jab.get_accessible_child_from_context(ctx, i)
465
+ c = build_tree(jab, child_ctx, depth + 1)
466
+ if c:
467
+ children.append(c)
468
+ except Exception:
469
+ pass
470
+ if children:
471
+ node["children"] = children
472
+ return node
473
+ except Exception:
474
+ return None
475
+
476
+ pipe = queue.Queue()
477
+ t = threading.Thread(target=pump_bg, daemon=True, args=[pipe])
478
+ t.start()
479
+ jab = pipe.get()
480
+ if not jab:
481
+ print(json.dumps({"error": "Failed to initialize Java Access Bridge"}))
482
+ else:
483
+ time.sleep(0.1)
484
+ windows = jab.get_windows()
485
+ target = None
486
+ for w in windows:
487
+ if TITLE_FILTER is None or TITLE_FILTER.lower() in w.title.lower():
488
+ target = w
489
+ break
490
+ if not target:
491
+ print(json.dumps({"error": f"No matching Java window found (filter={TITLE_FILTER})"}))
492
+ else:
493
+ vm_id, root_ctx = jab.get_accessible_context_from_hwnd(target.hwnd)
494
+ jab.set_context(vm_id, root_ctx)
495
+ tree = build_tree(jab, root_ctx)
496
+ print(json.dumps({"root": tree, "window": target.title}, indent=2))
497
+ jab.shutdown()
498
+ `.trim();
499
+ }
500
+ case "focused_element":
501
+ return `
502
+ import json, queue, threading, ctypes, time
503
+ from ctypes import byref, wintypes
504
+ from JABWrapper.jab_wrapper import JavaAccessBridgeWrapper
505
+
506
+ GetMessage = ctypes.windll.user32.GetMessageW
507
+ TranslateMessage = ctypes.windll.user32.TranslateMessage
508
+ DispatchMessage = ctypes.windll.user32.DispatchMessageW
509
+
510
+ def pump_bg(pipe):
511
+ try:
512
+ jab = JavaAccessBridgeWrapper(ignore_callbacks=True)
513
+ pipe.put(jab)
514
+ msg = byref(wintypes.MSG())
515
+ while GetMessage(msg, 0, 0, 0) > 0:
516
+ TranslateMessage(msg)
517
+ DispatchMessage(msg)
518
+ except Exception as e:
519
+ pipe.put(None)
520
+
521
+ def find_focused(jab, ctx, window_title, max_depth=20):
522
+ try:
523
+ info = jab.get_context_info(ctx)
524
+ if 'focused' in (info.states or '').lower():
525
+ return {
526
+ "name": info.name, "role": info.role,
527
+ "x": info.x, "y": info.y, "width": info.width, "height": info.height,
528
+ "states": info.states, "window": window_title
529
+ }
530
+ if max_depth > 0:
531
+ for i in range(info.childrenCount):
532
+ try:
533
+ child_ctx = jab.get_accessible_child_from_context(ctx, i)
534
+ result = find_focused(jab, child_ctx, window_title, max_depth - 1)
535
+ if result:
536
+ return result
537
+ except Exception:
538
+ pass
539
+ except Exception:
540
+ pass
541
+ return None
542
+
543
+ pipe = queue.Queue()
544
+ t = threading.Thread(target=pump_bg, daemon=True, args=[pipe])
545
+ t.start()
546
+ jab = pipe.get()
547
+ if not jab:
548
+ print(json.dumps({"error": "Failed to initialize Java Access Bridge"}))
549
+ else:
550
+ time.sleep(0.1)
551
+ windows = jab.get_windows()
552
+ found = None
553
+ for w in windows:
554
+ try:
555
+ vm_id, root_ctx = jab.get_accessible_context_from_hwnd(w.hwnd)
556
+ jab.set_context(vm_id, root_ctx)
557
+ found = find_focused(jab, root_ctx, w.title)
558
+ if found:
559
+ break
560
+ except Exception:
561
+ continue
562
+ if found:
563
+ print(json.dumps(found, indent=2))
564
+ else:
565
+ print(json.dumps({"info": "No focused Java element found. Listing windows instead."}))
566
+ jab.shutdown()
567
+ `.trim();
568
+ default:
569
+ return `print("Unknown mode")`;
570
+ }
571
+ }
572
+ //# sourceMappingURL=inspect-scripts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspect-scripts.js","sourceRoot":"","sources":["../src/inspect-scripts.ts"],"names":[],"mappings":"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"}