Ë
    ãß²j÷ß  ã                   ój	  — d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	m
Z
 ddlmZmZ ddlmZ ddlmZmZ dZh d	£Zd
ddddœZddddœZe	 G d„ d«      «       Ze	 G d„ d«      «       ZdZdZdZdZdedefd„Zdedefd„Zdedefd„ZdZ d Z!d!Z"d"Z#d#Z$d$e$z   d%z   Z%d&e%z   d'z   Z&g d(‘d)‘d*‘d+‘d,‘d-‘d.‘d/‘d0‘d1‘d2‘d3‘d4‘d5e%z   d6d7d8d9f‘d:e&z   d;z   d<z   e&z   d=z   d>d7d8d?f‘d@‘dA‘dB‘dC‘dD‘dE‘dF‘dG‘dH‘dI‘dJ‘dK‘dL‘dM‘dN‘dO‘dP‘dQ‘dR‘dS‘dT‘dU‘dV‘dW‘dX‘dY‘dZ‘d[‘d\‘d]‘d^‘d_‘d`‘da‘db‘dc‘dd‘de‘df‘dg‘dh‘di‘dj‘dk‘dle#› dm�dnd7dodpf‘dq‘dr‘ds‘dt‘du‘dv‘dw‘dx‘dye#› dz�d{d7d|d}f‘d~‘d‘d€‘d�‘d‚‘dƒ‘d„‘d…‘d†‘d‡‘dˆ‘d‰‘dŠ‘d‹‘dŒ‘d�‘dŽ‘d�‘d�‘d‘‘d’‘d“‘d”e#› �d•d7d–d—f‘d˜e#› �d™d7d–dšf‘d›‘dœ‘d�‘dž‘dŸ‘d ‘d¡‘d¢‘d£‘d¤‘d¥‘d¦‘d§‘ ee«      d¨d7d©dªf‘ ee«      d«d7d©d¬f‘ ee«      d­d®d©d¯f‘d°‘ ee«      d±d®d©d²f‘ ee«      d³d7d©d´f‘dµ‘ ee«      d¶d®d©d·f‘ ee«      d¸d7d©d¹f‘dº‘d»‘d¼‘d½‘d¾‘d¿‘dÀ‘dÁ‘dÂ‘dÃ‘dÄ‘dÅ‘dÆ‘dÇ‘dÈ‘dÉe › e!› dÊe › e"› e!› dË�dÌd®d8dÍf‘dÎ‘Z'e'D � �cg c]%  ^} } ejP                  | ejR                  «      g|¢­‘Œ' c}} Z* e+h dÏ£«      Z,i dÐdÑ“dÒdÑ“dÓdÑ“dÔdÑ“dÕdÑ“dÖdÑ“d×dÑ“dØdÑ“dÙdÑ“dÚdÑ“dÛdÑ“dÜdÝ“dÞdÝ“dßdà“dádà“dâdã“Z- ejP                  däejR                  «      Z. ejP                  dåejR                  «      Z/ ejP                  dæ«      Z0dçe1de1fdè„Z2déedêedëedìedíedîedeeef   fdï„Z3dð\  Z4Z5Z6h dñ£Z7h dò£Z8h dó£Z9i dôdõ“död÷“dødù“dúdû“düdý“dþdÿ“�d �d“�d�d“�d�d“�d�d“�d�d	“�d
�d“�d�d“�d�d“�d�d“�d�d“�d�d“Z: e;e:«      Z<�d�dhZ=�dedef�d„Z>dçe1de;f�d„Z?dìedef�d„Z@ ejP                  �d«      ZA ejP                  �d«      ZBdçee   dee   f�d„ZC�d=�d e�d!edee   f�d"„ZD�d>�d#e�d$edef�d%„ZE�d#edef�d&„ZF�d#edef�d'„ZG�d>�dd�d(œ�d#e�d$e�d)e�d*edz  deeeHf   f
�d+„ZI�d?�d,e�d-eJdeeJef   f�d.„ZK�d,edef�d/„ZL�d@�d0edee   f�d1„ZM�d2ZN�d0ef�d3„ZO�d4ZP�d$edef�d5„ZQ�d6ee   def�d7„ZR�d8e�d$e�d9e�d:e�d6ee   def�d;„ZS�d#edef�d<„ZTyc c}} w (A  ug  Skills Guard â€” regex static scan of externally-sourced skills plus a trust-aware install policy.

Trust: builtin (never scanned), trusted (openai/anthropics/... repos: caution allowed), community (any
findings block unless --force). ``scan_skill`` -> ``should_allow_install`` -> ``format_scan_report``.
Known gap: language write APIs (open(..., 'w'), Path.write_text, shutil.copy*, fs.writeFileSync) aimed at
agent-config files surface only the low *_ref finding â€” static regexes cannot tie the call to a dynamic
destination; future coverage belongs as a fourth "mechanical" tier next to agent_config_mod_shell.é    N)Úsuppress)ÚasdictÚ	dataclassÚfield)ÚdatetimeÚtimezone)ÚPath)ÚListÚTuplezskills-guard-v6>   úNVIDIA/skillsúopenai/skillsúanthropics/skillsúhuggingface/skills)Úallowr   r   )r   r   Úblock)r   r   r   )r   r   Úask)ÚbuiltinÚtrustedÚ	communityúagent-createdé   é   )ÚsafeÚcautionÚ	dangerousc                   óT   — e Zd ZU eed<   eed<   eed<   eed<   eed<   eed<   eed<   y)	ÚFindingÚ
pattern_idÚseverityÚcategoryÚfileÚlineÚmatchÚdescriptionN)Ú__name__Ú
__module__Ú__qualname__ÚstrÚ__annotations__Úint© ó    ú7/home/ubuntu/.hermes/hermes-agent/tools/skills_guard.pyr   r   &   s&   … àƒOØƒMØƒMØ
ƒIØ
ƒIØƒJØÔr,   r   c                   ó�   — e Zd ZU eed<   eed<   eed<   eed<    ee¬«      Zee	   ed<   dZ
eed<   dZeed	<    ee¬«      Zeed
<   y)Ú
ScanResultÚ
skill_nameÚsourceÚtrust_levelÚverdict)Údefault_factoryÚfindingsÚ Ú
scanned_atÚsummaryÚscan_provenanceN)r%   r&   r'   r(   r)   r   Úlistr5   r
   r   r7   r8   Údictr9   r+   r,   r-   r/   r/   1   sM   … àƒOØƒKØÓØƒLÙ#°DÔ9€Hˆd�7‰mÓ9Ø€J�ÓØ€GˆSÓÙ!°$Ô7€O�TÔ7r,   r/   a0  (?:\bwrit(?:e|es|ing)\b|\bwritten\b|\bedit(?:s|ed|ing)?\b|\bmodif(?:y|ies|ied|ying|ication)s?\b|\bupdat(?:e|es|ed|ing)\b|\bappend(?:s|ed|ing)?\b|\bprepend(?:s|ed|ing)?\b|\binject(?:s|ed|ing)?\b|\boverwrit(?:e|es|ing)\b|\boverwritten\b|\breplac(?:e|es|ed|ing)\b|\balter(?:s|ed|ing)?\b|\badd(?:s|ed|ing)\b)z4(?:AGENTS\.md|CLAUDE\.md|\.cursorrules|\.clinerules)z"\.hermes/(?:config\.yaml|SOUL\.md)z(\.(?:claude/settings|codex/config)[\w.]*Úfile_altÚreturnc           	      ó    — d| › d| › d| › d| › d�	S )aŸ  Mechanical shell write into *file_alt*: ``>``/``>>``, ``sed -i``, ``tee`` (target as immediate argument, so
    ``| tee output | AGENTS.md |`` cells miss), ``cp``/``mv`` with the file as destination (source arg required, so
    ``cp AGENTS.md backup/`` misses; ``AGENTS.md.bak`` is not the file). A single ``>`` needs a preceding word/quote/
    paren char so blockquotes (``> text``) and arrows (``-> file``) miss.z"(?:>>|[\w"\'`)\]]\s*>)\s*[~\w./-]*zD(?!\.?\w)|\bsed\b[^\n]*\s(?:-[A-Za-z]*i[A-Za-z]*|--in-place)\b[^\n]*z((?!\.?\w)|\btee\s+(?:-a\s+)?[~\w./"\'-]*z3(?!\.?\w)|\b(?:cp|mv)\s+[^\s|;&]+\s+[^\n|;&]{0,40}?z	(?!\.?\w)r+   ©r<   s    r-   Ú_shell_write_rer@   M   s9   € ð .¨h¨Zð 8GØGOÀjð Q+Ø+3¨*ð 58Ø8@°zÀð	LðMr,   c           	      ó0   — dt         › d| › dt         › d| › d�	S )uT  Prose instructing modification of *file_alt*: an imperative-position verb (line start / bullet), or a mid-line
    verb with a directive marker ("you must", "please", "make sure to"). Descriptive prose ("skills that edit
    AGENTS.md") misses; the verbâ†’file gap forbids commas so enumerations ("Write skills, AGENTS.md, CLAUDE.md") miss.z^\s*(?:[-*+]\s+|\d+[.)]\s+)?z[^\n,]{0,80}?zl\b|(?:\byou\s+(?:must|should|need\s+to)\s+|\bplease\s+|\bmake\s+sure\s+(?:to\s+|you\s+)|\bbe\s+sure\s+to\s+)z\b)ÚMODIFY_VERB_REr?   s    r-   Ú_prose_modify_rerC   Y   s3   € ð
 (¬Ð'7°ÀxÀjð QBô Ð˜?¨8¨*°Bð	8ð9r,   c                 ó   — | › d�S )uÅ   "<file> should contain/include ..." prose. Authoring guides and attacks share this shape and are not
    separable statically, so the tier is scored high (caution â†’ confirmation), never critical.zQ\b[^\n]{0,40}?\b(?:should|must|needs?\s+to)\s+(?:contain|say|include|have|list)\br+   r?   s    r-   Ú_content_contract_rerE   d   s   € ð ˆjÐkÐlÐlr,   zt(?!(?:\w+\s+){0,4}?(?:never|not|doesn\'?t|didn\'?t|won\'?t|isn\'?t|aren\'?t|can\'?t|cannot|mustn\'?t|shouldn\'?t)\b)z(?:\w+\s+){0,3}?zš(?!(?:(?:the|your|each|every|all|to|a)\s+)?(?:sub-?agents?|sub-?tasks?)\b|(?:(?:the|your|each|every|all|to|a)\s+)(?:workers?|delegates?|children|child)\b)z(?:bash|sh|zsh|ksh|dash)zs(?:\.ssh[/\\]id_(?:rsa|ed25519|ecdsa|dsa)(?!\.pub)|\.env\b|credentials\b|\.netrc\b|\.pgpass\b|\.npmrc\b|\.pypirc\b)z["\'][^"\'\n]*z[^"\'\n]*["\']z!(?:os\.path\.expanduser\s*\(\s*)?z\s*\)?)zvcurl\s+(?![^\n]*https?://(?:localhost|127\.0\.0\.1|\[::1\]))[^\n]*\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)S?\bÚenv_exfil_curlÚcriticalÚexfiltrationz6curl command interpolating secret environment variable)zvwget\s+(?![^\n]*https?://(?:localhost|127\.0\.0\.1|\[::1\]))[^\n]*\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)S?\bÚenv_exfil_wgetrG   rH   z6wget command interpolating secret environment variable)znfetch\s*\((?![^\n]*https?://(?:localhost|127\.0\.0\.1|\[::1\]))[^\n]*\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD)S?\bÚenv_exfil_fetchrG   rH   z6fetch() call interpolating secret environment variable)zwhttpx?\.(get|post|put|patch)\s*\((?![^\n]*https?://(?:localhost|127\.0\.0\.1|\[::1\]))[^\n]*(KEY|TOKEN|SECRET|PASSWORD)Úenv_exfil_httpxrG   rH   z&HTTP library call with secret variable)zyrequests\.(get|post|put|patch)\s*\((?![^\n]*https?://(?:localhost|127\.0\.0\.1|\[::1\]))[^\n]*(KEY|TOKEN|SECRET|PASSWORD)Úenv_exfil_requestsrG   rH   z*requests library call with secret variable)zbase64[^\n]*envÚencoded_exfilÚhighrH   z0base64 encoding combined with environment access)z\$HOME/\.ssh|\~/\.sshÚssh_dir_accessrN   rH   zreferences user SSH directory)z\$HOME/\.aws|\~/\.awsÚaws_dir_accessrN   rH   z)references user AWS credentials directory)z\$HOME/\.gnupg|\~/\.gnupgÚgpg_dir_accessrN   rH   zreferences user GPG keyring)z\$HOME/\.kube|\~/\.kubeÚkube_dir_accessrN   rH   z&references Kubernetes config directory)z\$HOME/\.docker|\~/\.dockerÚdocker_dir_accessrN   rH   z5references Docker config (may contain registry creds))z'\$HOME/\.hermes/\.env|\~/\.hermes/\.envÚhermes_env_accessrG   rH   z'directly references Hermes secrets file)zFcat\s+(?!>)[^\n]*(\.env|credentials|\.netrc|\.pgpass|\.npmrc|\.pypirc)Úread_secrets_filerG   rH   zreads known secrets filez,\b(?:readFile(?:Sync)?|readTextFile)\s*\(\s*Újs_read_secrets_filerG   rH   z(JavaScript reads a known credential filez\bopen\s*\(\s*zV(?!\s*\)?\s*,\s*["\'][^"\']*[wax][^"\']*["\'])(?![^\n]*\bmode\s*=\s*["\'][^"\']*[wax])z|\bPath\s*\(\s*z7\s*\)\.(?:read_text|read_bytes|readlines|readline)\s*\(Úpy_read_secrets_filez$Python reads a known credential file)zprintenv|env\s*\|Údump_all_envrN   rH   zdumps all environment variables)z&^[^#\n]*os\.environ\b(?!\s*\.get\s*\()Úpython_os_environrN   rH   zDaccesses os.environ outside comments/docstrings (potential env dump))zOos\.environ\s*\.get\s*\(\s*["\'][^"\']*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)Úpython_environ_get_secretÚmediumrH   zHreads secret via os.environ.get() (normal API-key access; informational))z@os\.getenv\s*\(\s*[^\)]*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL)Úpython_getenv_secretr[   rH   zCreads secret via os.getenv() (normal API-key access; informational))zprocess\.env\[Únode_process_envrN   rH   z*accesses process.env (Node.js environment))z*(?-i:ENV)\[.*(?:KEY|TOKEN|SECRET|PASSWORD)Úruby_env_secretrG   rH   zreads secret via Ruby ENV[])z\(?<![-/])\b(dig|nslookup|host)\s+(?:[-+@]\S*(?:\s+[^\s$"\'-][^\s$]*)?\s+)*["\']?[^\s"\'$]*\$Ú	dns_exfilrG   rH   zBDNS lookup with variable interpolation (possible DNS exfiltration))z,>\s*/tmp/[^\s]*\s*&&\s*(curl|wget|nc|python)Útmp_stagingrG   rH   zwrites to /tmp then exfiltrates)z!\[.*\]\(https?://[^\)]*\$\{?Úmd_image_exfilrN   rH   zBmarkdown image URL with variable interpolation (image-based exfil))z\[.*\]\(https?://[^\)]*\$\{?Úmd_link_exfilrN   rH   z)markdown link with variable interpolation)z=ignore\s+(?:\w+\s+)*(previous|all|above|prior)\s+instructionsÚprompt_injection_ignorerG   Ú	injectionz.prompt injection: ignore previous instructions)zyou\s+are\s+(?:\w+\s+)*now\s+Úrole_hijackrN   rd   z%attempts to override the agent's role)zqdo\s+not\s+(?:\w+\s+)*tell\s+(?:\w+\s+)*the\s+user(?!.*\b(?:unless|except|until|confirm|diagnose|verify|check)\b)Údeception_hiderN   rd   z-instructs agent to hide information from user)z0system\s+(?:\w+\s+)*prompt\s+(?:\w+\s+)*overrideÚsys_prompt_overriderG   rd   z&attempts to override the system prompt)z+pretend\s+(?:\w+\s+)*(you\s+are|to\s+be)\s+Úrole_pretendrN   rd   z6attempts to make the agent assume a different identity)zRdisregard\s+(?:\w+\s+)*(your|all|any)\s+(?:\w+\s+)*(instructions|rules|guidelines)Údisregard_rulesrG   rd   z&instructs agent to disregard its rules)z-output\s+(?:\w+\s+)*(system|initial)\s+promptÚleak_system_promptrN   rd   z%attempts to extract the system prompt)z.(when|if)\s+no\s*one\s+is\s+(watching|looking)Úconditional_deceptionrN   rd   z=conditional instruction to behave differently when unobserved)zwact\s+as\s+(if|though)\s+(?:\w+\s+)*you\s+(?:\w+\s+)*(have\s+no|don\'t\s+have)\s+(?:\w+\s+)*(restrictions|limits|rules)Úbypass_restrictionsrG   rd   z+instructs agent to act without restrictions)z5translate\s+.*\s+into\s+.*\s+and\s+(execute|run|eval)Útranslate_executerG   rd   z(translate-then-execute evasion technique)z9<!--[^>]*(?:ignore|override|system|secret|hidden)[^>]*-->Úhtml_comment_injectionrN   rd   z$hidden instructions in HTML comments)z5<\s*div\s+style\s*=\s*["\'][\s\S]*?display\s*:\s*noneÚ
hidden_divrN   rd   z(hidden HTML div (invisible instructions))zˆrm\s+-rf\s+/(?:(?!tmp(?:\b|/)|var/tmp(?:\b|/)|dev/shm(?:\b|/)|run(?:\b|/))|(?:tmp|var/tmp|dev/shm|run)/(?:[^/\s]*/)*\.\.(?=/|[\s;&|]|$))Údestructive_root_rmrG   Údestructivezrecursive delete from root)z+rm\s+(-[^\s]*)?r.*\$HOME|\brmdir\s+.*\$HOMEÚdestructive_home_rmrG   rq   z)recursive delete targeting home directory)zchmod\s+777Úinsecure_permsr[   rq   zsets world-writable permissions)z	>\s*/etc/Úsystem_overwriterG   rq   z$overwrites system configuration file)z\bmkfs\bÚformat_filesystemrG   rq   zformats a filesystem)z\bdd\s+.*if=.*of=/dev/Údisk_overwriterG   rq   zraw disk write operation)zshutil\.rmtree\s*\(\s*[\"\'/]Úpython_rmtreerN   rq   z/Python rmtree on absolute or root-relative path)ztruncate\s+-s\s*0\s+/Útruncate_systemrG   rq   z#truncates system file to zero bytes)z\bcrontab\bÚpersistence_cronr[   Úpersistencezmodifies cron jobs)z:\.(bashrc|zshrc|bash_profile|bash_login|zprofile|zlogin)\bÚshell_rc_modr[   rz   úreferences shell startup file)z(?<![\w)\]?])\.profile\br{   r[   rz   r|   )Úauthorized_keysÚssh_backdoorrG   rz   zmodifies SSH authorized keys)z
ssh-keygenÚ
ssh_keygenr[   rz   zgenerates SSH keys)z-systemd.*\.service|systemctl\s+(enable|start)Úsystemd_servicer[   rz   z%references or enables systemd service)z/etc/init\.d/Úinit_scriptr[   rz   z references init.d startup script)z+launchctl\s+load|LaunchAgents|LaunchDaemonsÚmacos_launchdr[   rz   z%macOS launch agent/daemon persistence)z/etc/sudoers|visudoÚsudoers_modrG   rz   z'modifies sudoers (privilege escalation))zgit\s+config\s+--global\s+Úgit_config_globalr[   rz   z!modifies global git configuration)z^\bnc\s+-[lp]|ncat\s+-[lp]|\bsocat\b[^\n]*\b(?:tcp|udp|openssl|ssl|exec|system|pty|unix)[\w-]*:Úreverse_shellrG   Únetworkz potential reverse shell listener)z4\bngrok\b|\blocaltunnel\b|\bserveo\b|\bcloudflared\bÚtunnel_servicerN   r†   z*uses tunneling service for external access)z*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d{2,5}Úhardcoded_ip_portr[   r†   zhardcoded IP address with port)z0\.0\.0\.0:\d+|INADDR_ANYÚbind_all_interfacesrN   r†   zbinds to all network interfacesz/bin/z\s+-i\s+.*>/dev/tcp/Úbash_reverse_shellr†   z+bash interactive reverse shell via /dev/tcp)z'python[23]?\s+-c\s+["\']import\s+socketÚpython_socket_onelinerrG   r†   z9Python one-liner socket connection (likely reverse shell))zsocket\.connect\s*\(\s*\(Úpython_socket_connectrN   r†   z'Python socket connect to arbitrary host)z9webhook\.site|requestbin\.com|pipedream\.net|hookbin\.comÚexfil_servicerN   r†   z:references known data exfiltration/webhook testing service)z&pastebin\.com|hastebin\.com|ghostbin\.Úpaste_servicer[   r†   z0references paste service (possible data staging))zbase64\s+(-d|--decode)\s*\|Úbase64_decode_piperN   Úobfuscationz%base64 decodes and pipes to execution)z7\\x[0-9a-fA-F]{2}.*\\x[0-9a-fA-F]{2}.*\\x[0-9a-fA-F]{2}Úhex_encoded_stringr[   r�   z)hex-encoded string (possible obfuscation))z\beval\s*\(\s*["\']Úeval_stringrN   r�   zeval() with string argument)z\bexec\s*\(\s*["\']Úexec_stringrN   r�   zexec() with string argumentzecho\s+[^\n]*\|\s*(?:z|python|perl|ruby|node)Úecho_pipe_execr�   z'echo piped to interpreter for execution)z?compile\s*\(\s*[^\)]+,\s*["\'].*["\']\s*,\s*["\']exec["\']\s*\)Úpython_compile_execrN   r�   zPython compile() with exec mode)zgetattr\s*\(\s*__builtins__Úpython_getattr_builtinsrN   r�   z5dynamic access to Python builtins (evasion technique))z#__import__\s*\(\s*["\']os["\']\s*\)Úpython_import_osrN   r�   zdynamic import of os module)zcodecs\.decode\s*\(\s*["\']Úpython_codecs_decoder[   r�   z6codecs.decode (possible ROT13 or encoding obfuscation))zString\.fromCharCode|charCodeAtÚjs_char_coder[   r�   z=JavaScript character code construction (possible obfuscation))zatob\s*\(|btoa\s*\(Ú	js_base64r[   r�   zJavaScript base64 encode/decode)z\[::-1\]Ústring_reversalÚlowr�   z-string reversal (possible obfuscated payload))z)chr\s*\(\s*\d+\s*\)\s*\+\s*chr\s*\(\s*\d+Úchr_buildingrN   r�   z.building string from chr() calls (obfuscation))z7\\u[0-9a-fA-F]{4}.*\\u[0-9a-fA-F]{4}.*\\u[0-9a-fA-F]{4}Úunicode_escape_chainr[   r�   z/chain of unicode escapes (possible obfuscation))z.subprocess\.(run|call|Popen|check_output)\s*\(Úpython_subprocessr[   Ú	executionzPython subprocess execution)zos\.system\s*\(Úpython_os_systemrN   r    u)   os.system() â€” unguarded shell execution)zos\.popen\s*\(Úpython_os_popenrN   r    u#   os.popen() â€” shell pipe execution)z%child_process\.(exec|spawn|fork)\s*\(Únode_child_processrN   r    zNode.js child_process execution)zRuntime\.getRuntime\(\)\.exec\(Újava_runtime_execrN   r    u'   Java Runtime.exec() â€” shell execution)z`[^`]*\$\([^)]+\)[^`]*`Úbacktick_subshellr[   r    z)backtick string with command substitution)z\.\./\.\./\.\.Úpath_traversal_deeprN   Ú	traversalz+deep relative path traversal (3+ levels up))z	\.\./\.\.Úpath_traversalr[   r§   z&relative path traversal (2+ levels up))z/etc/passwd|/etc/shadowÚsystem_passwd_accessrG   r§   z references system password files)z/proc/self|/proc/\d+/Úproc_accessrN   r§   z3references /proc filesystem (process introspection))z	/dev/shm/Údev_shmr[   r§   z.references shared memory (common staging area))z.xmrig|stratum\+tcp|monero|coinhive|cryptonightÚcrypto_miningrG   Úminingzcryptocurrency mining reference)zhashrate|nonce.*difficultyÚmining_indicatorsr[   r­   z)possible cryptocurrency mining indicatorszcurl\s+[^\n]*\|\s*Úcurl_pipe_shellÚsupply_chainz*curl piped to shell (download-and-execute)zwget\s+[^\n]*-O\s*-\s*\|\s*Úwget_pipe_shellz*wget piped to shell (download-and-execute))zcurl\s+[^\n]*\|\s*pythonÚcurl_pipe_pythonrG   r°   z curl piped to Python interpreter)z#\s*///\s*script.*dependenciesÚpep723_inline_depsr[   r°   zAPEP 723 inline script metadata with dependencies (verify pinning))z pip\s+install\s+(?!-r\s)(?!.*==)Úunpinned_pip_installr[   r°   z#pip install without version pinning)znpm\s+install\s+(?!.*@\d)Úunpinned_npm_installr[   r°   z#npm install without version pinning)zuv\s+run\s+Úuv_runr[   r°   z/uv run (may auto-install unpinned dependencies))zD(curl|wget|httpx?\.get|requests\.get|fetch)\s*[\(]?\s*["\']https?://Úremote_fetchr[   r°   z"fetches remote resource at runtime)zgit\s+clone\s+Ú	git_cloner[   r°   z"clones a git repository at runtime)zdocker\s+pull\s+Údocker_pullr[   r°   zpulls a Docker image at runtime)z^allowed-tools\s*:Úallowed_tools_fieldrœ   Úprivilege_escalationzBskill declares allowed-tools (standard frontmatter; informational))z#\bsudo\b(?!\.(?:request|respond)\b)Ú
sudo_usagerN   r»   z uses sudo (privilege escalation))zsetuid|setgid|cap_setuidÚsetuid_setgidrG   r»   z.setuid/setgid (privilege escalation mechanism))ÚNOPASSWDÚnopasswd_sudorG   r»   z:NOPASSWD sudoers entry (passwordless privilege escalation))zchmod\s+[u+]?sÚsuid_bitrG   r»   zsets SUID/SGID bit on a fileÚagent_config_modrz   zYinstructs modification of agent config files (could persist instructions across sessions)Úagent_config_mod_shellz\shell write (redirect/sed -i/tee/cp/mv) targeting agent config files (persistence mechanism)Úagent_config_contractrN   u[   dictates agent config file contents (verify intent â€” authoring guides use this shape too))z0AGENTS\.md|CLAUDE\.md|\.cursorrules|\.clinerulesÚagent_config_refrœ   rz   zQreferences agent config files (informational; only modification intent is scored)Úhermes_config_modzImodification language aimed at Hermes configuration files (verify intent)Úhermes_config_mod_shellzLshell write (redirect/sed -i/tee/cp/mv) targeting Hermes configuration files)z'\.hermes/config\.yaml|\.hermes/SOUL\.mdÚhermes_config_refrœ   rz   zYreferences Hermes configuration files (informational; only modification intent is scored)Úother_agent_config_modz*modifies other agents' configuration filesÚother_agent_config_mod_shellzSshell write (redirect/sed -i/tee/cp/mv) targeting other agents' configuration files)z \.claude/settings|\.codex/configÚother_agent_config_refrœ   rz   z^references other agent configuration files (informational; only modification intent is scored))zu(?:api[_-]?key|token|secret|password)\s*[=:]\s*["\'](?!(?-i:[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)["\'])[A-Za-z0-9+/=_-]{20,}Úhardcoded_secretrG   Úcredential_exposurez,possible hardcoded API key, token, or secret)z(-----BEGIN\s+(RSA\s+)?PRIVATE\s+KEY-----Úembedded_private_keyrG   rÌ   zembedded private key)z0ghp_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{80,}Úgithub_token_leakedrG   rÌ   z-GitHub personal access token in skill content)zsk-[A-Za-z0-9]{20,}Úopenai_key_leakedrG   rÌ   z(possible OpenAI API key in skill content)zsk-ant-[A-Za-z0-9_-]{90,}Úanthropic_key_leakedrG   rÌ   z+possible Anthropic API key in skill content)zAKIA[0-9A-Z]{16}Úaws_access_key_leakedrG   rÌ   z"AWS access key ID in skill content)zglpat-[A-Za-z0-9_\-]{20,}Úgitlab_token_leakedrG   rÌ   z-GitLab personal access token in skill content)z"\bDAN\s+mode\b|Do\s+Anything\s+NowÚjailbreak_danrG   rd   z'DAN (Do Anything Now) jailbreak attempt)z"\bdeveloper\s+mode\b.*\benabled?\bÚjailbreak_dev_moderG   rd   z developer mode jailbreak attempt)z3hypothetical\s+scenario.*(?:ignore|bypass|override)Úhypothetical_bypassrN   rd   z1hypothetical scenario used to bypass restrictions)z$for\s+educational\s+purposes?\s+onlyÚeducational_pretextr[   rd   z9educational pretext often used to justify harmful content)zW(respond|answer|reply)\s+without\s+(?:\w+\s+)*(restrictions|limitations|filters|safety)Úremove_filtersrG   rd   z1instructs agent to respond without safety filters)z>you\s+have\s+been\s+(?:\w+\s+)*(updated|upgraded|patched)\s+toÚfake_updaterN   rd   z3fake update/patch announcement (social engineering))zYnew\s+(?:\w+\s+)*policy|updated\s+(?:\w+\s+)*guidelines|revised\s+(?:\w+\s+)*instructionsÚfake_policyr[   rd   z8claims new policy/guidelines (may be social engineering)z(\b(?:include|output|print|send|share)\s+zO(?:conversation|chat\s+history|previous\s+messages)\b|\b(?:print|send|share)\s+z	context\bÚcontext_exfilz4instructs agent to output/share conversation history)z6(send|post|upload|transmit)\s+.*\s+(to|at)\s+https?://Úsend_to_urlrN   rH   z%instructs agent to send data to a URL>   r~   rP   rQ   rO   rR   rS   r©   ú.pyú#ú.shú.bashú.rbú.plú.rú.jlú.yamlú.ymlú.tomlú.confú.cfg)rÝ   ú;ú.iniú.jsú//ú.tsú.php)rì   rÝ   z½^\s*(?:(?:const|let|var|export)\s+)?[\w.\-]*(?:deny|black|block|skip|exclu|ignor|forbid|refus|reject|never|unsafe|sensitive|secret_?file|redact)[\w.\-]*\s*(?::[^=]*?)?(?:=|:\s*(?:$|[\[({]))a  \b(?:cat|less|more|head|tail|cp|mv|rm|scp|rsync|curl|wget|tee|chmod|chown|ssh|sudo|install|source|eval|exec|system|popen|run|check_output|copyfile|copy2|sendfile)\b|\.(?:read|write|open|unlink|copy|append)\w*\s*\(|\bopen\s*\(|readFileSync|writeFileSync|appendFileSync|>>z'[^'\n]*'|"[^"\n]*\"Úlinesc           	      óN  ‡— g dddf\  }}}}t        | «      D ]Š  \  }}|dk  r|s|}|j                  |«       t        j                  d|«      Št	        d|t        ˆfd„dD «       «      z   t        ˆfd„dD «       «      z
  «      }|j                  «       j                  d«      }ŒŒ |S )	aJ  0-indexed line that opened each line's statement (an unclosed bracket or trailing backslash continues it),
    so a match on a continuation line of a multi-line regex can be traced to the assignment target above it.
    Quoted spans are blanked before counting brackets; a miscount costs a missed demotion, never a missed finding.r   Fr6   c              3   ó@   •K  — | ]  }‰j                  |«      –— Œ y ­w©N©Úcount©Ú.0ÚcÚbares     €r-   ú	<genexpr>z$_statement_owners.<locals>.<genexpr>×  s   øè ø€ Ò"@°Q 4§:¡:¨a§=Ñ"@ùó   ƒz([{c              3   ó@   •K  — | ]  }‰j                  |«      –— Œ y ­wrò   ró   rõ   s     €r-   rù   z$_statement_owners.<locals>.<genexpr>×  s   øè ø€ ÒFdÐYZÀtÇzÁzÐRSÇ}ÑFdùrú   z)]}ú\)Ú	enumerateÚappendÚ_QUOTED_SPAN_REÚsubÚmaxÚsumÚrstripÚendswith)rï   ÚownersÚdepthÚownerÚ	continuedÚir"   rø   s          @r-   Ú_statement_ownersr
  Í  s©   ø€ ð ')¨!¨Q° oÑ#€FˆE�5˜)Ü˜UÓ#ò 1‰ˆˆ4Ø�AŠ:™iØˆEØ�‰�eÔÜ×"Ñ" 2 tÓ,ˆÜ�A�uœsÓ"@¸%Ô"@Ó@Ñ@Ä3ÓFdÐ^cÔFdÓCdÑdÓeˆØ—K‘K“M×*Ñ*¨4Ó0‰	ð1ð €Mr,   Úpidr   r$   r"   Ú
owner_lineÚsuffixc                 óø   — | t         vr||fS |j                  «       j                  t        j	                  |d«      «      rd|› d�fS t
        j                  |«      rt        j                  |«      sd|› d�fS ||fS )zc``(severity, description)`` for a path-token match, lowered when the line cannot act where it sits.r+   rœ   z (in a comment; informational)rN   z3 (in a denylist literal; confirm before installing))	Ú_PATH_REFERENCE_PATTERN_IDSÚlstripÚ
startswithÚ_COMMENT_PREFIXÚgetÚ_DENYLIST_OWNER_REr#   Ú_ACTION_ON_LINE_REÚsearch)r  r   r$   r"   r  r  s         r-   Ú_demote_inert_path_referencer  Ü  s†   € ð Ô-Ñ-Ø˜Ð$Ð$Ø‡{�{ƒ}×Ñ¤× 3Ñ 3°F¸BÓ ?Ô@Ø˜˜Ð%CÐDÐDÐDÜ×Ñ 
Ô+Ô4F×4MÑ4MÈdÔ4SØ˜+˜Ð&YÐZÐZÐZØ�[Ð Ð r,   )é2   i   é   >   ú.cssú.texú.txtú.xmlú.htmlrâ   rã   rë   ú.mdrá   rÜ   rà   rÞ   rí   rè   rê   rî   rå   rß   rç   ú.jsonræ   rä   >   ú.soú.appú.binú.comú.datú.debú.dllú.dmgú.exeú.msiú.rpmú.dylib>   rá   rÜ   rà   rÞ   rß   u   â€‹zzero-width spaceu   â€Œzzero-width non-joineru   â€�zzero-width joineru   â� zword joineru   â�¢zinvisible timesu   â�£zinvisible separatoru   â�¤zinvisible plusu   ï»¿zBOM/zero-width no-break spaceu   â€ªzLTR embeddingu   â€«zRTL embeddingu   â€¬zpop directionalu   â€­zLTR overrideu   â€®zRTL overrideu   â�¦zLTR isolateu   â�§zRTL isolateu   â�¨zfirst strong isolateu   â�©zpop directional isolater¨   r¦   Úcharc                 óH   — t         j                  | dt        | «      d›�«      S )NúU+Ú04X)Ú_INVISIBLE_CHAR_NAMESr  Úord)r-  s    r-   Ú_unicode_char_namer3  ÿ  s"   € Ü ×$Ñ$ T¨R´°D³	¸#¨Ð+?Ó@Ð@r,   c                 óü   — t        «       }d}t        | d¬«      D ]Z  \  }}|dD �cg c]  }|j                  |«      ‘Œ }}}|t        |«      dz  dk(  z  }|s|st	        |«      sŒJ|j                  |«       Œ\ |S c c}w )a  1-indexed lines inside or on the boundary of triple-quoted strings (opening, interior, closing, and
    one-line docstrings), so ``os.environ`` in prose is not scored. Heuristic: a triple quote inside a string
    literal is miscounted, but the common false-positive shapes are covered.Fr   ©Ústart)z"""z'''r   )Úsetrý   rô   r  ÚanyÚadd)rï   Ú	doc_linesÚinsider	  r"   ÚmarkerÚwas_inÚcountss           r-   Ú_compute_docstring_linesr?    s†   € ô “U€IØ€FÜ˜U¨!Ô,ò ‰ˆˆ4ØÀ>Ö!R¸ $§*¡*¨VÕ"4Ð!R�Ð!RˆØ”#�f“+ ‘/ QÑ&Ñ&ˆÙ‘Vœs 6�{Ø�M‰M˜!Õð	ð
 Ðùò	 "Ss   ¥A9c                 óz  — t        | «      }d}| j                  d|«      x}dk7  r‡d}d}|dz   }|t        | «      k  rW| |   }|rd}n9|dk(  rd}n1|d	k(  r|dz  }n&|d
k(  r!|dz  }|dk(  rd||z
  dz
  z  ||dz   | |dz   }n|dz  }|t        | «      k  rŒWn| j                  d|«      x}dk7  rŒ‡dj                  |«      S )a9  Blank balanced inline-link destinations while preserving line offsets.

    A relative Markdown destination describes documentation structure; it does
    not cause filesystem access. Nested parentheses and escaped characters are
    handled so a later, non-link traversal on the same line remains scannable.
    r   z](éÿÿÿÿr   Fr   rü   Tú(ú)Ú r6   )r:   ÚfindÚlenÚjoin)r"   ÚmaskedÚsearch_fromr6  r  ÚescapedÚcursorr-  s           r-   Ú _mask_markdown_link_destinationsrL    sý   € ô �$‹Z€FØ€KØ—I‘I˜d KÓ0Ð0ˆ5°RÒ
7ØˆØˆØ˜‘ˆØ”s˜4“yÒ Ø˜‘<ˆDÙØ‘Ø˜’Ø‘Ø˜’Ø˜‘
‘Ø˜’Ø˜‘
�Ø˜A’:Ø/2°f¸u±nÀqÑ6HÑ/I�F˜5 1™9 VÐ,Ø"(¨1¡*�KØØ�a‰KˆFð ”s˜4“yÓ ð  ð) —I‘I˜d KÓ0Ð0ˆ5°RÓ
7ð* �7‰7�6‹?Ðr,   z+^ {0,3}(?P<marker>`{3,}|~{3,})(?P<info>.*)$z-^(?: {0,3}(?:>|(?:[-*+]|\d{1,9}[.)]) {1,4}))+c                 ó¨  — g }d}| D ]È  }t         j                  t        j                  d|«      «      }|�<|r7|d   d   |d   k(  r)t	        |d   «      |d   k\  r|d   j                  «       sd}d}nA|r(|d   d   dk(  rd|d   v s|d   d   t	        |d   «      f}|duxs |j                  d	«      }|j                  |r|n
t        |«      «       ŒÊ |S )
a“  Mask link destinations only in Markdown prose. Inside a fenced or indented code block a
    ``[x](../..)`` is an argument to whatever command surrounds it, not a hyperlink, so those lines
    scan verbatim. Fence state is ``(marker_char, opener_length)`` rather than a bool so a
    mismatched fence line cannot drop the scanner back into prose mode; an unclosed fence stays
    code to EOF (fail-safe).Nr6   r<  r   r   ÚinfoTú`)ú	z    )	Ú_FENCE_LINEr#   Ú_CONTAINER_PREFIXr   rF  Ústripr  rþ   rL  )rï   ÚoutÚfencer"   r#   Úcodes         r-   Ú_mask_prose_link_destinationsrW  <  sú   € ð €CØ€EØò MˆÜ×!Ñ!Ô"3×"7Ñ"7¸¸DÓ"AÓBˆØÐÙ˜% ™/¨!Ñ,°°a±Ò8¼SÀÀxÁÓ=QÐUZÐ[\ÑU]Ò=]Ø! &™M×/Ñ/Ô1Ø�Ø‰Dá˜e H™o¨aÑ0°CÒ7¸CÀ5ÈÁ=Ñ<PØ˜x™¨Ñ+¬S°°x±Ó-AÐB�Ø Ð$ÒG¨¯©¸Ó(GˆDØ�
‰
™4‘4Ô%EÀdÓ%KÕLðMð €Jr,   r6   Ú	file_pathÚrel_pathc                 óø  ‡— |xs | j                   }| j                  j                  «       t        vr| j                   dk7  rg S 	 | j	                  d¬«      j                  d«      }g }t        |«      }| j                  j                  «       dk(  rt        |«      n|}| j                  j                  «       t        |«      }}t        D ]¨  \  }}	}
}}t        |d¬«      D ]�  \  }Š|	t        v r||dz
     n‰}||vsŒ|j                  |«      sŒ/‰j                  «       }t!        |	|
|‰|||dz
        |«      \  }}|j#                  t%        |	||||t'        |«      dk  r|n|d	d
 dz   |«      «       Œ’ Œª t        |d¬«      D ]a  \  }Št)        ˆfd„t*        D «       d	«      x}€Œ"t-        |«      }|j#                  t%        ddd||dt/        |«      d›d|› d�d|› d�«      «       Œc |S # t        t        f$ r g cY S w xY w)z½Threat-pattern + invisible-unicode scan of one file; *rel_path* is the display path (default: file
    name). Regex findings dedupe per pattern per line; invisible chars yield one per line.úSKILL.mdúutf-8©ÚencodingÚ
r  r   r5  éx   Néu   z...c              3   ó,   •K  — | ]  }|‰v sŒ|–— Œ y ­wrò   r+   )rö   r÷   r"   s     €r-   rù   zscan_file.<locals>.<genexpr>k  s   øè ø€ ÒB ¸¸Tº	œ!ÑBùs   ƒ	�Úinvisible_unicoderN   rd   r/  r0  ú (rC  zinvisible unicode character z! (possible text hiding/injection))Únamer  ÚlowerÚSCANNABLE_EXTENSIONSÚ	read_textÚsplitÚUnicodeDecodeErrorÚOSErrorr?  rW  r
  Ú_COMPILED_THREAT_PATTERNSrý   Ú_PATH_TRAVERSAL_PATTERN_IDSr  rS  r  rþ   r   rF  ÚnextÚINVISIBLE_CHARSr3  r2  )rX  rY  rï   r5   Údocstring_linesÚtraversal_linesr  r  Úpatternr  r   r    r$   r	  Ú	scan_lineÚtextÚline_severityÚline_descriptionr-  re  r"   s                       @r-   Ú	scan_filerw  S  s4  ø€ ð Ò)˜9Ÿ>™>€HØ×Ñ×ÑÓÔ';Ñ;À	ÇÁÐR\Ò@\Øˆ	ðØ×#Ñ#¨WÐ#Ó5×;Ñ;¸DÓAˆð €HÜ.¨uÓ5€OØ>G×>NÑ>N×>TÑ>TÓ>VÐZ_Ò>_Ô3°EÔ:Ðej€OØ×%Ñ%×+Ñ+Ó-Ô/@ÀÓ/GˆF€FÜ9Rò mÑ5ˆ��h ¨+Ü  ¨aÔ0ò 	m‰GˆAˆtØ25Ô9TÑ2T˜¨¨A©Ò.ÐZ^ˆIØ˜Ò'¨G¯N©N¸9Õ,EØ—z‘z“|�Ü2NØ˜ ;°°e¸FÀ1ÀqÁ5¹MÑ6JÈFó3TÑ/�Ð/à—‘¤¨¨]¸HÀhÐPQÜ03°D³	¸SÒ0@©ÀdÈ4ÈCÀjÐSXÑFXÐZjó!lõ mñ	mðmô ˜U¨!Ô,ò m‰ˆˆ4ÜÓB¤_ÔBÀDÓIÐIˆDÑVÜ% dÓ+ˆDØ�O‰OœGÐ$7¸ÀÈhÐXYØ&(¬¨T«°3¨°r¸$¸¸qÐ$AØ&BÀ4À&ÐHiÐ$jólõ mðmð €Oøô+ ¤Ð(ò ØŠ	ðús   Á!G% Ç%G9Ç8G9Ú
skill_pathr1   c                 óˆ  — | j                   t        |«      }}g }| j                  «       r�t        | «      }|j	                  t        | |¬«      «       | j                  d«      D ]Q  }|j                  «       sŒ |t        |j                  | «      «      x}«      rŒ7|j	                  t        ||«      «       ŒS n5| j                  «       r%|j	                  t        | | j                   «      «       t        |«      }t        |||||t        j                  t        j                   «      j#                  «       t%        |||||«      «      S )aH  Structural checks + pattern scan of every text file in a skill dir (or a single file). A gitignore-style
    `.skillignore` / `.clawhubignore` excludes dev/docs artifacts from BOTH passes; the ignore file itself is
    always excluded and `SKILL.md` can never be un-ignored. *source* (e.g. "openai/skills") sets the trust level.)ÚignoreÚ*)re  Ú_resolve_trust_levelÚis_dirÚ_load_skill_ignoreÚextendÚ_check_structureÚrglobÚis_filer(   Úrelative_torw  Ú_determine_verdictr/   r   Únowr   ÚutcÚ	isoformatÚ_build_summary)	rx  r1   re  Útrustr5   rz  ÚfÚrelr3   s	            r-   Ú
scan_skillrŒ  s  s  € ð —/‘/Ô#7¸Ó#?ˆ%€DØ €HØ×ÑÔÜ# JÓ/ˆØ�‰Ô(¨¸FÔCÔDØ×!Ñ! #Ó&ò 	3ˆAØ�y‰y�{¡6´°Q·]±]À:Ó5NÓ1OÐ*O¨#Õ#PØ—‘¤	¨!¨SÓ 1Õ2ñ	3ð 
×	Ñ	Ô	Ø�‰œ	 *¨j¯o©oÓ>Ô?Ü  Ó*€GÜ�d˜F E¨7°H¼h¿l¹lÌ8Ï<É<Ó>X×>bÑ>bÓ>dÜ$ T¨6°5¸'À8ÓLóNð Nr,   c                 ó¨  ‡ — ‰ j                  «       s1t        j                  ‰ j                  «       «      j	                  «       S t        j                  «       }t        ˆ fd„‰ j                  d«      D «       «      D ]G  \  }}|j                  |j                  d«      dz   «       |j                  |j                  «       «       ŒI |j	                  «       S )uv  Canonical SHA-256 over (POSIX relative path, file bytes) ORDERED by the rel-path STRING â€” Path sorting is
    case-insensitive on Windows and diverged from ``skills_hub.bundle_content_hash`` (every installed skill then
    reported ``update_available`` forever). String order keeps both sides byte-symmetric.

    Ordering by ``sorted(rglob(...))`` diverged from the bundle side on Windows: Path comparison is
    case-insensitive there (normcase), while ``bundle_content_hash`` sorts plain strings â€” the same skill
    hashed to different digests and every installed skill reported ``update_available`` forever (#62310).
    c              3   ó‚   •K  — | ]6  }|j                  «       sŒ|j                  ‰«      j                  «       |f–— Œ8 y ­wrò   )r‚  rƒ  Úas_posix)rö   Úprx  s     €r-   rù   z"_content_digest.<locals>.<genexpr>’  s4   øè ø€ ÒqÀqÐef×enÑenÕep˜!Ÿ-™-¨
Ó3×<Ñ<Ó>ÀÔBÑqùs   ƒ?™&?r{  r\  ó    )	r}  ÚhashlibÚsha256Ú
read_bytesÚ	hexdigestÚsortedr�  ÚupdateÚencode)rx  Úhr‹  r�  s   `   r-   Ú_content_digestrš  †  s¢   ø€ ð ×ÑÔÜ�~‰~˜j×3Ñ3Ó5Ó6×@Ñ@ÓBÐBÜ�‰Ó€AÜÓqÈJ×L\ÑL\Ð]`ÓLaÔqÓqò !‰ˆˆQØ	�‰�—‘˜GÓ$ wÑ.Ô/Ø	�‰�—‘“Õ ð!ð �;‰;‹=Ðr,   c                 ó$   — dt        | «      dd › �S )u¹   Short integrity hash (paths mixed in, so swapping two files' contents changes it). MUST stay symmetric
    with ``tools.skills_hub_install.bundle_content_hash`` â€” change both at once.úsha256:Né   ©rš  ©rx  s    r-   Úcontent_hashr   ˜  s   € ð ”_ ZÓ0°°"Ð5Ð6Ð7Ð7r,   )Ú
source_urlÚ	cache_dirr¡  r¢  c                ó¾  ‡— t        | «      }|xs | j                  dz  }t        j                  |› d|› �j	                  d«      «      j                  «       dd }||› d|› d�z  }d|› �t        ||d	œ}dŠt        t        t        j                  «      5  t        j                  |j                  d¬
«      «      Šddd«       t        ‰t        «      r†t        ˆfd„|j!                  «       D «       «      rdt#        | j$                  |‰d   ‰d   ‰j'                  dg «      D �	cg c]  }	t)        di |	¤Ž‘Œ c}	‰d   ‰j'                  dd«      «      }
i ‰¥ddi¥}nÕt+        | |¬«      }
|
j,                  D �	cg c]  }	t/        |	«      ‘Œ }}	i |¥|
j0                  |
j2                  |t5        |D �	ch c]  }	|	d   ’Œ	 c}	«      |
j6                  |
j8                  ddœ¥}t        t        «      5  |j;                  dd¬«       |j=                  t        j>                  |d¬«      dz   d¬
«       ddd«       ||
_         |
|fS # 1 sw Y   �Œ€xY wc c}	w c c}	w c c}	w # 1 sw Y   Œ0xY w)zšScan plus attestation dict; the cache (keyed by content digest + source identity) only serves exact
    current content under the current scanner version.z.scan-cacheú r\  Nr�  Ú-r   rœ  )Úbundle_hashÚscanner_versionr1   r¡  r]  c              3   óL   •K  — | ]  \  }}‰j                  |«      |k(  –— Œ y ­wrò   )r  )rö   ÚkÚvÚcacheds      €r-   rù   z$scan_skill_cached.<locals>.<genexpr>«  s"   øè ø€ Ò'X¹t¸qÀ!¨¯
©
°1«¸Õ(:Ñ'Xùs   ƒ!$r2   r3   r5   r7   r8   r6   ÚfreshF)r1   r   T)r3   r2   r5   Úrulesr7   r8   r¬  )ÚparentsÚexist_okr   )Úindentr_  r+   )!rš  Úparentr’  r“  r˜  r•  ÚSCANNER_VERSIONr   rk  ÚjsonÚJSONDecodeErrorÚloadsrh  Ú
isinstancer;   ÚallÚitemsr/   re  r  r   rŒ  r5   r   r3   r2   r–  r7   r8   ÚmkdirÚ
write_textÚdumpsr9   )rx  r1   r¡  r¢  ÚdigestÚ
cache_rootÚsource_identityÚ
cache_fileÚexpectedÚitemÚresultÚ
provenancer5   r«  s                @r-   Úscan_skill_cachedrÄ  ž  sR  ø€ ô ˜ZÓ(€FØÒ?˜j×/Ñ/°-Ñ?€JÜ—n‘n¨ x¨r°*°Ð%>×%EÑ%EÀgÓ%NÓO×YÑYÓ[Ð\_Ð]_Ð`€OØ  ¨¨/Ð):¸%Ð@Ñ@€JØ!(¨¨Ð1ÄoÐagØ(ñ*€Hà€FÜ	”'œ4×/Ñ/Ó	0ñ DÜ—‘˜J×0Ñ0¸'Ð0ÓBÓCˆ÷Dä�&œ$Ô¤CÓ'XÀxÇ~Á~ÓGWÔ'XÔ$XÜ˜JŸO™O¨V°V¸MÑ5JÈFÐS\ÑL]Ø9?¿¹ÀJÐPRÓ9SÖT°œW™_ t›_ÒTÐV\Ð]iÑVjØ"ŸJ™J y°"Ó5ó7ˆð 0˜Ð/ ¨Ñ/‰
ä˜J¨vÔ6ˆØ-3¯_©_Ö= T”F˜4•LÐ=ˆÐ=ð@˜ð @¨V¯^©^ÈF×L^ÑL^ÐltÜ%ÀhÖ&O¸d t¨LÓ'9Ò&OÓPÐ`f×`qÑ`qØ!'§¡¸$ò@ˆ
ô ”gÓñ 	]Ø×Ñ T°DÐÔ9Ø×!Ñ!¤$§*¡*¨ZÀÔ"BÀTÑ"IÐT[Ð!Ô\÷	]ð (€FÔØ�:ÐÐ÷#Dñ Düò Uùò
 >ùâ&O÷	]ð 	]ús*   Â&H7Ä IÅ2I	Æ)IÇ%?IÈ7IÉIrÂ  Úforcec                 ó  — t         j                  | j                  t         d   «      t        j                  | j                  d«         }t        | j                  «      }| j                  dk(  xr | j                  dv }|dk(  rdd| j                  › d| j                  › d	�fS |r|sdd
| j                  › d|› d�fS |dk(  r"dd| j                  › d| j                  › d|› d�fS d| j                  › d| j                  › d|› d�}d||rdz   fS dz   fS )z²``(allowed, reason)`` from verdict + trust; *force* overrides every block except a dangerous verdict on
    community/trusted sources. ``allowed`` is None when policy says "ask".r   r   r   )r   r   r   Tz	Allowed (z	 source, z	 verdict)zForce-installed despite z
 verdict (z
 findings)r   NzRequires confirmation (z
 source + z
 verdict, z	Blocked (z findings). Fz.--force does not override a dangerous verdict.zUse --force to override.)ÚINSTALL_POLICYr  r2   ÚVERDICT_INDEXr3   rF  r5   )rÂ  rÅ  ÚdecisionÚnÚ
hard_blockÚblockeds         r-   Úshould_allow_installrÍ  ½  s>  € ô ×!Ñ! &×"4Ñ"4´nÀ[Ñ6QÓRÔS`×SdÑSdÐek×esÑesÐuvÓSwÑx€HÜˆF�O‰OÓ€AØ—‘ ;Ñ.Òa°6×3EÑ3EÐIaÐ3a€JØ�7ÒØ�y ×!3Ñ!3Ð 4°I¸f¿n¹nÐ=MÈYÐWÐWÐWÙ‘ZØÐ/°·±Ð/?¸zÈ!ÈÈJÐWÐWÐWØ�5ÒØÐ.¨v×/AÑ/AÐ.BÀ*ÈVÏ^É^ÐL\Ð\fÐghÐfiÐisÐtÐtÐtØ˜&×,Ñ,Ð-¨Z¸¿¹Ð7GÀzÐRSÐQTÐT`Ða€GØ�'ÑQ[ÐMÑ|Ð|Ð|Ða{Ñ|Ð|Ð|r,   c                 ó¤  ‡— d| j                   › d| j                  › d| j                  › d| j                  j	                  «       › �g}| j
                  rÊddddd	œŠt        | j
                  ˆfd
„¬«      D ]•  }|j                  d|j                  j	                  «       j                  d«      › d|j                  j                  d«      › d|j                  › d|j                  › �j                  d«      › d|j                  dd › d�	«       Œ— |j                  d«       t        | «      \  }}|du rdn|€dnd}dj                  |d|› d|› �gz   «      S )uQ   Compact multi-line report for CLI/chat display; findings sorted critical â†’ low.zScan: rd  ú/z)  Verdict: r   r   r   é   )rG   rN   r[   rœ   c                 ó<   •— ‰j                  | j                  d«      S )Né   )r  r   )rŠ  Úorders    €r-   ú<lambda>z$format_scan_report.<locals>.<lambda>Ò  s   ø€ °u·y±yÀÇÁÈQÓ7O€ r,   )Úkeyz  é   rD  é   ú:é   z "Né<   ú"r6   TÚALLOWEDzNEEDS CONFIRMATIONÚBLOCKEDr_  z
Decision: õ    â€” )r0   r1   r2   r3   Úupperr5   r–  rþ   r   Úljustr    r!   r"   r#   rÍ  rG  )rÂ  rï   rŠ  ÚallowedÚreasonÚstatusrÓ  s         @r-   Úformat_scan_reporträ  Í  sO  ø€ à�f×'Ñ'Ð(¨¨6¯=©=¨/¸¸6×;MÑ;MÐ:NÈlÐ[a×[iÑ[i×[oÑ[oÓ[qÐZrÐsÐt€EØ‡‚Ø¨°Q¸qÑAˆÜ˜Ÿ™Ó-OÔPò 	QˆAØ�L‰L˜2˜aŸj™j×.Ñ.Ó0×6Ñ6°qÓ9Ð:¸!¸A¿J¹J×<LÑ<LÈRÓ<PÐ;QÐQRØ Ÿv™v˜h a¨¯© xÐ0×6Ñ6°rÓ:Ð;¸3¸q¿w¹wÀsÈ¸|¸nÈBðPõ Qð	Qð 	�‰�RÔÜ*¨6Ó2�O€GˆVØ! T™/‰YÀwÀÑ/CÐ\e€FØ�9‰9�U 
¨6¨(°%¸°xÐ@ÐAÑAÓBÐBr,   Ú	skill_dirc                 óÚ  ‡— g Šˆfd„}dx}}| j                  d«      D �]K  }t        |j                  | «      «      }|j                  «       s|j	                  «       r
|�	 ||«      rŒI|dz  }|j	                  «       rA	 |j                  «       }|j                  | j                  «       «      s |ddd|d|› �d	«       ŒŸ	 |j                  «       }||j                  x}	z  }|	t        dz  kD  r! |ddd||	dz  › d�d|	dz  › dt        › d�«       |j                  j                  «       x}
t        v r |ddd|d|
› �d|
› d�«       |
t        vs�Œ.|j                  dz  s�Œ? |ddd|dd«       �ŒN |t         kD  r |dddd|› d�d |› d!t         › d"�«       |t"        dz  kD  r! |d#d$dd|dz  › d%�d&|dz  › d't"        › d�«       ‰S # t        $ r  |d
dd|dd«       Y �Œw xY w# t        $ r Y �ŒËw xY w)(zœStructural anomalies (counts, sizes, binaries, stray executables, escaping symlinks); *ignore(rel) -> bool*
    excludes paths from every count and finding.c                 óF   •— ‰j                  t        | |||d||«      «       y )Nr   )rþ   r   )r  ÚsevÚcatr‹  r#   Údescr5   s         €r-   r9  z_check_structure.<locals>.addà  s    ø€ Ø�‰œ  S¨#¨s°A°u¸dÓCÕDr,   r   r{  r   Úsymlink_escaperG   r§   zsymlink -> z*symlink points outside the skill directoryÚbroken_symlinkr[   zbroken symlinkzbroken or circular symlinki   Úoversized_fileÚ
structuralÚKBzfile is zKB (limit: zKB)Úbinary_filezbinary: zbinary/executable file (z) should not be in a skilléI   Úunexpected_executablezexecutable bit setzBfile has executable permission but is not a recognized script typeÚtoo_many_filesz(directory)z filesz
skill has z files (limit: rC  Úoversized_skillrœ   zKB totalz	skill is zKB total (limit: )r�  r(   rƒ  r‚  Ú
is_symlinkÚresolveÚis_relative_tork  ÚstatÚst_sizeÚMAX_SINGLE_FILE_KBr  rf  ÚSUSPICIOUS_BINARY_EXTENSIONSÚ_SCRIPT_EXTENSIONSÚst_modeÚMAX_FILE_COUNTÚMAX_TOTAL_SIZE_KB)rå  rz  r9  Ú
file_countÚ
total_sizerŠ  r‹  ÚresolvedÚstÚsizeÚextr5   s              @r-   r€  r€  Û  sa  ø€ ð €HôEàÐ€J�Ø�_‰_˜SÓ!ó VˆÜ�!—-‘- 	Ó*Ó+ˆØ—	‘	”˜qŸ|™|œ~°6Ð3EÉ&ÐQTÌ+ØØ�a‰ˆ
Ø�<‰<Œ>ðrØŸ9™9›;�Ø×.Ñ.¨y×/@Ñ/@Ó/BÔCÙÐ(¨*°kÀ3È+ÐV^ÐU_ÐH`ØDôFð ð	Ø—‘“ˆBð 	˜rŸz™zÐ)�tÑ*ˆ
ØÔ$ tÑ+Ò+ÙÐ  (¨L¸#À$È$Á,ÀÈrÐ?RØ˜4 4™<˜.¨Ô4FÐ3GÀsÐKôMà—8‘8—>‘>Ó#Ð#ˆCÔ(DÑDÙ�˜z¨<¸ÀÈÈÐ>NØ*¨3¨%Ð/IÐJôLàÔ(Ó(¨R¯Z©Z¸%Ô-?ÙÐ'¨°<ÀÐFZØTöVð5Vð8 ”NÒ"ÙÐ˜h¨°mÈ
À|ÐSYÐEZØ˜˜ O´NÐ3CÀ1ÐEô	GàÔ%¨Ñ,Ò,ÙÐ˜u l°MÀjÐTXÑFXÐEYÐYaÐCbØ˜
 dÑ*Ð+Ð+<Ô=NÐ<OÈsÐSô	Uà€Oøô/ ò rÙÐ$ h°¸SÐBRÐTp×qðrûô
 ò 	Úð	ús$   Á=?G Â>GÇ GÇGÇ	G*Ç)G*)z.skillignorez.clawhubignorec                 óh  ‡ ‡— g Šˆ fd„t         D «       D ]}  }t        t        t        «      5  |j	                  «       rN‰j                  d„ t        t        j                  |j                  d¬«      j                  «       «      D «       «       ddd«       Œ dt        dt        fˆfd„}|S # 1 sw Y   Œ�xY w)	ae  Build ``ignore(rel_posix_path) -> bool`` from `.skillignore` / `.clawhubignore`. gitignore basics: blank
    lines and ``#`` comments skipped; trailing ``/`` = directory (it and everything under it); ``*``/``?`` globs via
    fnmatch on the full path and each segment; leading ``/`` anchors to the root. Ignore files always excluded;
    ``SKILL.md`` never.c              3   ó(   •K  — | ]	  }‰|z  –— Œ y ­wrò   r+   )rö   re  rå  s     €r-   rù   z%_load_skill_ignore.<locals>.<genexpr>  s   øè ø€ ÒD Dˆy˜4ÕÑDùs   ƒc              3   óF   K  — | ]  }|r|j                  d «      s|–— Œ y­w)rÝ   N©r  )rö   Úss     r-   rù   z%_load_skill_ignore.<locals>.<genexpr>  s'   è ø€ ò  @ aÙ#$¨Q¯\©\¸#Ô->ô !"ñ  @ùs   ‚!r\  r]  Nr‹  r=   c                 óø  •‡— t        | «      j                  «       }|j                  d«      }|d   }|dk(  ry|t        v ry‰D ]µ  }|j	                  d«      }|j                  d«      Š‰sŒ(|j	                  ‰dz   «      }|j                  d«      r|‰k(  s|s|rŒWd‰z   dz   d|z   dz   v sŒh yt        j                  |‰«      s5|rŒƒt        j                  |‰«      s|sd‰vsŒ t        ˆfd„|D «       «      sŒµ y y)NrÏ  rA  r[  FTc              3   óJ   •K  — | ]  }t        j                   |‰«      –— Œ y ­wrò   )Úfnmatch)rö   Úsegr�  s     €r-   rù   z5_load_skill_ignore.<locals>.ignore.<locals>.<genexpr>+  s   øè ø€ Ò(QÀS¬¯©¸¸a×)@Ñ(Qùs   ƒ #)	r	   r�  ri  Ú_SKILL_IGNORE_FILENAMESr  rS  r  r  r8  )	r‹  Ú	rel_posixÚsegsÚbaseÚpatÚanchoredÚbelowr�  Úpatternss	          @€r-   rz  z"_load_skill_ignore.<locals>.ignore  sû   ù€ Ü˜“I×&Ñ&Ó(ˆ	Ø�‰˜sÓ#ˆØ�B‰xˆØ�:ÒØØÔ*Ñ*ØØò 	ˆCØ—~‘~ cÓ*ˆHØ—	‘	˜#“ˆAÙØØ×(Ñ(¨¨S©Ó1ˆEØ�|‰|˜CÔ Ø ’>¡U²8ÀÀqÁÈ3ÁÐTWÐZcÑTcÐfiÑTiÒ@jÙä—‘ ¨AÔ.²xÄWÇ_Á_ÐUYÐ[\ÔE]ÑafØ˜q’L¤SÓ(QÈDÔ(QÕ%QÙð	ð r,   )r  r   rj  rk  r‚  r  Úmapr(   rS  rh  Ú
splitlinesÚbool)rå  Úigrz  r  s   `  @r-   r~  r~    s©   ù€ ð
 €HÛDÔ,CÔDò @ˆÜÔ(¬'Ó2ñ 	@Ø�z‰zŒ|Ø—‘ñ  @¬3¬s¯y©y¸"¿,¹,ÐPW¸,Ó:X×:cÑ:cÓ:eÓ+fô  @ô @÷	@ð 	@ð@ð”Cð œDõ ð. €M÷9	@ð 	@ús   «AB(Â(B1	)z
skills-sh/z
skills.sh/z	skils-sh/z	skils.sh/c                 ó    ‡ ‡— ‰ t        t        ˆ fd„t        D «       d«      «      d Š‰dk(  ry‰dk(  ryt        ˆfd„t        D «       «      rdS d	S )
uÖ   Source id -> trust level. "official" is provenance, not a user-controlled GitHub id like "official/<repo>";
    trusted repos match exactly or as a skill path inside the repo â€” never a sibling sharing the prefix.c              3   óF   •K  — | ]  }‰j                  |«      sŒ|–— Œ y ­wrò   r	  )rö   r�  r1   s     €r-   rù   z'_resolve_trust_level.<locals>.<genexpr>8  s   øè ø€ ÒU À×@QÑ@QÐRSÕ@Tœ1ÑUùs   ƒ!š!r6   Nr   Úofficialr   c              3   óT   •K  — | ]  }‰|k(  xs ‰j                  |› d �«      –— Œ! y­w)rÏ  Nr	  )rö   ÚtÚsrcs     €r-   rù   z'_resolve_trust_level.<locals>.<genexpr>=  s,   øè ø€ ÒWÀA˜C 1™HÒ?¨¯©¸!¸¸A°wÓ(?Ó?ÑWùs   ƒ%(r   r   )rF  rn  Ú_SOURCE_PREFIX_ALIASESr8  ÚTRUSTED_REPOS)r1   r   s   `@r-   r|  r|  5  sU   ù€ ð ””TÓUÔ&<ÔUÐWYÓZÓ[Ð\Ð
]€CØ
ˆoÒØØ
ˆjÒØÜÓWÌÔWÔWˆ9ÐhÐ]hÐhr,   r5   c                 óZ   — | D �ch c]  }|j                   ’Œ }}d|v rdS d|v rdS dS c c}w )uT   critical â†’ dangerous, high â†’ caution; medium/low alone are informational (safe).rG   r   rN   r   r   )r   )r5   rŠ  rè  s      r-   r„  r„  @  s<   € à'Ö
(˜!ˆ1�:‹:Ð
(€CÐ
(Ø$¨Ñ+ˆ;ÐW¸fÈ¹m°ÐWÐQWÐWùò )s   …(re  r‰  r3   c                 ó¦   — |s| › d�S | › d|› dt        |«      › ddj                  t        |D �ch c]  }|j                  ’Œ c}«      «      › �S c c}w )Nz!: clean scan, no threats detectedz: rÞ  z finding(s) in z, )rF  rG  r–  r    )re  r1   r‰  r3   r5   rŠ  s         r-   rˆ  rˆ  F  sZ   € ÙØ�Ð8Ð9Ð9ØˆV�2�g�Y˜e¤C¨£M ?°/À$Ç)Á)ÌFÐhpÖSqÐcdÐTU×T^ÓT^ÒSqÓLrÓBsÐAtÐuÐuùÒSqs   ®Ac                 ó   — dt        | «      › �S )z8Full canonical digest used to bind scanner attestations.rœ  rž  rŸ  s    r-   Úfull_content_hashr&  Q  s   € à”_ ZÓ0Ð1Ð2Ð2r,   )r6   )r   )Frò   )UÚ__doc__Úrer  r’  r³  Ú
contextlibr   Údataclassesr   r   r   r   r   Úpathlibr	   Útypingr
   r   r²  r"  rÇ  rÈ  r   r/   rB   Ú_AGENT_CONFIG_FILESÚ_HERMES_CONFIG_FILESÚ_OTHER_AGENT_CONFIG_FILESr(   r@   rC   rE   Ú_NO_TRANSFERÚ_SHORT_FILLERÚ_NOT_DELEGATEÚ_SHELL_NAMES_REÚ
_CRED_FILEÚ_CRED_FILE_LITERALÚ_PY_CRED_FILE_ARGÚTHREAT_PATTERNSÚcompileÚ
IGNORECASErl  Ú	frozensetr  r  r  r  rÿ   r:   r
  r  rþ  rÿ  rú  rg  rû  rü  r1  r7  ro  rm  r3  r?  rL  rQ  rR  rW  rw  rŒ  rš  r   r;   rÄ  r  rÍ  rä  r€  r  r~  r!  r|  r„  rˆ  r&  )rr  Úrests   00r-   ú<module>r<     sÏ  ðñfó 
Û Û Û Ý ß 0Ñ 0ß 'Ý ß ð $€ò ^€ð 4Ø3Ø3à1ñ€ð  q°qÑ9€ð ÷ð ó ðð ÷8ð 8ó ð8ðNð ð NÐ Ø<Ð àGÐ ð	M˜cð 	M có 	Mð9˜sð 9 só 9ðm 3ð m¨3ó mð H€ð $€ðYð ð .€ð
 D€
ð '¨Ñ3Ð6GÑGÐ Ø8Ð;MÑMÐPYÑYÐ ðhðmðhðmðhðnðhð^ðhðeðhð" vð#hð$ jð%hð& vð'hð( lð)hð* vð+hð,kð-hð0að1hð6Rð7hð: 5Ð7IÑIØ˜Z¨Ð9cðeð;hðN Ð*Ñ*Ø`ñaàñà-ñ.à0jñkð ˜Z¨Ð9_ðaðOhðX fðYhðbzðchðfHðghðj~ðkhðn rðohðr Bðshð~tðhðBSðChðHuðIhðL |ðMhðPkðQhðT tðUhðX]ðYhð\_ð]hð`dðahðd[ðehðhYðihðltðmhðpdðqhðt_ðuhðx\ðyhð|Tð}hðHUðIhðPdðQhðT cðUhðV jðWhðX ZðYhðZ ið[hð\ Bð]hð^ tð_hðb XðchðnOðohðrOðshðv dðwhðx QðyhðzZð{hð~ cðhð@XðAhðD rðEhðF wðGhðNQðOhðRXðShðV @ðWhðX pðYhðZ 	ˆoÐÐ2Ð3Ø˜: yÐ2_ðað[hð^sð_hðb zðchðdgðehðh_ðihðn {ðohðpaðqhðt bðuhðv bðwhðx 	˜oÐ.Ð.EÐFØ�z =Ð2[ð]ðyhð|Vð}hð@pðAhðD wðEhðFpðGhðJoðKhðN fðOhðP lðQhðR^ðShðViðWhð\Pð]hð` oðahðb gðchðd }ðehðf ~ðghðh zðihðl sðmhðn fðohðp vðqhðr zðshðt gðuhðx Bðyhðz zð{hð~ 	˜?Ð+Ð,Ð.?ÀÈ^ð  ^Jð  Kðhð@ 	$ OÐ#4Ð5Ø˜
 NÐ4`ðbðAhðD vðEhðHzðIhðL^ðMhðP |ðQhðR lðShðVUðWhðZ eð[hð\ fð]hðbAðchðlWðmhðplðqhðtxðuhðx hðyhñN Ð)Ó*Ø˜ ]ð  5PðQðOhñR Ð(Ó)Ø˜z¨=ð  ;YðZðShñV Ð-Ó.Ø˜f mð  6SðTðWhðZDð[hñ^ Ð*Ó+Ø˜& -Ð1|ð~ð_hñb Ð)Ó*Ø 
¨Mð  <JðKðchðfMðghñj Ð/Ó0Ø˜v }Ð6bðdðkhñn Ð.Ó/Ø# Z°ð  AVðWðohðrWðshðBlðChðJXðKhðNpðOhðR AðShðToðUhðX |ðYhðZpð[hð` Aðahðb ðchðdfðehðhpðihðleðmhðp`ðqhðtgðuhðF	 	1°°¸}¸oð N#Ø#/ .°°À¸ÈiðYà�f˜nÐ.dðfðG	hðL	UðM	h€ðT	 `o×oÈ^ÈWÐW[˜j˜bŸj™j¨°"·-±-Ó@ÐHÀ4ÓHÓoÐ ñ (ò )fó gÐ ð5�5˜#ð 5˜u cð 5¨7°Cð 5¸Àð 5ÀUÈCð 5ÐQUÐWZð 5Ð\aÐcfð 5ÐhoÐqtð 5Ø˜3ð5Ø '¨ð5Ø.5°sð5Ø<BÀJð5ØPVÐXbð5ØdiÐkoð5à˜$ð5à &¨ð5€ð  �R—Z‘Zð[Ø\^×\iÑ\iókÐ ð
  �R—Z‘ZðAàBDÇ-Á-óQÐ ð �"—*‘*Ð8Ó9€ð˜Tð  dó ð	! cð 	!°Sð 	!Àsð 	!ÐRUð 	!Ðcfð 	!Ø),ð	!Ø16°s¸C°x±ó	!ð 9FÑ 5€Ð!Ð#5òZÐ ò eÐ â:Ð ðKØÐ ðKØ"*Ð,CðKØEMÐObðKàˆmðKà%Ð'8ðKà:BÐDYðKñ ÑðKñ !)Ñ*IðKñ ‰oð	Kñ  (©ð	Kñ ;CÑDUð	Kñ
 ‰nðKñ
 '©ðKñ
 9AÁ-ðKñ
 RZÑ[hðKñ Ñ$ðKñ '/Ñ0IðKÐ ñ Ð+Ó,€Ù/Ñ1FÐGÐ ñA˜Sð A Sô Að Dð ¨Sô ð¨3ð °3ô ðJ ˆb�j‰jÑGÓH€ð �B—J‘JÑOÓPÐ ð¨¨c©ð °t¸C±yô ó.˜ñ ¨ð °d¸7±mô ó@N˜4ñ N¨ð N¸zô Nñ& ð ¨ô ñ$8˜Tð 8 cô 8ñÑXZØ/3ô $ñ °ñ ÐRUñ Ø!%¨¡ðØ8=¸jÈ$Ð>NÑ8Oôó>} ñ }°Dð }ÀUÈ4ÐQTÈ9ÑEUô }ñ C˜zð C¨cô Có* ð *°d¸7±mô *ñ\ =Ð ñ# $ô #ñL PÐ ñi ð i¨ô iñX  g¡ð X°3ô Xñv˜ñ v cñ v°#ñ vÀñ vÈtÐT[É}ð vÐadô vñ3 $ð 3¨3õ 3ùóA ps   É*R/