extra-desktop 0.1.1__py3-none-any.whl

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.
extra/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """
2
+ Project Extra — Flashless Windows 10/11 Computer-Use Engine & MCP Server.
3
+ """
4
+
5
+ __version__ = "0.1.1"
extra/cli.py ADDED
@@ -0,0 +1,242 @@
1
+ """
2
+ Project Extra — Command-Line Interface (CLI) & System Diagnostic Runner
3
+ Provides `extra doctor`, `extra test`, `extra run`, `extra inspect`, and `extra snap`.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import argparse
9
+ import os
10
+ import platform
11
+ import sys
12
+ import time
13
+ from pathlib import Path
14
+
15
+ # Add project root to sys.path
16
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
17
+
18
+ try:
19
+ from extra import __version__
20
+ except Exception:
21
+ __version__ = "0.1.1"
22
+
23
+ from extra.core.capture import capture_screen
24
+ from extra.core.focus import (
25
+ find_window_by_title,
26
+ get_foreground_window,
27
+ list_windows,
28
+ )
29
+ from extra.core.geometry import (
30
+ attach_input_desktop,
31
+ ensure_dpi_aware,
32
+ get_cursor_position,
33
+ get_monitors_info,
34
+ )
35
+ from extra.core.uia_plane import SetOfMarkAnnotator, UIAutomationPlane
36
+ from extra.fastpath.shell import resolve_executable
37
+
38
+
39
+ def cmd_doctor() -> int:
40
+ """Runs a complete system health and capability diagnostic."""
41
+ ensure_dpi_aware()
42
+ attach_input_desktop()
43
+
44
+ print("=" * 65)
45
+ print(" EXTRA SYSTEM HEALTH & HARDWARE DIAGNOSTIC (DOCTOR)")
46
+ print("=" * 65)
47
+
48
+ # 1. OS & Architecture
49
+ print("\n[Operating System & Architecture]")
50
+ os_name = platform.system()
51
+ os_release = platform.release()
52
+ os_version = platform.version()
53
+ machine = platform.machine()
54
+ py_ver = sys.version.split()[0]
55
+ print(f" Extra Version: {__version__}")
56
+ print(f" OS: {os_name} {os_release} (Build {os_version})")
57
+ print(f" Architecture: {machine}")
58
+ print(f" Python: {py_ver} ({'64-bit' if sys.maxsize > 2**32 else '32-bit'})")
59
+
60
+ if os_name != "Windows":
61
+ print(" [FAIL] Extra requires Windows 10 or Windows 11.")
62
+ return 1
63
+ else:
64
+ print(" [OK] Supported Windows host.")
65
+
66
+ # 2. DPI & Security Desktop Attachment
67
+ print("\n[DPI Geometry & Thread Desktop]")
68
+ dpi_ok = ensure_dpi_aware()
69
+ desk_ok = attach_input_desktop()
70
+ print(f" DPI Awareness: {'PerMonitorV2 (Active)' if dpi_ok else 'Fallback'}")
71
+ print(f" Input Desktop: {'Attached (Default)' if desk_ok else 'Standard'}")
72
+
73
+ cursor = get_cursor_position()
74
+ print(f" Mouse Cursor: Physical pixel {cursor}")
75
+
76
+ # 3. Displays & Hardware Metrics
77
+ print("\n[Displays & Multi-Monitor Metrics]")
78
+ monitors = get_monitors_info()
79
+ print(f" Monitors: {len(monitors)} connected display(s)")
80
+ for m in monitors:
81
+ print(f" - Display {m.index}: {m.width}x{m.height} @ ({m.left}, {m.top}) | DPI: {m.dpi_x}x{m.dpi_y} ({m.scale_factor}x scale) | Primary={m.is_primary}")
82
+
83
+ # 4. Perception Engine Latency Benchmark
84
+ print("\n[Screen Capture Benchmark]")
85
+ latencies = []
86
+ for _ in range(3):
87
+ cap = capture_screen(0)
88
+ latencies.append(cap.duration_ms)
89
+ avg_latency = sum(latencies) / len(latencies)
90
+ print(f" Capture Runs: {latencies[0]:.1f}ms, {latencies[1]:.1f}ms, {latencies[2]:.1f}ms (Average: {avg_latency:.1f}ms)")
91
+ if avg_latency < 100:
92
+ print(f" [OK] High-speed screen capture verified ({avg_latency:.1f}ms).")
93
+ else:
94
+ print(" [WARN] Screen capture took longer than expected.")
95
+
96
+ # 5. Semantic UI Automation v3 Plane
97
+ print("\n[Microsoft UI Automation Core COM Layer]")
98
+ try:
99
+ uia = UIAutomationPlane()
100
+ t0 = time.perf_counter()
101
+ elems = uia.inspect_window(interactive_only=True, max_elements=20)
102
+ t_uia = (time.perf_counter() - t0) * 1000.0
103
+ print(f" UIA Status: Active & Operational ({len(elems)} elements inspected in {t_uia:.1f}ms)")
104
+ print(" [OK] UIAutomationCore.dll COM interface functional.")
105
+ except Exception as e:
106
+ print(f" [FAIL] UIA Plane Error: {e}")
107
+
108
+ # 6. Microsoft Edge & Playwright Fast-Path
109
+ print("\n[Browser Fast-Path (Microsoft Edge / Playwright)]")
110
+ edge_path = resolve_executable("edge")
111
+ if edge_path and os.path.exists(edge_path):
112
+ print(f" Edge Binary: {edge_path}")
113
+ print(" [OK] Microsoft Edge available for zero-download web fast-path.")
114
+ else:
115
+ print(" [WARN] Microsoft Edge not found at standard path.")
116
+
117
+ # 7. Active Windows
118
+ print("\n[Active Desktop Windows]")
119
+ fg = get_foreground_window()
120
+ print(f" Foreground: {repr(fg.title) if fg else 'None'} ({fg.process_name if fg else ''})")
121
+ wins = list_windows(visible_only=True)
122
+ print(f" Total Windows: {len(wins)} visible top-level windows")
123
+
124
+ print("\n" + "=" * 65)
125
+ print(" DOCTOR DIAGNOSTIC COMPLETE: SYSTEM IS READY FOR EXTRA")
126
+ print("=" * 65)
127
+ return 0
128
+
129
+
130
+ def cmd_test() -> int:
131
+ """Runs the full integration test suite."""
132
+ from extra.test_core_engine import run_tests
133
+ try:
134
+ run_tests()
135
+ return 0
136
+ except Exception as e:
137
+ print(f"\n[FAIL] Test suite failed: {e}")
138
+ return 1
139
+
140
+
141
+ def cmd_run(args: argparse.Namespace) -> int:
142
+ """Starts the Model Context Protocol (MCP) server."""
143
+ from extra.mcp.server import main
144
+ main()
145
+ return 0
146
+
147
+
148
+ def cmd_inspect(args: argparse.Namespace) -> int:
149
+ """Quickly inspects UI Automation controls on the desktop."""
150
+ ensure_dpi_aware()
151
+ attach_input_desktop()
152
+
153
+ uia = UIAutomationPlane()
154
+ print(f"Inspecting UI elements (window='{args.window}', max={args.limit})...")
155
+ hwnd = None
156
+ if args.window:
157
+ win = find_window_by_title(args.window)
158
+ if win:
159
+ hwnd = win.hwnd
160
+ print(f"Targeting window [{hwnd}] '{win.title}'")
161
+
162
+ elems = uia.inspect_window(hwnd=hwnd, interactive_only=not args.all, max_elements=args.limit)
163
+ print(f"\nDiscovered {len(elems)} elements:")
164
+ for el in elems:
165
+ safe_name = el.name.encode("ascii", "replace").decode("ascii")
166
+ print(f" [{el.element_id:2d}] {el.control_type:<12} center={el.center} bbox={el.bounding_box} '{safe_name}'")
167
+ return 0
168
+
169
+
170
+ def cmd_snap(args: argparse.Namespace) -> int:
171
+ """Captures a screenshot and optionally overlays Set-of-Mark badges."""
172
+ ensure_dpi_aware()
173
+ attach_input_desktop()
174
+
175
+ cap = capture_screen(monitor_index=args.monitor)
176
+ output_path = Path(args.output)
177
+
178
+ if args.som:
179
+ uia = UIAutomationPlane()
180
+ elems = uia.inspect_window(interactive_only=True, max_elements=50)
181
+ annotator = SetOfMarkAnnotator()
182
+ ann_img, mark_map = annotator.annotate(cap.image, elems)
183
+ ann_img.save(output_path)
184
+ print(f"Saved Set-of-Mark annotated screenshot ({len(mark_map)} badges) to {output_path.resolve()}")
185
+ else:
186
+ cap.image.save(output_path)
187
+ print(f"Saved screenshot ({cap.width}x{cap.height}, {cap.duration_ms}ms) to {output_path.resolve()}")
188
+ return 0
189
+
190
+
191
+ def main() -> None:
192
+ parser = argparse.ArgumentParser(
193
+ prog="extra",
194
+ description="Extra — Flashless Windows 10/11 Computer-Use Engine & MCP Server",
195
+ )
196
+ parser.add_argument(
197
+ "--version", "-v", action="version", version=f"extra {__version__}"
198
+ )
199
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
200
+
201
+ # doctor
202
+ subparsers.add_parser("doctor", help="Run system health and capability diagnostics")
203
+
204
+ # test
205
+ subparsers.add_parser("test", help="Run integration test suite")
206
+
207
+ # run
208
+ run_parser = subparsers.add_parser("run", help="Start the MCP Server on stdio")
209
+ run_parser.add_argument("--transport", default="stdio", choices=["stdio"], help="Transport mode")
210
+
211
+ # inspect
212
+ inspect_parser = subparsers.add_parser("inspect", help="Inspect Windows UI Automation tree")
213
+ inspect_parser.add_argument("--window", "-w", default=None, help="Filter by window title")
214
+ inspect_parser.add_argument("--limit", "-n", type=int, default=30, help="Max elements to display")
215
+ inspect_parser.add_argument("--all", "-a", action="store_true", help="Include non-interactive containers")
216
+
217
+ # snap
218
+ snap_parser = subparsers.add_parser("snap", help="Capture a desktop screenshot")
219
+ snap_parser.add_argument("--output", "-o", default="screenshot.png", help="Output file path")
220
+ snap_parser.add_argument("--monitor", "-m", type=int, default=0, help="Monitor index")
221
+ snap_parser.add_argument("--som", action="store_true", help="Overlay Set-of-Mark numbered badges")
222
+
223
+ args = parser.parse_args()
224
+
225
+ if not args.command:
226
+ parser.print_help()
227
+ sys.exit(0)
228
+
229
+ if args.command == "doctor":
230
+ sys.exit(cmd_doctor())
231
+ elif args.command == "test":
232
+ sys.exit(cmd_test())
233
+ elif args.command == "run":
234
+ sys.exit(cmd_run(args))
235
+ elif args.command == "inspect":
236
+ sys.exit(cmd_inspect(args))
237
+ elif args.command == "snap":
238
+ sys.exit(cmd_snap(args))
239
+
240
+
241
+ if __name__ == "__main__":
242
+ main()
extra/core/__init__.py ADDED
@@ -0,0 +1,113 @@
1
+ """
2
+ Project Extra — Core Engine Package
3
+ High-performance Windows 10/11 desktop automation, dual-plane perception,
4
+ zero-latency SendInput injection, and closed-loop stall breaker.
5
+ """
6
+
7
+ from extra.core.capture import (
8
+ CaptureResult,
9
+ ScreenCaptureEngine,
10
+ capture_roi,
11
+ capture_screen,
12
+ get_capture_engine,
13
+ image_to_base64,
14
+ )
15
+ from extra.core.focus import (
16
+ WindowInfo,
17
+ find_window_by_title,
18
+ find_windows_by_process,
19
+ force_activate_window,
20
+ get_foreground_window,
21
+ get_window_info,
22
+ list_windows,
23
+ )
24
+ from extra.core.geometry import (
25
+ MonitorInfo,
26
+ attach_input_desktop,
27
+ clamp_coordinates,
28
+ denormalize_bbox,
29
+ denormalize_coordinates,
30
+ ensure_dpi_aware,
31
+ get_bbox_center,
32
+ get_cursor_position,
33
+ get_monitors_info,
34
+ get_primary_monitor,
35
+ get_virtual_screen_bounds,
36
+ normalize_bbox,
37
+ normalize_coordinates,
38
+ )
39
+ from extra.core.input_engine import (
40
+ atomic_clipboard_paste,
41
+ instant_type,
42
+ mouse_click,
43
+ mouse_double_click,
44
+ mouse_down,
45
+ mouse_drag,
46
+ mouse_move,
47
+ mouse_scroll,
48
+ mouse_up,
49
+ send_hotkey,
50
+ )
51
+ from extra.core.stall_breaker import (
52
+ ActionOutcome,
53
+ EmergencyAbortError,
54
+ StallBreaker,
55
+ StallStatus,
56
+ )
57
+ from extra.core.uia_plane import (
58
+ SetOfMarkAnnotator,
59
+ UIAutomationPlane,
60
+ UIElement,
61
+ )
62
+
63
+ __all__ = [
64
+ # Geometry
65
+ "ensure_dpi_aware",
66
+ "attach_input_desktop",
67
+ "get_monitors_info",
68
+ "get_primary_monitor",
69
+ "get_virtual_screen_bounds",
70
+ "normalize_coordinates",
71
+ "denormalize_coordinates",
72
+ "normalize_bbox",
73
+ "denormalize_bbox",
74
+ "get_bbox_center",
75
+ "clamp_coordinates",
76
+ "get_cursor_position",
77
+ "MonitorInfo",
78
+ # Capture
79
+ "ScreenCaptureEngine",
80
+ "get_capture_engine",
81
+ "capture_screen",
82
+ "capture_roi",
83
+ "image_to_base64",
84
+ "CaptureResult",
85
+ # Input
86
+ "instant_type",
87
+ "atomic_clipboard_paste",
88
+ "mouse_move",
89
+ "mouse_down",
90
+ "mouse_up",
91
+ "mouse_click",
92
+ "mouse_double_click",
93
+ "mouse_drag",
94
+ "mouse_scroll",
95
+ "send_hotkey",
96
+ # Focus
97
+ "WindowInfo",
98
+ "get_window_info",
99
+ "get_foreground_window",
100
+ "list_windows",
101
+ "find_window_by_title",
102
+ "find_windows_by_process",
103
+ "force_activate_window",
104
+ # UIA Plane
105
+ "UIAutomationPlane",
106
+ "SetOfMarkAnnotator",
107
+ "UIElement",
108
+ # Stall Breaker
109
+ "StallBreaker",
110
+ "StallStatus",
111
+ "ActionOutcome",
112
+ "EmergencyAbortError",
113
+ ]
extra/core/capture.py ADDED
@@ -0,0 +1,187 @@
1
+ """
2
+ Project Extra — Screen Capture Engine
3
+ High-speed screen buffer capture via hardware-accelerated and GDI pipelines,
4
+ supporting sub-30ms frame grabs, multi-monitor selection, ROI cropping,
5
+ and base64 encoding.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import base64
11
+ import concurrent.futures
12
+ import io
13
+ import time
14
+ from dataclasses import dataclass
15
+ from typing import Optional, Tuple
16
+
17
+ import mss
18
+ from PIL import Image
19
+
20
+ from extra.core.geometry import (
21
+ attach_input_desktop,
22
+ clamp_coordinates,
23
+ ensure_dpi_aware,
24
+ )
25
+
26
+
27
+ @dataclass
28
+ class CaptureResult:
29
+ """Encapsulates captured screen image with performance metadata."""
30
+ image: Image.Image
31
+ duration_ms: float
32
+ monitor_index: int
33
+ width: int
34
+ height: int
35
+ crop_box: Optional[Tuple[int, int, int, int]] = None
36
+
37
+ def to_base64(self, format: str = "JPEG", quality: int = 85) -> str:
38
+ """Encodes captured PIL Image into base64 string."""
39
+ return image_to_base64(self.image, format=format, quality=quality)
40
+
41
+
42
+ class ScreenCaptureEngine:
43
+ """
44
+ High-performance Windows screen capture engine.
45
+ Uses an isolated background capture worker thread to avoid Win32 desktop
46
+ security context contamination from COM apartments or UI message loops.
47
+ """
48
+
49
+ def __init__(self) -> None:
50
+ ensure_dpi_aware()
51
+ self._executor = concurrent.futures.ThreadPoolExecutor(
52
+ max_workers=1, thread_name_prefix="ExtraCaptureWorker"
53
+ )
54
+ self._sct: Optional[mss.MSS] = None
55
+
56
+ def _worker_grab(
57
+ self,
58
+ monitor_index: int,
59
+ crop_box: Optional[Tuple[int, int, int, int]],
60
+ ) -> Tuple[bytes, Tuple[int, int], str]:
61
+ # Always attach the clean worker thread to the active input desktop
62
+ attach_input_desktop()
63
+
64
+ if self._sct is None:
65
+ self._sct = mss.MSS()
66
+
67
+ # mss.monitors[0] is all monitors combined, mss.monitors[1] is monitor 0
68
+ mss_idx = monitor_index + 1
69
+ if mss_idx < 1 or mss_idx >= len(self._sct.monitors):
70
+ mss_idx = 1 # Fallback to primary monitor
71
+
72
+ mon_info = self._sct.monitors[mss_idx]
73
+
74
+ if crop_box:
75
+ left, top, right, bottom = crop_box
76
+ left, top = clamp_coordinates(left, top, monitor_index)
77
+ right, bottom = clamp_coordinates(right, bottom, monitor_index)
78
+
79
+ if right <= left or bottom <= top:
80
+ region = mon_info
81
+ else:
82
+ region = {
83
+ "left": left,
84
+ "top": top,
85
+ "width": right - left,
86
+ "height": bottom - top,
87
+ }
88
+ else:
89
+ region = mon_info
90
+
91
+ raw_frame = self._sct.grab(region)
92
+ return (bytes(raw_frame.bgra), raw_frame.size, "BGRX")
93
+
94
+ def capture(
95
+ self,
96
+ monitor_index: int = 0,
97
+ crop_box: Optional[Tuple[int, int, int, int]] = None,
98
+ ) -> CaptureResult:
99
+ """
100
+ Captures a screen frame from the specified monitor.
101
+
102
+ Args:
103
+ monitor_index: 0-based index of monitor (0 = primary).
104
+ crop_box: Optional (left, top, right, bottom) physical pixel bounding box.
105
+
106
+ Returns:
107
+ CaptureResult with PIL Image and latency stats.
108
+ """
109
+ ensure_dpi_aware()
110
+ t_start = time.perf_counter()
111
+
112
+ future = self._executor.submit(self._worker_grab, monitor_index, crop_box)
113
+ bgra_bytes, size, raw_mode = future.result()
114
+
115
+ img = Image.frombytes("RGB", size, bgra_bytes, "raw", raw_mode)
116
+ duration_ms = (time.perf_counter() - t_start) * 1000.0
117
+
118
+ return CaptureResult(
119
+ image=img,
120
+ duration_ms=round(duration_ms, 2),
121
+ monitor_index=monitor_index,
122
+ width=img.width,
123
+ height=img.height,
124
+ crop_box=crop_box,
125
+ )
126
+
127
+ def close(self) -> None:
128
+ """Releases capture worker thread and resources."""
129
+ def _cleanup():
130
+ if self._sct is not None:
131
+ try:
132
+ self._sct.close()
133
+ except Exception:
134
+ pass
135
+ self._sct = None
136
+
137
+ try:
138
+ self._executor.submit(_cleanup).result(timeout=1.0)
139
+ except Exception:
140
+ pass
141
+ self._executor.shutdown(wait=False)
142
+
143
+ def __enter__(self) -> "ScreenCaptureEngine":
144
+ return self
145
+
146
+ def __exit__(self, exc_type, exc_val, exc_tb) -> None:
147
+ self.close()
148
+
149
+
150
+ _default_engine: Optional[ScreenCaptureEngine] = None
151
+
152
+
153
+ def get_capture_engine() -> ScreenCaptureEngine:
154
+ """Returns or initializes the shared ScreenCaptureEngine."""
155
+ global _default_engine
156
+ if _default_engine is None:
157
+ _default_engine = ScreenCaptureEngine()
158
+ return _default_engine
159
+
160
+
161
+ def capture_screen(
162
+ monitor_index: int = 0,
163
+ crop_box: Optional[Tuple[int, int, int, int]] = None,
164
+ ) -> CaptureResult:
165
+ """Convenience function to capture screen via default engine."""
166
+ return get_capture_engine().capture(monitor_index=monitor_index, crop_box=crop_box)
167
+
168
+
169
+ def capture_roi(
170
+ left: int, top: int, right: int, bottom: int, monitor_index: int = 0
171
+ ) -> CaptureResult:
172
+ """Convenience function to capture a specific region of interest."""
173
+ return capture_screen(monitor_index=monitor_index, crop_box=(left, top, right, bottom))
174
+
175
+
176
+ def image_to_base64(image: Image.Image, format: str = "JPEG", quality: int = 85) -> str:
177
+ """Converts a PIL Image to a base64 encoded string."""
178
+ buffer = io.BytesIO()
179
+ if format.upper() == "JPEG":
180
+ if image.mode != "RGB":
181
+ image = image.convert("RGB")
182
+ image.save(buffer, format="JPEG", quality=quality, optimize=True)
183
+ else:
184
+ image.save(buffer, format=format)
185
+
186
+ encoded = base64.b64encode(buffer.getvalue()).decode("utf-8")
187
+ return encoded