
    Oj?8                    f    d Z ddlmZ ddlZddlZddlZddlZddlZd
dZ	ddZ
ddZdZddZd	 Zy)u^  Windows in-process desktop-control MCP for Jarvis.

This is the Windows replacement for the macOS ``macos-mcp`` HTTP server. It
gives Claude OS-wide "control any app" hands — see the screen and drive any
application (Teams, WhatsApp, Chrome, VS Code, anything) by moving the real
mouse, typing, pressing hotkeys, launching apps, listing windows, reading the
accessibility tree, and running shell commands.

Unlike the macOS build (which needed an external HTTP server so it could
inherit the app's Accessibility grant), Windows needs no permission wall for
SendInput/screenshots against ordinary non-elevated apps. So we run the tools
IN-PROCESS via the Claude Agent SDK's in-process MCP server: no external
server, no auth token, no HTTP hop. The server object is placed in the session
options ``mcp_servers`` dict under the key ``"desktop"``, and Claude sees the
tools as ``mcp__desktop__<name>``.

Backing libraries (all imported lazily inside each tool so importing this
module never hard-fails when a dependency is missing):
- ``mss``          — fast full-screen screenshots.
- ``pyautogui``    — mouse move/click, keyboard typing, hotkeys, scroll.
- ``pywin32``      — enumerate visible top-level windows and their bounds.
- ``uiautomation`` — read the foreground window's UI accessibility tree.

Set ``MCP_DESKTOP=0`` to disable the desktop tools entirely.
    )annotationsNc                 r    t         j                  dk(  xr# t         j                  j                  dd      dk7  S )u   Whether the desktop-control MCP should be exposed to Claude.
    Windows-only: the Mac uses the macos-mcp HTTP server instead
    (voice/desktop_server.py) — this module's hands are pywin32-based.ntMCP_DESKTOP10)osnameenvironget     C/Users/ahmed/devFolder/Ultron/claude-voice/voice/desktop_control.pyenabledr   %   s+     77d?Hrzz~~mSASHHr   c                   d}	 t        t        j                  |       }t        j                  ddd|g|ddd      }|j
                  r/|j
                  xs d	j                         j                         d
   nd	}|j                  d      |j                  dd      d
   xs | fS # t        $ r}dt        |      dd fcY d}~S d}~ww xY w)u  Open an app by fuzzy name the way the Start menu does.

    Resolves the name via `Get-StartApps` (the real Start-menu index, which
    covers Store/UWP apps, Steam games, and desktop apps alike) to an AppID,
    then launches it — a Steam/URL AppID directly, an AUMID via
    shell:AppsFolder. Falls back to Start-Process on the raw name. Returns
    (ok, matched-name-or-error). This is why "open Discord" / "open Marvel
    Rivals" works where a bare `start "Name"` fails.
    aH  $n=$env:JARVIS_APP;$a=Get-StartApps | Where-Object { $_.Name -like "*$n*" } | Sort-Object { $_.Name.Length } | Select-Object -First 1;if($a){ if($a.AppID -match "://"){ Start-Process $a.AppID } else { Start-Process ("shell:AppsFolder\" + $a.AppID) }; "OK:"+$a.Name } else { try{ Start-Process $n; "OK:"+$n }catch{ "FAIL:"+$n } })
JARVIS_APP
powershell
-NoProfile-CommandT   )envcapture_outputtexttimeout zOK::   FNP   )dictr	   r   
subprocessrunstdoutstrip
splitlines
startswithsplit	Exceptionstr)r
   psr   routes         r   shell_launchr.   ,   s    	I 	$2::$/NN<R8DtR
 <=88qxx~2$$&113B7u%syya'8'<'DEE $s1vcr{##$s   BB$ $	C-C<CCc                    dd| dgiS )z2Wrap a plain string as an MCP text content result.contentr   typer   r   )msgs    r   _textr4   K   s    5677r   i   c                    ddl } | j                         5 }|j                  d   }|j                  |      }|j                  |j                  }}t        j                  |      ddddddf   dddddddf   }ddd       d}t        kD  r=|t        z  }ddl}|j                  t        t        |z        f|j                        }ddl}|j                  ddddddddf         \  }	}
|	st        d      |dkD  r=d	| d
 dd    d|d    d|j                  d    d
|j                  d    d|dd|ddnd| d
 d}|
j                         |fS # 1 sw Y   xY w)u@   Capture the full virtual desktop → (png_bytes, geometry_note).r   N   r   g      ?)interpolationz.pngzpng encode failedzReal screen: xz px (virtual desktop, origin left,topz). Image shown: r   u    px — scale factor z.3fzR. To CLICK something you located on this image, MULTIPLY its image coordinates by z to get real screen pixels.zScreen: uK    px, shown at full resolution — image coordinates ARE screen coordinates.)mssmonitorsgrabwidthheightnparray_MAX_SHOT_Wcv2resizeint
INTER_AREAimencodeRuntimeErrorshapetobytes)r<   sctmonshotwhimgscalerD   okpngnotes               r   _grab_screenrV   V   s   	cll1oxx}zz4;;1hhtnQ2A2X&q!TrTz2	 

 E;Kjj{CE	N;'*~~  7ll63q!TrTz?3GB.// s{ A3as"?6{m1SZL(81ayy|n1% =#C[(C	E qc1# 2 3 	 ;;=$/ 
s   A'EE%c                    ddl m} m}  | ddi       d+d       } | ddt        t        t        t
        d      d+d	       } | d
dt        t        d      d+d       } | dddt        i      d+d       } | dddt        i      d+d       } | dddt        i      d+d       } | dddt        i      d+d       } | ddi       d+d        }	 | d!d"i       d+d#       }
 | d$d%d&t        i      d+d'       } |d(d)||||||||	|
|g
*      S ),aU  Build and return the in-process ``desktop`` MCP server.

    Imports the SDK's in-process MCP helpers here (not at module top) so that
    merely importing this module never fails if the installed
    ``claude_agent_sdk`` lacks ``tool``/``create_sdk_mcp_server``. Returns the
    server object to place under ``mcp_servers["desktop"]``.
    r   )toolcreate_sdk_mcp_server
screenshotzCapture the full screen so you can SEE it. Returns the desktop image plus its exact scale factor for converting image coordinates to real screen pixels.c                   K   	 t               \  }}t        j                  |      j                  d      }dd|dd|ddgiS # t        $ r}t        d|       cY d }~S d }~ww xY ww)	Nasciir0   r   r1   image	image/pngr2   datamimeTypezscreenshot failed: )rV   base64	b64encodedecoder(   r4   )argsrT   rU   r`   r-   s        r   rZ   z build_server.<locals>.screenshot}   sy     	4$IC##C(//8D. $KH     	4.qc233	4s4   A&=A A&	A#AA#A&A##A&clickz_Move the mouse to absolute screen pixel (x, y) and click. Origin is the top-left of the screen.)r8   ybuttondoublec           
     `  K   	 dd l }t        | d         }t        | d         }| j                  d      xs d}t        | j                  dd            }|j	                  ||||rdnd	
       |rdnd}t        | d| d| d| d      S # t        $ r}t        d|       cY d }~S d }~ww xY ww)Nr   r8   rg   rh   r9   ri   F   r   )rh   clickszdouble-clickedclicked z at (, ).zclick failed: )	pyautoguirF   r   boolrf   r4   r(   )re   rq   r8   rg   rh   ri   kindr-   s           r   rf   zbuild_server.<locals>.click   s     
	/DIADIAXXh'16F$((8U34FOOAqVOK'-#9DD66(%s"QCr:;; 	/>!-..	/s5   B.BB
 	B.
	B+B& B+!B.&B++B.movez/Move the mouse to absolute screen pixel (x, y).)r8   rg   c                   K   	 dd l }t        | d         }t        | d         }|j                  ||       t        d| d| d      S # t        $ r}t        d|       cY d }~S d }~ww xY ww)Nr   r8   rg   z
moved to (ro   rp   zmove failed: )rq   rF   moveTor4   r(   )re   rq   r8   rg   r-   s        r   rt   zbuild_server.<locals>.move   ss     	.DIADIAQ":aS1#R011 	.=,--	.s5   A,AA A,	A)A$A)A,$A))A,	type_textzFType the given text at the current focus, as if typed on the keyboard.r   c                   K   	 dd l }t        | j                  dd            }|j                  |d       t	        dt        |       d      S # t        $ r}t	        d|       cY d }~S d }~ww xY ww)	Nr   r   r   g{Gz?)intervalztyped z characters.ztype_text failed: )rq   r)   r   writer4   lenr(   )re   rq   r   r-   s       r   rw   zbuild_server.<locals>.type_text   sm     	3txx+,DOOD4O06#d)L9:: 	3-aS122	3s5   A2A	A A2	A/A*$A/%A2*A//A2keyzOPress a keyboard hotkey combo, e.g. 'ctrl+c' or 'win+d'. Combine keys with '+'.keysc                $  K   	 dd l }t        | j                  dd            j                         }|st	        d      S dddd}|j                  d      D cg c]\  }|j                         rJ|j                  |j                         j                         |j                         j                               ^ }} |j                  |  t	        ddj                  |       d	      S c c}w # t        $ r}t	        d
|       cY d }~S d }~ww xY ww)Nr   r}   r   zkey failed: no keys given.winleft)wincmdwindows+zpressed .zkey failed: )
rq   r)   r   r$   r4   r'   lowerhotkeyjoinr(   )re   rq   rawaliasppartsr-   s          r   r|   zbuild_server.<locals>.key   s     	-dhhvr*+113C9::%iINE!iin;,	 YYqwwy0!'')//2CD,  ;Ie$8CHHUO#4A677;  	-<s+,,	-sQ   D9C, DC, A!C'8.C, &D'C, ,	D5DDDDDscrollzLScroll the mouse wheel by the given amount (positive = up, negative = down).amountc                   K   	 dd l }t        | d         }|j                  |       t        d| d      S # t        $ r}t        d|       cY d }~S d }~ww xY ww)Nr   r   z	scrolled r   zscroll failed: )rq   rF   r   r4   r(   )re   rq   r   r-   s       r   r   zbuild_server.<locals>.scroll   s_     	0h(FV$9VHA.// 	0?1#.//	0s0   A16 A	AAAAAAlaunchzOpen/launch/focus any app by name the way a person would from the Start menu (e.g. 'Discord', 'Marvel Rivals', 'Microsoft Teams', 'notepad'), or a path/URL.appc                  K   t        | j                  dd            j                         }|st        d      S t        j
                  j                  |      s8|j                  d      s'd|v s#d|v s|j                         j                  d      r%	 t	        j                  |       t        d| d	      S t        |      \  }}t        |r
d| d	      S d
| d| d      S # t        $ r Y 7w xY ww)Nr   r   zlaunch failed: no app given.)zhttp://zhttps://\/z.exez	launched r   zcouldn't find an app matching 'z' (rp   )r)   r   r$   r4   r	   pathexistsr&   r   endswith	startfiler(   r.   )re   r   rS   matcheds       r   r   zbuild_server.<locals>.launch   s      $((5"%&,,.788GGNN33>>2I#J3;#*		0D0DV0LS!yQ/00 #3'Gry	+ + 	+;C5 A%Yb*+ 	+	  s*   BC0#C! 4-C0!	C-*C0,C--C0r   zTList visible top-level windows with their titles and bounds (left,top,right,bottom).c                  K   	 dd l 	 g fd}j                  |d        st        d      S t        dj	                              S # t        $ r t        d      cY S w xY w# t        $ r}t        d|       cY d }~S d }~ww xY ww)Nr   z.windows unavailable: pywin32 is not installed.c                    j                  |       sy j                  |       }|j                         sy j                  |       \  }}}}j	                  | d| d| d| d| 	       y )N | r:   )IsWindowVisibleGetWindowTextr$   GetWindowRectappend)	hwnd_titleltr+   bfoundwin32guis	          r   _cbz*build_server.<locals>.windows.<locals>._cb   sq    //5 ..t4{{}%33D9
1awc!AaS!AaS9:r   z no visible titled windows found.
zwindows failed: )r   r(   r4   EnumWindowsr   )re   r   r-   r   r   s      @@r   r   zbuild_server.<locals>.windows   s     	K	1!E;   d+?@@5)**#  	KIJJ	K$  	1+A3/00	1s[   B
A &A& B
A& B
A# B
"A##B
&	B/B<B=B
BB
snapshotzwSee the REAL buttons: returns a screenshot AND a text list of the foreground window's UI elements (accessibility tree).c                P  	
K   g }	 t               \  }}t        j                  |      j                  d      }|j	                  d|d       |j	                  d|dd       	 d	d l}|j                         }||j	                  dd
d       d|iS g 
	
fd	 	|d	       
rdj                  
      nd}|j	                  dd|z   d       d|iS # t
        $ r"}|j	                  dd| dd       Y d }~d }~ww xY w# t
        $ r |j	                  ddd       Y d|iS w xY ww)Nr\   r   r1   r]   r^   r_   z(screenshot failed: )r   zNo foreground window found.r0   c                   |dkD  ry 	 | j                   }|j                   d|j                   d|j                   d|j                   }d}	 | j                  }t        | dd      }d|z  }	j                  | | d| d|        	 | j                         D ]  } ||d	z           y # t
        $ r d}Y lw xY w# t
        $ r d}Y nw xY w# t
        $ r Y y w xY w)
Nrk   r:   ?r   ControlTypeNameControlz  r   r   )
BoundingRectangler9   r;   rightbottomr(   Namegetattrr   GetChildren)
ctrldepthrectboundsr
   ctypeindentchild_walkliness
           r   r   z-build_server.<locals>.snapshot.<locals>._walk  s    19!11D!%1TXXJa!%Adkk]<F 99D  &7Cxwc$s6(CD!%!1!1!3eUQY/ "4 ! ! F!
 ! D ! s6   AB) B: !C )B76B7:CC	CCr   z(no elements read)z6Foreground UI elements (ControlType | Name | bounds):
z<Accessibility tree unavailable (uiautomation not installed).)	rV   rb   rc   rd   r   r(   uiautomationGetForegroundControlr   )re   r0   rT   rU   r`   r-   autofgtreer   r   s            @@r   r   zbuild_server.<locals>.snapshot   sq     !	B$IC##C(//8DNNFD9:NNGT(35 6(	F'**,Bz(E G H!7++!E. "aL',499U#2FDNNF%GIM%NO P 7##[  	BNNF&:1#Q$?A B B	BR  	FNNF%DE F 7##		FsY   D&AC #-D  D&=D  D&	C=C83D&8C==D& D#D&"D##D&shellz/Run a PowerShell command and return its output.commandc                P  K   	 t        | j                  dd            }t        j                  ddd|gddd      }|j                  xs d|j
                  xs dz   }t        |      d	kD  r|d d	 d
z   }t        |xs d      S # t        $ r}t        d|       cY d }~S d }~ww xY ww)Nr   r   r   r   r   T<   )r   r   r   i  u   
…(truncated)z(no output)zshell failed: )	r)   r   r!   r"   r#   stderrr{   r4   r(   )re   r   procr,   r-   s        r   r   zbuild_server.<locals>.shell7  s     	/$((9b12G>>|ZA#$D ;;$"):;C3x$%4j#55-.. 	/>!-..	/s5   B&A=B B&	B#BB#B&B##B&desktopz1.0.0)r
   versiontools)re   r    returnr    )claude_agent_sdkrX   rY   rF   r)   rr   )rX   rY   rZ   rf   rt   rw   r|   r   r   r   r   r   s               r   build_serverr   s   s    =	, /024	44	4 
' 2#
=?/?/ 
&C#
 . . 
+ %sm-3-3 
% #%+SM3-3- 
( "$,c?4040 
( /16>+>+$ 
) ,-/11110 
* N
6$6$p 
'Dc
// !5$	3w%1 r   )r   rr   )r
   r)   r   ztuple[bool, str])r3   r)   r   r    )r   ztuple[bytes, str])__doc__
__future__r   rb   ior	   r!   numpyrA   r   r.   r4   rC   rV   r   r   r   r   <module>r      s@   4 #  	 	  I$>8 :Yr   