@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.
- package/README.md +169 -0
- package/dist/__tests__/diff.test.d.ts +2 -0
- package/dist/__tests__/diff.test.d.ts.map +1 -0
- package/dist/__tests__/diff.test.js +23 -0
- package/dist/__tests__/diff.test.js.map +1 -0
- package/dist/__tests__/helpers.test.d.ts +2 -0
- package/dist/__tests__/helpers.test.d.ts.map +1 -0
- package/dist/__tests__/helpers.test.js +70 -0
- package/dist/__tests__/helpers.test.js.map +1 -0
- package/dist/__tests__/inspect-scripts.test.d.ts +2 -0
- package/dist/__tests__/inspect-scripts.test.d.ts.map +1 -0
- package/dist/__tests__/inspect-scripts.test.js +66 -0
- package/dist/__tests__/inspect-scripts.test.js.map +1 -0
- package/dist/browser-client.d.ts +42 -0
- package/dist/browser-client.d.ts.map +1 -0
- package/dist/browser-client.js +66 -0
- package/dist/browser-client.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +256 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +57 -0
- package/dist/config.js.map +1 -0
- package/dist/diff.d.ts +7 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +97 -0
- package/dist/diff.js.map +1 -0
- package/dist/helpers.d.ts +28 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +91 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect-scripts.d.ts +18 -0
- package/dist/inspect-scripts.d.ts.map +1 -0
- package/dist/inspect-scripts.js +572 -0
- package/dist/inspect-scripts.js.map +1 -0
- package/dist/laminar-client.d.ts +160 -0
- package/dist/laminar-client.d.ts.map +1 -0
- package/dist/laminar-client.js +237 -0
- package/dist/laminar-client.js.map +1 -0
- package/dist/lds-client.d.ts +107 -0
- package/dist/lds-client.d.ts.map +1 -0
- package/dist/lds-client.js +81 -0
- package/dist/lds-client.js.map +1 -0
- package/dist/paths.d.ts +17 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +46 -0
- package/dist/paths.js.map +1 -0
- package/dist/prompts/build-browser-rpa.d.ts +3 -0
- package/dist/prompts/build-browser-rpa.d.ts.map +1 -0
- package/dist/prompts/build-browser-rpa.js +90 -0
- package/dist/prompts/build-browser-rpa.js.map +1 -0
- package/dist/prompts/build-rpa.d.ts +3 -0
- package/dist/prompts/build-rpa.d.ts.map +1 -0
- package/dist/prompts/build-rpa.js +168 -0
- package/dist/prompts/build-rpa.js.map +1 -0
- package/dist/prompts/debug-execution.d.ts +3 -0
- package/dist/prompts/debug-execution.d.ts.map +1 -0
- package/dist/prompts/debug-execution.js +50 -0
- package/dist/prompts/debug-execution.js.map +1 -0
- package/dist/prompts/workflow-guide.d.ts +3 -0
- package/dist/prompts/workflow-guide.d.ts.map +1 -0
- package/dist/prompts/workflow-guide.js +175 -0
- package/dist/prompts/workflow-guide.js.map +1 -0
- package/dist/services.d.ts +61 -0
- package/dist/services.d.ts.map +1 -0
- package/dist/services.js +249 -0
- package/dist/services.js.map +1 -0
- package/dist/setup.d.ts +11 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +790 -0
- package/dist/setup.js.map +1 -0
- package/dist/state.d.ts +23 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +24 -0
- package/dist/state.js.map +1 -0
- package/dist/sync.d.ts +86 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +394 -0
- package/dist/sync.js.map +1 -0
- package/dist/tools/browser.d.ts +3 -0
- package/dist/tools/browser.d.ts.map +1 -0
- package/dist/tools/browser.js +254 -0
- package/dist/tools/browser.js.map +1 -0
- package/dist/tools/config-stores.d.ts +3 -0
- package/dist/tools/config-stores.d.ts.map +1 -0
- package/dist/tools/config-stores.js +54 -0
- package/dist/tools/config-stores.js.map +1 -0
- package/dist/tools/core.d.ts +3 -0
- package/dist/tools/core.d.ts.map +1 -0
- package/dist/tools/core.js +202 -0
- package/dist/tools/core.js.map +1 -0
- package/dist/tools/cron.d.ts +3 -0
- package/dist/tools/cron.d.ts.map +1 -0
- package/dist/tools/cron.js +168 -0
- package/dist/tools/cron.js.map +1 -0
- package/dist/tools/elasticsearch.d.ts +3 -0
- package/dist/tools/elasticsearch.d.ts.map +1 -0
- package/dist/tools/elasticsearch.js +248 -0
- package/dist/tools/elasticsearch.js.map +1 -0
- package/dist/tools/issues.d.ts +3 -0
- package/dist/tools/issues.d.ts.map +1 -0
- package/dist/tools/issues.js +39 -0
- package/dist/tools/issues.js.map +1 -0
- package/dist/tools/stats.d.ts +3 -0
- package/dist/tools/stats.d.ts.map +1 -0
- package/dist/tools/stats.js +18 -0
- package/dist/tools/stats.js.map +1 -0
- package/dist/tools/sync-tools.d.ts +3 -0
- package/dist/tools/sync-tools.d.ts.map +1 -0
- package/dist/tools/sync-tools.js +121 -0
- package/dist/tools/sync-tools.js.map +1 -0
- package/dist/tools/vm-rpa.d.ts +3 -0
- package/dist/tools/vm-rpa.d.ts.map +1 -0
- package/dist/tools/vm-rpa.js +281 -0
- package/dist/tools/vm-rpa.js.map +1 -0
- package/dist/tools/vm.d.ts +3 -0
- package/dist/tools/vm.d.ts.map +1 -0
- package/dist/tools/vm.js +280 -0
- package/dist/tools/vm.js.map +1 -0
- package/dist/tools/workflow-ops.d.ts +3 -0
- package/dist/tools/workflow-ops.d.ts.map +1 -0
- package/dist/tools/workflow-ops.js +313 -0
- package/dist/tools/workflow-ops.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- 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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"}
|