
    i                       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lZddl	Z	ddl
Z
ddlmZmZ ddlmZ ddlmZmZ ddlmZmZ  ee      j-                         j.                  j.                  Z ee      e	j4                  vr"e	j4                  j7                  d ee             ddlmZmZmZm Z m!Z! dd	l"m#Z#m$Z$m%Z%  ed
      Z& ed      Z'g dZ(g dZ)g dZ*g dZ+g dZ,g dZ-g dZ. ej^                  d      Z0g dZ1g dZ2g dZ3g dZ4d#dZ5d$dZ6d%dZ7d&dZ8 G d de#      Z9d'dZ:	 	 	 	 d(	 	 	 	 	 	 	 	 	 	 	 d)dZ;d*d Z<d+d!Z=e>d"k(  r ej~                   e=              yy),uo  
Competitive Intel — Autonomous competitor onboarding funnel analysis.
======================================================================
Navigates to a competitor's site, finds and completes signup autonomously,
tracks every page transition with numbered screenshots, checks email for
verification links, maps the full funnel, and generates a comprehensive JSON
report with friction score, pricing discovery, and feature list.

Usage (CLI):
    python testing/competitive_intel.py --url https://competitor.com
    python testing/competitive_intel.py --url https://competitor.com --screenshots --report
    python testing/competitive_intel.py --url https://competitor.com --email-provider mailslurp

Programmatic:
    from testing.competitive_intel import CompetitiveIntelAgent
    agent = CompetitiveIntelAgent(url="https://competitor.com")
    report = await agent.run()
    )annotationsN)datetimetimezone)Path)AnyOptional)urljoinurlparse)EmailProviderInboxextract_verification_linkget_email_providerwait_for_email)BaseScenarioScenarioResult
StepResultz)/mnt/e/genesis-system/testing/screenshotsz%/mnt/e/genesis-system/testing/reports)za[href*=signup]za[href*=register]za[href*=sign-up]za[href*=create-account]za[href*=get-started]za[href*=free-trial]za[href*=start]za:text-matches("sign up", "i")za:text-matches("register", "i")z"a:text-matches("get started", "i")z!a:text-matches("start free", "i")za:text-matches("try free", "i")#button:text-matches("sign up", "i")'button:text-matches("get started", "i")z&button:text-matches("start free", "i"))zinput[type=email]zinput[name=email]zinput[id*=email]zinput[placeholder*=email i]zinput[name=username]zinput[id*=username]zinput[autocomplete=email])zinput[type=password]zinput[name=password]zinput[id*=password]zinput[placeholder*=password i])zinput[name=name]zinput[name=full_name]zinput[name=fullname]zinput[name=first_name]zinput[id*=name]zinput[placeholder*=name i]zinput[autocomplete=name])	zform[action*=register]zform[action*=signup]zform[action*=sign-up]zform[action*=create]z#signupz	#registerz#sign-upz#create-accountform)	zbutton[type=submit]zinput[type=submit]r   z*button:text-matches("create account", "i")z$button:text-matches("register", "i")r   z$button:text-matches("continue", "i")z button:text-matches("next", "i")zform button)za[href*=pricing]za[href*=plans]za[href*=subscribe]za:text-matches("pricing", "i")za:text-matches("plans", "i")za:text-matches("upgrade", "i")u#   [\$£€A\$]\s*[\d,]+(?:\.\d{1,2})?)zul.features liz.feature-list liz.pricing-features liz.plan-features liz[class*=feature] liz.benefits liz[class*=benefit] li)z[class*=dashboard]z[class*=app-nav]znav [href*=logout]znav [href*=signout]za[href*=logout]za[href*=signout]z[data-testid*=user]z[class*=user-menu]z[class*=account-menu]z.sidebarz#sidebarz[class*=onboarding])JamesEmmaOliverAvaWilliamSophiaNoahIsabellaLiamMiaEthan	CharlotteMasonAmeliaJacobHarperMichaelEvelynJackAbigail)SmithJohnsonWilliamsJonesBrownDavisMillerWilsonMooreTaylorAndersonThomasJacksonWhiteHarrisMartinThompsonGarciaMartinezc                   t        j                  t              }t        j                  t              }t        j                  dd      }d| dt        j                  dd       }||| d| | || dd	d
j                  t        d      D cg c]!  }t        t        j                  dd            # c}       dS c c}w )z5Generate a realistic human identity for signup forms.
   c   Testz!Genesisd   i   z Consultingz+614    r   	   )
first_name	last_name	full_nameemailpasswordcompanyphone)randomchoice_FIRST_NAMES_LAST_NAMESrandintjoinrangestr)email_addressfirstlastsuffixrJ   _s         2/mnt/e/genesis-system/testing/competitive_intel.py_generate_identityr[      s    MM,'E==%D^^B#FfXXfnnS#&>%?@Hwav&V;'E!H MqV^^Aq%9!: MNOP  !Ns   &B=c                ^    t        |       }|j                  j                  dd      xs | d d S )Nzwww.rC   (   )r
   netlocreplace)urlparseds     rZ   _domain_from_urlrb      s-    c]F==  ,8CR8    c                0    t        j                  dd|       S )Nz[^\w\-.]rY   )resub)domains    rZ   _safe_dirnamerh      s    66+sF++rc   c                   d}t        d | D              }t        d | D              }t        d | D              }t        |       }t        d | D              dz  }|t        d|dz
  dz        z  }||rd	ndz  }|t        d|d
z
  dz  dz        z  }||dz  z  }|dkD  r|d	z  }n
|dkD  r|dz  }t	        t        |d      d      S )u=  
    Score the onboarding friction on a 0–10 scale.
    0 = frictionless, 10 = extremely painful.

    Factors:
    - Number of form fields encountered
    - Email verification required (adds friction)
    - Number of funnel steps before "first value"
    - Any errors/failures
    - Time to complete (seconds)
            c              3  @   K   | ]  }|j                  d d        yw)fields_filledr   Nget.0ss     rZ   	<genexpr>z)compute_friction_score.<locals>.<genexpr>   s     GQquu_a0G   c              3  D   K   | ]  }|j                  d       dk(    yw)	step_typeemail_verificationNrm   ro   s     rZ   rr   z)compute_friction_score.<locals>.<genexpr>   s     aqk 26J Jas    c              3  H   K   | ]  }|j                  d       dvsd  yw)status)passskipped   Nrm   ro   s     rZ   rr   z)compute_friction_score.<locals>.<genexpr>   s      ]Q!%%/I\2\q]s   ""c              3  @   K   | ]  }|j                  d d        ywduration_msr   Nrm   ro   s     rZ   rr   z)compute_friction_score.<locals>.<genexpr>   s     E1quu]A.Ers        @@r      g       @         ?g      ?i,  x   g      $@)sumanylenmaxroundmin)funnel_stepsscoretotal_fieldsverification_requiredfailed_steps
step_counttotal_time_ss          rZ   compute_friction_scorer      s     EG,GGLaT`aa],]]L\"JEEENL 
S\A%*++E	)Ss2E	SZ!^q(3.//E	\CEc		UD!1%%rc   c                       e Zd ZdZdZ	 	 	 d	 	 	 	 	 	 	 	 	 d fdZddZddZddZddZ	ddZ
dd	Zdd
ZddZddZ	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZ xZS )CompetitiveIntelAgenta"  
    Full autonomous competitor onboarding agent.

    Inherits BaseScenario for Playwright helpers + screenshot infrastructure.
    Adds: identity generation, autonomous form discovery, email verification,
    pricing extraction, feature extraction, funnel mapping, report generation.
    competitive_intelc                   t         |           |j                  d      | _        t	        |      | _        t        | j
                        | _        || _        || _	        || _
        d | _        d | _        g | _        d| _        t        d| j                   z  | _        | j                   j#                  dd       t$        j#                  dd       t'        j&                         | _        y )N/r   competitor_T)parentsexist_ok)super__init__rstrip
target_urlrb   rg   rh   safe_domainsave_screenshotsemail_wait_timeout_email_provider_inbox	_identity_funnel_steps_screenshot_counterSCREENSHOTS_BASE_screenshots_dirmkdirREPORTS_DIRtime_start_time)selfr`   email_providerr   r   	__class__s        rZ   r   zCompetitiveIntelAgent.__init__  s     	**S/&s+(5 0"48F'+)-)+()  0[AQAQ@R3S S##D4#@$6"&))+rc   c                  K   || _         || _        |j                  dd      | _        | j	                          d {    | j                          d {    | j                          d {    | j                          d {    | j                          d {    | j                          d {    | j                          d {    | j                          d {    y 7 7 7 7 k7 U7 ?7 )7 w)Ndefault_timeout N  )_page_configrn   _timeout_phase_create_identity_phase_homepage_phase_find_signup_phase_signup_form_phase_post_signup_phase_email_verification_phase_discover_pricing_phase_generate_report)r   pageconfigs      rZ   runzCompetitiveIntelAgent.run  s     


#4f= ))+++ ""$$$ %%''' %%''' %%''' ,,... **,,, ))++++ 	, 	% 	( 	( 	( 	/ 	- 	,s   9C9C)C9C+C9+C-,C9C/C9C1C93C34C9C5C9#C7$C9+C9-C9/C91C93C95C97C9c           
       K   | j                  d      }	 | j                  xs
 t               }|j                  d| j                   dt        t        j                                       d {   | _        || _        t        | j                  j                        | _
        | j                  |dd| j                  d    d| j                  j                   d	       | j                  d
dd| j                  j                  | j                  d   d       y 7 # t        $ r?}| j                  |dd|        | j                  d
dddt        |      i       Y d }~y d }~ww xY ww)Ncreate_identityci_rY   )namery   z
Identity: rH   z <>identity_creation)rI   r   )ru   	step_namerx   detailserrorzFailed to create inbox: )	_new_stepr   r   create_inboxr   intr   r   r[   rU   r   _finish_step_record_funnel	ExceptionrT   )r   stepproviderexcs       rZ   r   z,CompetitiveIntelAgent._phase_create_identity=  s[    ~~/0	f++C/A/CH ( 5 54++,Ac$))+.>-?@ !6 ! DK $,D /0I0IJDNfT^^K89DKK<U<U;VVWX -+"&++";";T^^T_E`a	     	fdG/Gu-MN 35FRY[^_b[cQdee	fsB   E$AD -D.B(D E$D 	E!"5EE$E!!E$c           
       K   | j                  d      }t        j                         }	 | j                  j                  | j                  | j
                  d       d {    | j                  j                          d {   }| j                  d       d {   }t        t        j                         |z
  dz  d      }| j                  |dd|        | j                  ddd| j                  |d	||
       y 7 7 ~7 g# t        $ ra}| j                  d       d {  7  }| j                  |dt        |             | j                  ddddt        |      i|       Y d }~y d }~ww xY ww)Nnavigate_homepagedomcontentloadedtimeout
wait_untilhomepage  r{   ry   zTitle: )r`   title
screenshotr~   homepage_errorr   r   )r   r   r   gotor   r   r   _numbered_screenshotr   r   r   r   rT   )r   r   t0r   r   r~   r   s          rZ   r   z%CompetitiveIntelAgent._phase_homepageT  sO    ~~12YY[	7**//$//4==Ug/hhh****,,E#88DDJr!1T 91=KdFgeW,=>/%8%;    i,D  	7#889IJJJJdGSX6
,?7TWX[T\J]+5   7 7	7sr   &E05D C=!D  C?D DA"D <E0=D ?D D 	E-E( D#!AE(#E0(E--E0c           
       K   | j                  d      }t        j                         }	 d }t        D ],  }	 | j                  j	                  |       d {   }|r|} n. |r| j                  j                  |d       d {   xs d}| j                  d| d|        | j                  j                  || j                         d {    | j                  j                  d| j                         d {    | j                  d       d {   }t        t        j                         |z
  d	z  d
      }| j                  |dd| d       | j                  ddd||d||       y | j                  }	dD ]  }
	 | j                  j!                  t#        |	|
      | j                  d       d {    | j                  j%                          d {   }|rd|j'                         vrp| j                  d       d {   }t        t        j                         |z
  d	z  d
      }| j                  |dd|
 d       | j                  dddd|
d||        y  | j                  d       d {   }| j                  |dd       | j                  ddddt        d d i|       y 7 \# t
        $ r Y w xY w7 @7 7 7 7 7 7 # t
        $ r Y dw xY w7 m# t
        $ ra}| j                  d       d {  7  }| j                  |d t)        |             | j                  ddd d t)        |      i|       Y d }~y d }~ww xY ww)!Nfind_signup_linkhrefrC   zSignup link found: u    → r   r   signup_pager   r{   ry   zClicked signup link ()find_signup)selector_usedr   r   )z/signupz	/registerz/sign-upz/create-accountz/get-startedr   404signup_page_directzDirect nav to z worked
direct_nav)methodpathsignup_not_foundfailz!No signup link or form page foundtried   r   find_signup_errorr   )r   r   SIGNUP_LINK_SELECTORSr   query_selectorr   get_attribute_logclickr   wait_for_load_stater   r   r   r   r   r   r	   r   lowerrT   )r   r   r   found_selectorselelr   r   r~   baser   status_textr   s                rZ   r   z(CompetitiveIntelAgent._phase_find_signuph  ss    ~~01YY[8	L!N, #zz88==B),  !ZZ55nfMMSQS		//?uTFKLjj&&~t}}&MMMjj445GQUQ^Q^4___#'#<#<]#KK
#TYY[2%5$=qA!!$2GGWWX0YZ##!#5v&4dC){ $  c !D!"jjoogdD.A4==:L . N N N -1JJ,<,<,>&>&58I8I8K+K/3/H/HI]/^)^J*/r1AT0I1*MK --dFnTFRY<Z[ // -/A6+7 F+5; 0 
 #!& $(#<#<=O#PP
!!$0ST##M3Ev%,.CBQ.G$H/9 $ ;Y > !  NM_KN '?)^ % ! ! Q  	L#889LMMMJdGSX6/A7!(#c( 3
   L L	Ls3  &MK' J2J/J2&K' KA	K' K.K' ;K<K' KAK' .M/K' 5K6K7!KK,KKAKK'  M!K' 7K%86K' .M/J22	J?;K' >J??K' K' K' K' KKK	K"K' !K""K' '	M0MLAMMMMc           	     .  K   | j                  d      }t        j                         }d}	 | j                  j                  d| j                         d {    t
        D ]  }| j                  j                  |       d {   }|s)|j                          d {   }|sD|j                  d       d {   xs d}d|j                         v r'|j                  | j                  d          d {    n&|j                  | j                  d	          d {    |d
z  }| j                  d|         n d}t        D ]  }| j                  j                  |       d {   }|s)|j                          d {   sB|j                  | j                  d          d {    |d
z  }d}| j                  d|         n |sE| j                  d       d {   }	| j                  |dd       | j!                  dddddi|	       y d}
t"        D ]  }| j                  j                  |       d {   }|s)|j                          d {   sB|j                  | j                  d          d {    |d
z  }d}
| j                  d|         n |
s| j                  d       d| j                  d   fd| j                  d   fd| j                  d   fd| j                  d   ffD ]v  \  }}| j                  j                  |       d {   }|s,|j                          d {   sE|j                  |       d {    |d
z  }| j                  d|        x t%        j&                  t)        j*                  d d!             d {    | j                  d"       d {    d}t,        D ]  }| j                  j                  |       d {   }|s)|j                          d {   sB|j/                          d {   }|r]|j1                  | j                         d {    d}| j                  d#|         n |sF| j                  d$       d {   }	| j                  |dd%       | j!                  ddd|d&d'|	       y 	 | j                  j                  d| j                         d {    | j                  d(       d {   }	t5        t        j                         |z
  d)z  d
      }| j                  |d*d+| d,       | j!                  ddd*|| j                  d   d-|	||.       y 7 7 7 7 7 f7 B7 7 7 7 7 27 7 7 ]7 E7 .7 7 7 7 7 v7 R7 !7 # t2        $ r Y w xY w7 # t2        $ rc}| j                  d/       d {  7  }	| j                  |d0t7        |             | j!                  ddd0t7        |      |d1|	|2       Y d }~y d }~ww xY ww)3Nfill_signup_formr   r   r   r   rC   rV   rF   rH   r{   zFilled name field: FrI   TzFilled email: no_email_fieldr   z#No email field found on signup formsignup_formreasonr   rJ   zFilled password: u;   No password field found — may be OAuth or email-only flowzinput[name*=company i]rK   zinput[placeholder*=company i]zinput[name*=phone i]rL   zinput[placeholder*=phone i]zFilled optional field: r         ?
pre_submitzClicked submit: no_submit_buttonz$Could not find enabled submit button	no_submit)rl   r  post_submitr   ry   zForm submitted (z fields filled))rl   rI   )r   r~   rl   signup_form_errorr   )r   rl   )r   rl   )r   r   r   r   r   NAME_FIELD_SELECTORSr   
is_visibler   r   fillr   r   EMAIL_FIELD_SELECTORSr   r   r   PASSWORD_FIELD_SELECTORSasynciosleeprM   uniformSUBMIT_BUTTON_SELECTORSis_disabledr   r   r   rT   )r   r   r   rl   r   r   visible	name_attremail_filledr   	pw_filledtry_selvalue	submitteddisabledr~   r   s                    rZ   r   z(CompetitiveIntelAgent._phase_signup_form  s    ~~01YY[p	T**001CT]]0[[[ , ::44S99$&MMO3G*,*:*:6*B$B$Hb	"ioo&77"$''$..*F"GGG"$''$..*E"FFF%*		$7u"=>  !L, ::44S99//''$.."9:::!Q&M#'LIIse45  #'#<#<=M#NN
!!$0UV##M3Ev%-/?$@Z $ Y I/ ::44S99//''$.."<===!Q&M $III 1#78 		WX *4>>)+DE0$..2KL')@A.w0GH	# 
C  ::44W==//''%.((!Q&MII 7yAB
C --sC 8999 ++L999 I. ::44S99//%'^^%55H# hht}}h===$(			$4SE":; #'#<#<=O#PP
!!$0VW##M3Ev6C{$[/9 $ ; jj445GQUQ^Q^4___  $88GGJr!1T 91=KdF.>}o_,]^16"/$..:QR%;+	   G \ :3 %CGF :/: O :/=" >/(
 : :
 :/5= Q `  H  	T#889LMMMJdGSX6/A7*-c(] S+5]   T T	Tss  (X*V& U+V& UV& 	V& UV& $V& 8U9;V& 4U5&V& UA	V& %U &V& -V&  U#V& !V& 'U&(8V&  U)!/V& X)V& :U,;V& V& U/V& !V& <U2=BV& U5V&  V& 3U84V& 9V& U;AV& U>V& 2V3-V&  V!V& (V& ;V<V& V& V
V& V& ;V<3V& /V00V&  X"*V VV V& %V$&A'V& XV& V& V& V& V& V&  V& #V& &V& )V& ,V& /V& 2V& 5V& 8V& ;V& >V& V& V& V& 
V& V& V& V 	V!V&  V!!V& &	X/XWAXXXXc           
     v  K   | j                  d      }t        j                         }	 t        j                  d       d {    | j                  j
                  }| j                  j                          d {   }| j                  j                  d       d {   }d}t        D ]D  }| j                  j                  |       d {   }|s)|j                          d {   sBd} n |dk(  rGg d}	|j                         t        fd|	D              rd}nd	v sd
v rd}n|| j                  k7  rd}| j                  d|        d {   }
t        t        j                         |z
  dz  d      }| j!                  |dd|        | j#                  ddd|||d|
|       || _        y 7 t7 ?7 7 7 7 n# t&        $ rh}| j                  d       d {  7  }
| j!                  |d	t)        |             | j#                  ddd	d	t)        |      i|
       d	| _        Y d }~y d }~ww xY ww)Npost_signup_stater   bodyunknownauthenticated_dashboard)verifyconfirmzcheck your emailzwe sent
activationspamc              3  &   K   | ]  }|v  
 y w)N )rp   kw
page_lowers     rZ   rr   z;CompetitiveIntelAgent._phase_post_signup.<locals>.<genexpr>1  s     BBrZ'Bs   email_verification_requiredr   invalidsignup_error
redirectedpost_signup_r   r{   ry   zPost-signup state: post_signup)stater`   r   r   post_signup_errorr   )r   r   r  r  r   r`   r   
inner_textDASHBOARD_INDICATORSr   r  r   r   r   r   r   r   r   _post_signup_stater   rT   )r   r   r   current_urlr   	page_textr0  r   r   verify_keywordsr   r~   r   r)  s                @rZ   r   z(CompetitiveIntelAgent._phase_post_signup  s"    ~~12YY[)	.--"""**..K****,,E"jj33F;;I E+ ::44S99//5E	 	!#D&__.
B/BB9E
*i:.E*E DOO3(E#88<w9OPPJr!1T 91=KdF.A%,IJ2FeD%;    ',D#C #,;
 :/ Q  	.#889LMMMJdGSX6/BG!(#c( 3
   L&-D##	.s   &H9G F67G :F9;"G F<-G F?G G &G'G ,A(G GA G 5H96G 9G <G ?G G G 	H6H1"G%#A	H1,H91H66H9c           
     0  K   | j                  d      }t        j                         }| j                  r| j                  s(| j	                  |dd       | j                  dddi        y 	 | j                  d| j                   d       t        | j                  | j                  j                  d | j                  d       d {   }|j                  xs d}| j                  d	|        d }|j                  rt        |j                        }nF|j                  r:t        j                  d
|j                        }t!        d |D        |r|d   nd       }|r| j                  d|        | j"                  j%                  || j&                  d       d {    t)        j*                  d       d {    | j-                  d       d {   }t/        t        j                         |z
  dz  d      }| j	                  |dd|d d         | j                  ddd||dd||       y | j-                  d       d {   }| j	                  |dd| d       | j                  ddd|dd|       y 7 7 7 7 7 ># t0        $ r> | j                  d        | j	                  |dd!       | j                  dddd"dd#       Y y t2        $ rE}	| j	                  |d$t5        |	             | j                  ddd$d$t5        |	      i       Y d }	~	y d }	~	ww xY ww)%Nrv   rz   zNo inbox configuredz&Waiting for verification email (up to zs)...      @)subject_containsr   poll_intervalz(no subject)zEmail received: zhttps?://\S+c              3  l   K   | ],  }t        j                  d |t         j                        s)| . yw)zverif|confirm|activatN)re   search
IGNORECASE)rp   us     rZ   rr   zBCompetitiveIntelAgent._phase_email_verification.<locals>.<genexpr>e  s*      #bii,a71 #s   *44r   zVerification link: r   r   r   after_email_verificationr   r{   ry   zVerified via: P   )subject
verify_urlru   r   no_verify_linkr   z8Email received but no verification link found (subject: r   no_link_found)rB  r  r   u<   No verification email received within timeout — continuingu6   No email within timeout — product may not require itr   )r  ru   r   )r   r   r   r   r   r   r   r   r   idrB  htmlr   textre   findallnextr   r   r   r  r  r   r   TimeoutErrorr   rT   )
r   r   r   rI   rB  rC  urlsr   r~   r   s
             rZ   r   z/CompetitiveIntelAgent._phase_email_verificationI  s    ~~23YY[{{$"6"6dI/DE 46JIWYZ8	5II>t?V?V>WW\]^($$!%//! E mm5~GII(	23 Jzz6uzzB
zz/5::>! #d ##DG/
 		/
|<=jjooj$--2D & F F FmmA&&&#'#<#<=W#XX
#TYY[2%5$=qA!!$.CR@Q0RS##(*>#*&0%9
  *{ $  $(#<#<=M#NN
!!$2jkrjsst0uv##(*> '?C) $ S.F&X O  	ZIITUdI/gh 46JI+4CW XZ 	5dGSX6 46JG!(#c( 35 5	5s   A&L)AJ  I5CJ  I8J  4I:5J  I<AJ  *L+J  ?I> 4J  4L5J  8J  :J  <J  >J   ALLL;L	LLLc           
     f  K   | j                  d      }t        j                         }	 d }t        D ]i  }| j                  j	                  |       d {   }|s)|j                  d       d {   xs d}|sIt        | j                  j                  |      } n g }g }d}	|r| j                  j                  || j                  d       d {    | j                  j                  }	| j                  j                  d       d {   }
t        t        t        j                  |
                  }t        D ]~  }| j                  j!                  |       d {   }|s)|d d D ]J  }	 |j                          d {   j#                         }|rt%        |      dk  r|j'                  |       L |s~ n |sK	 | j                  j                  d       d {   }t        t        t        j                  |                  }| j+                  d	       d {   }t-        t        j                         |z
  d
z  d      }| j/                  |ddt%        |       dt%        |       d       | j1                  ddd|	||d d d||       ||d d |	d| _        y 7 N7 57 7 7 O7 .# t(        $ r Y Tw xY w7 # t(        $ r Y w xY w7 # t(        $ rP}| j/                  |dt5        |             | j1                  ddddt5        |      i       g g dd| _        Y d }~y d }~ww xY ww)Ndiscover_pricingr   rC   r   r   r        pricing_pager   r{   ry   z	Pricing: z prices found, z	 featurespricing_discovery   )pricing_urlprices_foundfeatures_foundr   pricesfeaturesr`   r   )r   r   PRICING_PAGE_SELECTORSr   r   r   r	   r`   r   r   r2  listsetPRICE_AMOUNT_PATTERNrI  FEATURE_BULLET_SELECTORSquery_selector_allstripr   appendr   r   r   r   r   _pricing_datarT   )r   r   r   rT  r   r   r   rX  rY  pricing_page_urlr6  itemsitemrH  r  r   r~   r   s                     rZ   r   z-CompetitiveIntelAgent._phase_discover_pricing  s(    ~~01YY[C	KK- ::44S99!#!1!1&!99?RD&-djjnnd&C !#F"$H!jjook4==2D & F F F#'::>> "&**"7"7"??	 c"6">">y"IJK 4 "C"&**"?"?"DDE$)#2J )D).2oo.?(?'F'F'H#'CIO$,OOD$9	) $!" !%!6!6v!>>D!#&:&B&B4&H"IJF  $88HHJr!1T 91=KfCK=HiP #%7#3$*&.sm
 &;    -3"Vf!gDu :9F @ E )@ $- ) () ?   I"  	KdGSX6 35G!(#c( 35,.Br!JD		Ks  &L1)K J K K .J#/
K :AK J&8K 
J)AK J,K %K .J2J/3J25K :K  K K+K 
K KB K L1 K #K &K )K ,K /J22	J?;K >J??K K 	KK KK 	L.AL)$L1)L..L1c                  K   | j                  d      }	 t        t        j                         | j                  z
  d      }t	        | j
                        }t        j                  t        j                        j                  d      }d }| j
                  D cg c]+  }|j                  d      dvr|j                  d      dk(  r|- }}|rKt        t        d | j
                  d | j
                  j                  |d	         dz    D              d
z  d      }| j                  | j                  |d| j                   r| j                   d   nd | j"                  r| j"                  j$                  nd ddt'        | j
                        |||t)        |      | j*                  t-        d | j
                  D              dt/        | dg g dd      | j
                  t1        | j2                        d}t4        d| j6                   d| dz  }	|	j9                  t;        j<                  |d             | j?                  |dd|	        | jA                  d| dt)        |       d       | jA                  dt'        | j
                                | jA                  d|	        t1        |	      | _!        || _"        y c c}w # tF        $ r }
| j?                  |d d!|
        Y d }
~
y d }
~
ww xY ww)"Ngenerate_reportr{   %Y%m%dT%H%M%SZru   )r   r   r   r  rx   ry   c              3  @   K   | ]  }|j                  d d        ywr}   rm   ro   s     rZ   rr   z?CompetitiveIntelAgent._phase_generate_report.<locals>.<genexpr>  s      AmQ/ rs   r   r   z1.0.0rH   )r   rI   )competitor_urlrg   generated_atagent_versionidentity_usedc              3  p   K   | ].  }|j                  d       dk(  xr |j                  d      dk(   0 yw)ru   rv   rx   ry   Nrm   ro   s     rZ   rr   z?CompetitiveIntelAgent._phase_generate_report.<locals>.<genexpr>  s=      7 k*.BB`quuXZ`G``7s   46)funnel_step_counttotal_time_secondstime_to_first_value_secondsfriction_scorefriction_explanationscreenshots_takenr*  rb  rC   rW  )metasummarypricingfunnelscreenshots_dirr   rY   .jsonr   )indentzReport saved: zFriction score: /10 (r   zFunnel steps: zReport: r   zReport generation failed: )$r   r   r   r   r   r   r   nowr   utcstrftimern   r   indexr   rg   r   r   rU   r   _friction_labelr   r   getattrrT   r   r   r   
write_textjsondumpsr   r   _report_path_reportr   )r   r   	elapsed_sfrictiontsttfv_srq   passed_after_signupreportreport_pathr   s              rZ   r   z,CompetitiveIntelAgent._phase_generate_report  s    ~~/08	QdiikD,<,<<a@I-d.@.@AHhll+445EFB F--#55% .> >BC%%/U[B[ # #
 # 9K9K MM**001DQ1GH1L:   !" '+oo"kk$&%,?C~~{ ;SW>Bkk!:!:t&	 *-T-?-?)@*339&.,;H,E)-)A)A36 7!%!3!37 4 #4RUW`b:cd,,#&t'<'<#=3F8 &+d6F6F5GqE(RRK""4::fQ#?@dFn[M,JKII(
%8Q7RRSTUIIs4+=+='>&?@AII./ #K 0D!DL_#`  	QdG/I#-OPP	QsB   K'BJ; 0J6G.J; 5K'6J; ;	K$KK'K$$K'c                x    | j                   j                  t        | j                         dz   |||||||d       y )Nr{   )step_numberru   r   rx   screenshot_pathr~   rl   r   )r   ra  r   )r   ru   r   rx   r   r   r~   rl   s           rZ   r   z$CompetitiveIntelAgent._record_funnel  sE     	!!t112Q6"")&*	#
 		rc   c                  K   | j                   sy	 | xj                  dz  c_        | j                  dd| d}| j                  |z  }| j                  j	                  t        |      d       d{    | j                  d	| j                  dd
|j                          t        |      S 7 ;# t        $ r}| j                  d|        Y d}~yd}~ww xY ww)z1Capture screenshot with sequential number prefix.rC   r{   03drY   z.pngT)r   	full_pageNz[SHOT z] z[SHOT-ERR] )	r   r   r   r   r   rT   r   r   r   )r   labelfilenamer   r   s        rZ   r   z*CompetitiveIntelAgent._numbered_screenshot)  s     $$		$$)$2237qtDH((83D**''SY$'GGGIIt77<BtyykJKt9 H  	IIC5)*	sA   CA B/ 1B-2:B/ ,C-B/ /	C8CCCC)NTZ   )
r`   rT   r   zOptional[EmailProvider]r   boolr   r   returnNone)r   r   r   dictr  r  r  r  )rC   rj   r   )ru   rT   r   rT   rx   rT   r   r  r   rT   r~   floatrl   r   r  r  )r  rT   r  rT   )__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__)r   s   @rZ   r   r      s     D
 37!%"$.. 0. 	.
  . 
.6,Bf.7(;LztTl,.\A5FFKP:QL    	
     
*rc   r   c                4    | dk  ry| dk  ry| dk  ry| dk  ryy	)
Nr  frictionlessg      @low_frictionr9  moderate_frictiong      @high_frictionvery_high_frictionr'  )r   s    rZ   r  r  9  s-    |||"|rc   c                  K   	 ddl m} |rt        |      n	t               }t	        | |||      } |       4 d{   }|j
                  j                  |ddg       d{   }	|	j                  d	d
ddd       d{   }
|
j                          d{   }|j                  dd}|j                  ||       d{   }|	j                          d{    ddd      d{    t        |ddj                         d      S # t        $ r t        d      w xY w7 7 7 7 7 j7 T7 F# 1 d{  7  sw Y   VxY ww)a  
    Run competitive intel against a URL. Returns the full report dict.

    Args:
        url:                  Target competitor URL.
        email_provider_name:  "mailslurp", "agentmail", "inbucket", or None (auto).
        save_screenshots:     Save screenshots to testing/screenshots/competitor_{domain}/.
        email_wait_timeout:   Seconds to wait for verification email.
        headless:             Run browser headlessly.

    Returns:
        Report dict (same as written to testing/reports/).
    r   )async_playwrightzMplaywright is required: pip install playwright && playwright install chromium)r`   r   r   r   Nz---disable-blink-features=AutomationControlledz--no-sandbox)headlessargsi   i   )widthheightzoMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36zen-AU)viewport
user_agentlocaler   )productr   r  zreport not generated)r   result)playwright.async_apir  ImportErrorr   r   chromiumlaunchnew_contextnew_pager   executecloser  to_dict)r`   email_provider_namer   r   r  r  r   agentpwbrowsercontextr   r   r  s                 rZ   run_competitive_intelr  I  sy    (
9 ;N!"56SeSgH!)-	E  !  R**? + 
 
  ++#s31  , 
 
 %%'' ((%

 }}T622mmo3 6 5)/EQWQ_Q_Qa%bccQ  
[
 	



 ( 33   s   ED 1ED%E#D3"D'#D3D)D3D+(D3D-D3D/D3E*D1+"ED""E'D3)D3+D3-D3/D31E3E9D<:EEc                    t        j                  dt         j                  d      } | j                  ddd       | j                  dd g d	d
       | j                  dddd       | j                  dddd       | j                  dddd       | j                  ddd       | j                  dt        dd       | S )Nu;   Competitive Intel — autonomous competitor funnel analysisa  
Examples:
  python testing/competitive_intel.py --url https://competitor.com
  python testing/competitive_intel.py --url https://competitor.com --screenshots --report
  python testing/competitive_intel.py --url https://competitor.com --email-provider mailslurp --no-headless
        )descriptionformatter_classepilogz--urlTzCompetitor URL to analyze)requiredhelpz--email-provider)	mailslurp	agentmailinbucketz2Email provider (auto-detected from env if not set))defaultchoicesr  z--screenshots
store_truez#Save screenshots (default: enabled))actionr  r  z--no-screenshotsstore_falsescreenshotszDisable screenshot capture)r  destr  z--reportz'Generate JSON report (default: enabled)z--no-headlessz*Run browser in visible (non-headless) mode)r  r  z--email-timeoutr  z4Seconds to wait for verification email (default: 90))typer  r  )argparseArgumentParserRawDescriptionHelpFormatteradd_argumentr   )parsers    rZ   _build_cli_parserr    s    $$Q <<	F $5PQ
6A	   d2   =})   <6   9   RC   Mrc   c            	       K   t               } | j                         }t        d|j                          t        d|j                  xs d        t        d|j
                          t        d|j                    d       t        |j                  |j                  |j
                  |j                  |j                          d {   }|j                  di       }|j                  d	i       }t        d
       t        d       t        d       t        d|j                  di       j                  d|j                                t        d|j                  dd              t        d|j                  dd       d       t        d|j                  dd       d       t        d|j                  dd       d|j                  dd       d       t        d|j                  dd              t        d |j                  d!d"              t        d#|j                  d$g               t        d%t        |j                  d&g              d'       |j                  d&      rJ|d&   d d( D ]  }t        d)|         t        |d&         d(kD  rt        d*t        |d&         d(z
   d+       t        d       |j                  di       }|j                  dt        |j                              }|j                  d,t        j                  t        j                        j!                  d-            }t"        d.t        |       d/| d0z  }	|	j%                         rt        d1|	        y t        d2t"                y 7 w)3Nz
[Competitive Intel] Target: z$[Competitive Intel] Email provider: autoz![Competitive Intel] Screenshots: z[Competitive Intel] Headless: 
)r`   r  r   r   r  rv  rw  z=
============================================================zCOMPETITIVE INTEL REPORTz<============================================================zDomain:              ru  rg   zFunnel steps:        ro  ?zTotal time:          rp  rq   zTime to first value: rq  zFriction score:      rr  r|  rs  rC   r   zEmail verification:  r*  zScreenshots taken:   rt  r   zPrices found:        rX  zFeatures found:      rY  z itemsr   z  - z
  ... and z morerk  rh  r   rY   rz  z
Report saved: z
Report dir: )r  
parse_argsprintr`   r   r  no_headlessr  email_timeoutrn   r   rh   r   r}  r   r~  r  r   exists)
r  r  r  rv  rw  fru  rg   r  expected_paths
             rZ   	_cli_mainr    sF     FD	*488*
56	01D1D1N0O
PQ	-d.>.>-?
@A	*t/?/?+?*@
CD(HH //))--%%% F jjB'GjjB'G	/	
$%	(O	!&**VR"8"<"<Xtxx"P!Q
RS	!'++.A3"G!H
IJ	!'++.BC"H!I
KL	!'++.KS"Q!RRS
TU	!'++.>"D!E Fkk0"56a9 :	!'++.KS"Q!R
ST	!'++.A1"E!F
GH	!'++h";!<
=>	!#gkk*b&A"B!C6
JK{{:$Ra( 	AD*	wz"#a'Js7:#67!;<EBC	(O ::fb!DXXhdhh 78F	.(,,x||"<"E"EFV"W	XBKf0E/Fat5"QQM 01{m,-Os   CN	N
J<N__main__)rU   rT   r  r  )r`   rT   r  rT   )rg   rT   r  rT   )r   z
list[dict]r  r  )r   r  r  rT   )NTr  T)r`   rT   r  zOptional[str]r   r  r   r   r  r  r  r  )r  zargparse.ArgumentParserr  )@r  
__future__r   r  r  r  osrM   re   sysr   r   r   pathlibr   typingr   r   urllib.parser	   r
   __file__resolveparent
_REPO_ROOTrT   r   inserttesting.email_agentr   r   r   r   r   testing.scenarios.baser   r   r   r   r   r   r  r  r  SIGNUP_FORM_SELECTORSr  rZ  compiler]  r^  r3  rO   rP   r[   rb   rh   r   r   r  r  r  r  r  r   r'  rc   rZ   <module>r     s  & #    	  	 
  '    *
 (^##%,,33
z?#(("HHOOAs:'  L KCD :;
 $   
 
   "rzz"HI    
"9
,!&P@	L @	F	 $ *.! >d	>d&>d >d 	>d
 >d 
>dJ&R0.f zGKK	 rc   