browser-lens-mcp 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/transport/connector-script.js +215 -215
- package/package.json +1 -1
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
export function getConnectorScript(httpPort, wsPort) {
|
|
2
2
|
return `(function(){
|
|
3
|
-
if(window.__MCP_BROWSER_LENS__){console.log('[
|
|
3
|
+
if(window.__MCP_BROWSER_LENS__){console.log('[BrowserLens] Already active.');return}
|
|
4
4
|
window.__MCP_BROWSER_LENS__=true;
|
|
5
5
|
var WS_URL='ws://localhost:'+${wsPort};
|
|
6
6
|
var HTTP_URL='http://localhost:'+${httpPort}+'/ingest';
|
|
7
|
-
var ws=null,mutQueue=[],
|
|
8
|
-
var SKIP_TAGS={SCRIPT:1,STYLE:1,META:1,LINK:1,NOSCRIPT:1,BR:1};
|
|
9
|
-
var CSS_PROPS=['color','backgroundColor','fontSize','fontFamily','fontWeight','fontStyle','lineHeight','letterSpacing','textAlign','textDecoration','textTransform','display','position','top','right','bottom','left','width','height','minWidth','minHeight','maxWidth','maxHeight','margin','marginTop','marginRight','marginBottom','marginLeft','padding','paddingTop','paddingRight','paddingBottom','paddingLeft','
|
|
7
|
+
var ws=null,mutQueue=[],sendQueue=[];
|
|
8
|
+
var SKIP_TAGS={SCRIPT:1,STYLE:1,META:1,LINK:1,NOSCRIPT:1,BR:1,TEMPLATE:1};
|
|
9
|
+
var CSS_PROPS=['color','backgroundColor','fontSize','fontFamily','fontWeight','fontStyle','lineHeight','letterSpacing','textAlign','textDecoration','textTransform','display','position','top','right','bottom','left','width','height','minWidth','minHeight','maxWidth','maxHeight','margin','marginTop','marginRight','marginBottom','marginLeft','padding','paddingTop','paddingRight','paddingBottom','paddingLeft','borderWidth','borderStyle','borderColor','borderRadius','borderTopLeftRadius','borderTopRightRadius','borderBottomLeftRadius','borderBottomRightRadius','overflow','overflowX','overflowY','opacity','visibility','zIndex','transform','transition','animation','boxShadow','cursor','flexDirection','flexWrap','justifyContent','alignItems','alignSelf','flexGrow','flexShrink','flexBasis','gap','gridTemplateColumns','gridTemplateRows','gridColumn','gridRow','whiteSpace','wordBreak','textOverflow','outline','backgroundImage','backgroundSize','backgroundPosition','backgroundRepeat','float','clear','verticalAlign','listStyleType','boxSizing'];
|
|
10
|
+
|
|
11
|
+
function log(msg){console.log('[BrowserLens] '+msg);}
|
|
12
|
+
function err(msg,e){console.error('[BrowserLens] '+msg,e||'');}
|
|
10
13
|
|
|
11
14
|
function buildSelector(el){
|
|
15
|
+
if(!el||!el.tagName)return'unknown';
|
|
12
16
|
if(el.id)return'#'+el.id;
|
|
13
17
|
var s=el.tagName.toLowerCase();
|
|
14
18
|
if(el.className&&typeof el.className==='string'){
|
|
15
|
-
var cls=el.className.trim().split(/\\s+/).slice(0,3).join('.');
|
|
19
|
+
var cls=el.className.trim().split(/\\s+/).filter(Boolean).slice(0,3).join('.');
|
|
16
20
|
if(cls)s+='.'+cls;
|
|
17
21
|
}
|
|
18
22
|
var p=el.parentElement;
|
|
19
23
|
if(p&&p!==document.documentElement&&p!==document.body){
|
|
20
|
-
var
|
|
21
|
-
if(
|
|
22
|
-
var idx=
|
|
23
|
-
s+=':nth-child('+(idx+1)+')';
|
|
24
|
+
var siblings=Array.from(p.children).filter(function(c){return c.tagName===el.tagName});
|
|
25
|
+
if(siblings.length>1){
|
|
26
|
+
var idx=siblings.indexOf(el);
|
|
27
|
+
if(idx>=0)s+=':nth-child('+(idx+1)+')';
|
|
24
28
|
}
|
|
25
29
|
}
|
|
26
30
|
return s;
|
|
@@ -31,149 +35,123 @@ function captureDomNode(el,depth,maxDepth){
|
|
|
31
35
|
var tag=el.tagName;
|
|
32
36
|
if(SKIP_TAGS[tag])return null;
|
|
33
37
|
var attrs={};
|
|
34
|
-
for(var i=0;i<el.attributes.length;i++){
|
|
35
|
-
var a=el.attributes[i];
|
|
36
|
-
attrs[a.name]=a.value.slice(0,200);
|
|
37
|
-
}
|
|
38
|
+
try{for(var i=0;i<Math.min(el.attributes.length,20);i++){var a=el.attributes[i];attrs[a.name]=a.value.slice(0,200);}}catch(e){}
|
|
38
39
|
var children=[];
|
|
39
40
|
if(depth<maxDepth){
|
|
40
41
|
var ch=el.children;
|
|
41
|
-
for(var j=0;j<Math.min(ch.length,
|
|
42
|
+
for(var j=0;j<Math.min(ch.length,40);j++){
|
|
42
43
|
var c=captureDomNode(ch[j],depth+1,maxDepth);
|
|
43
44
|
if(c)children.push(c);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
|
-
var text=
|
|
47
|
-
if(text.length>200)text=text.slice(0,200)+'...';
|
|
48
|
-
if(children.length>0)text='';
|
|
47
|
+
var text='';
|
|
48
|
+
try{text=el.textContent||'';if(text.length>200)text=text.slice(0,200)+'...';if(children.length>0)text='';}catch(e){}
|
|
49
49
|
return{
|
|
50
|
-
selector:buildSelector(el),
|
|
51
|
-
tagName:tag.toLowerCase(),
|
|
52
|
-
id:el.id||'',
|
|
50
|
+
selector:buildSelector(el),tagName:tag.toLowerCase(),id:el.id||'',
|
|
53
51
|
classNames:el.className&&typeof el.className==='string'?el.className.trim().split(/\\s+/).filter(Boolean):[],
|
|
54
|
-
attributes:attrs,
|
|
55
|
-
|
|
56
|
-
innerHTML:'',
|
|
57
|
-
outerHTML:'',
|
|
58
|
-
childCount:el.children.length,
|
|
59
|
-
children:children,
|
|
60
|
-
depth:depth
|
|
52
|
+
attributes:attrs,textContent:text,innerHTML:'',outerHTML:'',
|
|
53
|
+
childCount:el.children.length,children:children,depth:depth
|
|
61
54
|
};
|
|
62
55
|
}
|
|
63
56
|
|
|
64
57
|
function captureDom(){
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
try{
|
|
59
|
+
var root=captureDomNode(document.documentElement,0,8);
|
|
60
|
+
if(!root)return null;
|
|
61
|
+
var total=document.querySelectorAll('*').length;
|
|
62
|
+
var semantic=[];
|
|
63
|
+
['header','nav','main','aside','footer','section','article','form'].forEach(function(tag){
|
|
64
|
+
document.querySelectorAll(tag).forEach(function(el){
|
|
65
|
+
semantic.push({tag:tag,role:el.getAttribute('role')||'',label:el.getAttribute('aria-label')||'',selector:buildSelector(el),children:[]});
|
|
66
|
+
});
|
|
73
67
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
doctype:document.doctype?document.doctype.name:'html',
|
|
83
|
-
charset:document.characterSet,
|
|
84
|
-
viewport:{width:window.innerWidth,height:window.innerHeight,scrollX:window.scrollX,scrollY:window.scrollY,devicePixelRatio:window.devicePixelRatio,scrollWidth:document.documentElement.scrollWidth,scrollHeight:document.documentElement.scrollHeight},
|
|
85
|
-
rootElement:root,
|
|
86
|
-
totalElements:total,
|
|
87
|
-
semanticStructure:semantic
|
|
88
|
-
};
|
|
68
|
+
document.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach(function(el){
|
|
69
|
+
semantic.push({tag:el.tagName.toLowerCase(),level:parseInt(el.tagName[1]),label:(el.textContent||'').slice(0,100),selector:buildSelector(el),children:[]});
|
|
70
|
+
});
|
|
71
|
+
log('DOM captured: '+total+' elements');
|
|
72
|
+
return{timestamp:Date.now(),url:location.href,title:document.title,doctype:'html',charset:document.characterSet,
|
|
73
|
+
viewport:{width:window.innerWidth,height:window.innerHeight,scrollX:window.scrollX,scrollY:window.scrollY,devicePixelRatio:window.devicePixelRatio,scrollWidth:document.documentElement.scrollWidth,scrollHeight:document.documentElement.scrollHeight},
|
|
74
|
+
rootElement:root,totalElements:total,semanticStructure:semantic};
|
|
75
|
+
}catch(e){err('DOM capture failed',e);return null;}
|
|
89
76
|
}
|
|
90
77
|
|
|
91
78
|
function captureElementDetail(el){
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
layout.flexInfo={direction:cs.flexDirection,wrap:cs.flexWrap,justifyContent:cs.justifyContent,alignItems:cs.alignItems,gap:cs.gap,children:[]};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
return{snapshot:snap,computedStyle:{selector:sel,tagName:el.tagName.toLowerCase(),styles:styles,appliedClasses:el.className&&typeof el.className==='string'?el.className.trim().split(/\\s+/).filter(Boolean):[],matchedRules:[]},layout:layout,accessibility:acc};
|
|
79
|
+
try{
|
|
80
|
+
var sel=buildSelector(el);
|
|
81
|
+
var cs=getComputedStyle(el);
|
|
82
|
+
var styles={};
|
|
83
|
+
CSS_PROPS.forEach(function(p){try{styles[p]=cs.getPropertyValue(p.replace(/[A-Z]/g,function(m){return'-'+m.toLowerCase()}))||cs[p]||'';}catch(e){styles[p]='';}});
|
|
84
|
+
var rect=el.getBoundingClientRect();
|
|
85
|
+
var layout={
|
|
86
|
+
selector:sel,tagName:el.tagName.toLowerCase(),
|
|
87
|
+
box:{width:rect.width,height:rect.height,padding:{top:parseFloat(cs.paddingTop)||0,right:parseFloat(cs.paddingRight)||0,bottom:parseFloat(cs.paddingBottom)||0,left:parseFloat(cs.paddingLeft)||0},margin:{top:parseFloat(cs.marginTop)||0,right:parseFloat(cs.marginRight)||0,bottom:parseFloat(cs.marginBottom)||0,left:parseFloat(cs.marginLeft)||0},border:{top:parseFloat(cs.borderTopWidth)||0,right:parseFloat(cs.borderRightWidth)||0,bottom:parseFloat(cs.borderBottomWidth)||0,left:parseFloat(cs.borderLeftWidth)||0},contentWidth:Math.max(0,rect.width-(parseFloat(cs.paddingLeft)||0)-(parseFloat(cs.paddingRight)||0)-(parseFloat(cs.borderLeftWidth)||0)-(parseFloat(cs.borderRightWidth)||0)),contentHeight:Math.max(0,rect.height-(parseFloat(cs.paddingTop)||0)-(parseFloat(cs.paddingBottom)||0)-(parseFloat(cs.borderTopWidth)||0)-(parseFloat(cs.borderBottomWidth)||0))},
|
|
88
|
+
position:{type:cs.position,top:rect.top,left:rect.left,right:rect.right,bottom:rect.bottom,offsetParent:el.offsetParent?buildSelector(el.offsetParent):'',boundingRect:{x:rect.x,y:rect.y,width:rect.width,height:rect.height}},
|
|
89
|
+
display:cs.display,overflow:{x:cs.overflowX,y:cs.overflowY},zIndex:cs.zIndex,transform:cs.transform,opacity:cs.opacity,visibility:cs.visibility
|
|
90
|
+
};
|
|
91
|
+
if(cs.display==='flex'||cs.display==='inline-flex')layout.flexInfo={direction:cs.flexDirection,wrap:cs.flexWrap,justifyContent:cs.justifyContent,alignItems:cs.alignItems,gap:cs.gap,children:[]};
|
|
92
|
+
if(cs.display==='grid'||cs.display==='inline-grid')layout.gridInfo={templateColumns:cs.gridTemplateColumns,templateRows:cs.gridTemplateRows,gap:cs.gap,areas:cs.gridTemplateAreas,children:[]};
|
|
93
|
+
var snap=captureDomNode(el,0,2);
|
|
94
|
+
var acc=null;
|
|
95
|
+
if(el.getAttribute('role')||el.getAttribute('aria-label')||el.tabIndex>=0){
|
|
96
|
+
acc={selector:sel,tagName:el.tagName.toLowerCase(),role:el.getAttribute('role')||undefined,ariaLabel:el.getAttribute('aria-label')||undefined,ariaDescribedBy:el.getAttribute('aria-describedby')||undefined,ariaHidden:el.getAttribute('aria-hidden')==='true',tabIndex:el.tabIndex,altText:el.getAttribute('alt')||undefined,hasLabel:!!(el.getAttribute('aria-label')||el.getAttribute('title')),issues:[]};
|
|
97
|
+
}
|
|
98
|
+
return{snapshot:snap,computedStyle:{selector:sel,tagName:el.tagName.toLowerCase(),styles:styles,appliedClasses:el.className&&typeof el.className==='string'?el.className.trim().split(/\\s+/).filter(Boolean):[],matchedRules:[]},layout:layout,accessibility:acc};
|
|
99
|
+
}catch(e){err('Element detail failed for '+buildSelector(el),e);return null;}
|
|
115
100
|
}
|
|
116
101
|
|
|
117
102
|
function captureTopElements(){
|
|
118
103
|
var elements={};
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if(count>=30)break;
|
|
130
|
-
if(!SKIP_TAGS[ch[i].tagName]){
|
|
131
|
-
var csel=buildSelector(ch[i]);
|
|
132
|
-
elements[csel]=captureElementDetail(ch[i]);
|
|
133
|
-
count++;
|
|
104
|
+
try{
|
|
105
|
+
var els=document.querySelectorAll('body > *');
|
|
106
|
+
var count=0;
|
|
107
|
+
function addEl(el){
|
|
108
|
+
if(count>=30||SKIP_TAGS[el.tagName])return;
|
|
109
|
+
var d=captureElementDetail(el);
|
|
110
|
+
if(d){elements[buildSelector(el)]=d;count++;}
|
|
111
|
+
var ch=el.children;
|
|
112
|
+
for(var i=0;i<Math.min(ch.length,5)&&count<30;i++){
|
|
113
|
+
if(!SKIP_TAGS[ch[i].tagName]){var cd=captureElementDetail(ch[i]);if(cd){elements[buildSelector(ch[i])]=cd;count++;}}
|
|
134
114
|
}
|
|
135
115
|
}
|
|
136
|
-
|
|
137
|
-
|
|
116
|
+
for(var i=0;i<els.length;i++)addEl(els[i]);
|
|
117
|
+
log('Elements captured: '+count);
|
|
118
|
+
}catch(e){err('Top elements capture failed',e);}
|
|
138
119
|
return elements;
|
|
139
120
|
}
|
|
140
121
|
|
|
141
122
|
function captureCssVars(){
|
|
142
123
|
var vars={},count=0;
|
|
143
|
-
var cs=getComputedStyle(document.documentElement);
|
|
144
|
-
for(var i=0;i<cs.length;i++){
|
|
145
|
-
if(cs[i].startsWith('--')){vars[cs[i]]=cs.getPropertyValue(cs[i]).trim();count++;}
|
|
146
|
-
}
|
|
147
|
-
var sheets=document.styleSheets;
|
|
148
124
|
try{
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
for(var r=0;r<rules.length;r++){
|
|
153
|
-
if(rules[r].style){
|
|
154
|
-
for(var p=0;p<rules[r].style.length;p++){
|
|
155
|
-
var prop=rules[r].style[p];
|
|
156
|
-
if(prop.startsWith('--')&&!vars[prop]){vars[prop]=rules[r].style.getPropertyValue(prop).trim();count++;}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
}catch(e){}
|
|
125
|
+
var cs=getComputedStyle(document.documentElement);
|
|
126
|
+
for(var i=0;i<cs.length;i++){
|
|
127
|
+
if(cs[i].startsWith('--')){vars[cs[i]]=cs.getPropertyValue(cs[i]).trim();count++;}
|
|
161
128
|
}
|
|
162
|
-
|
|
129
|
+
try{
|
|
130
|
+
var sheets=document.styleSheets;
|
|
131
|
+
for(var s=0;s<sheets.length;s++){
|
|
132
|
+
try{var rules=sheets[s].cssRules;if(!rules)continue;
|
|
133
|
+
for(var r=0;r<rules.length;r++){if(rules[r].style){for(var p=0;p<rules[r].style.length;p++){var prop=rules[r].style[p];if(prop.startsWith('--')&&!vars[prop]){vars[prop]=rules[r].style.getPropertyValue(prop).trim();count++;}}}}
|
|
134
|
+
}catch(e){}
|
|
135
|
+
}
|
|
136
|
+
}catch(e){}
|
|
137
|
+
log('CSS vars captured: '+count);
|
|
138
|
+
}catch(e){err('CSS vars failed',e);}
|
|
163
139
|
return{timestamp:Date.now(),variables:vars,totalCount:count};
|
|
164
140
|
}
|
|
165
141
|
|
|
166
142
|
function captureTypography(){
|
|
167
|
-
var
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
var
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
143
|
+
var fontMap={};
|
|
144
|
+
try{
|
|
145
|
+
var textEls=document.querySelectorAll('p,h1,h2,h3,h4,h5,h6,span,a,li,td,th,label,button,input,textarea,div');
|
|
146
|
+
for(var i=0;i<Math.min(textEls.length,200);i++){
|
|
147
|
+
var el=textEls[i];
|
|
148
|
+
if(!el.textContent||!el.textContent.trim())continue;
|
|
149
|
+
var cs=getComputedStyle(el);
|
|
150
|
+
var key=cs.fontFamily+'|'+cs.fontSize+'|'+cs.fontWeight+'|'+cs.lineHeight;
|
|
151
|
+
if(!fontMap[key])fontMap[key]={family:cs.fontFamily,size:cs.fontSize,weight:cs.fontWeight,lineHeight:cs.lineHeight,color:cs.color,selector:buildSelector(el),count:0};
|
|
152
|
+
fontMap[key].count++;
|
|
153
|
+
}
|
|
154
|
+
}catch(e){err('Typography failed',e);}
|
|
177
155
|
return{timestamp:Date.now(),fonts:Object.values(fontMap).sort(function(a,b){return b.count-a.count}),fontFaces:[]};
|
|
178
156
|
}
|
|
179
157
|
|
|
@@ -187,21 +165,15 @@ function rgbToHex(rgb){
|
|
|
187
165
|
|
|
188
166
|
function captureColors(){
|
|
189
167
|
var colorMap={},bgMap={},borderMap={};
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
var
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if(!val||val==='transparent'||val==='rgba(0, 0, 0, 0)')return;
|
|
196
|
-
|
|
197
|
-
if(!map[hex])map[hex]={value:val,hex:hex,count:0,elements:[]};
|
|
198
|
-
map[hex].count++;
|
|
199
|
-
if(map[hex].elements.length<5)map[hex].elements.push(sel);
|
|
168
|
+
try{
|
|
169
|
+
var els=document.querySelectorAll('*');
|
|
170
|
+
for(var i=0;i<Math.min(els.length,300);i++){
|
|
171
|
+
var cs=getComputedStyle(els[i]);
|
|
172
|
+
var sel=buildSelector(els[i]);
|
|
173
|
+
function addC(map,val){if(!val||val==='transparent'||val==='rgba(0, 0, 0, 0)')return;var hex=rgbToHex(val);if(!map[hex])map[hex]={value:val,hex:hex,count:0,elements:[]};map[hex].count++;if(map[hex].elements.length<5)map[hex].elements.push(sel);}
|
|
174
|
+
addC(colorMap,cs.color);addC(bgMap,cs.backgroundColor);addC(borderMap,cs.borderColor);
|
|
200
175
|
}
|
|
201
|
-
|
|
202
|
-
addColor(bgMap,cs.backgroundColor);
|
|
203
|
-
addColor(borderMap,cs.borderColor);
|
|
204
|
-
}
|
|
176
|
+
}catch(e){err('Colors failed',e);}
|
|
205
177
|
var all=Object.assign({},colorMap,bgMap,borderMap);
|
|
206
178
|
return{timestamp:Date.now(),colors:Object.values(colorMap).sort(function(a,b){return b.count-a.count}),backgroundColors:Object.values(bgMap).sort(function(a,b){return b.count-a.count}),borderColors:Object.values(borderMap).sort(function(a,b){return b.count-a.count}),totalUniqueColors:Object.keys(all).length};
|
|
207
179
|
}
|
|
@@ -209,99 +181,127 @@ function captureColors(){
|
|
|
209
181
|
function captureAccessibility(){
|
|
210
182
|
var elements=[];
|
|
211
183
|
var summary={totalInteractive:0,withLabels:0,withoutLabels:0,imagesWithAlt:0,imagesWithoutAlt:0,headingLevels:{},landmarks:[],issues:[]};
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
var
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if(img.alt)summary.imagesWithAlt++;else{summary.imagesWithoutAlt++;summary.issues.push('Image without alt: '+buildSelector(img));}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
summary.headingLevels[lv]=(summary.headingLevels[lv]||0)+1;
|
|
226
|
-
});
|
|
227
|
-
['banner','navigation','main','complementary','contentinfo'].forEach(function(r){
|
|
228
|
-
var el=document.querySelector('[role="'+r+'"]');
|
|
229
|
-
if(el)summary.landmarks.push(r);
|
|
230
|
-
});
|
|
184
|
+
try{
|
|
185
|
+
var interactive=document.querySelectorAll('a,button,input,select,textarea,[tabindex],[role]');
|
|
186
|
+
summary.totalInteractive=interactive.length;
|
|
187
|
+
for(var i=0;i<Math.min(interactive.length,100);i++){
|
|
188
|
+
var el=interactive[i];
|
|
189
|
+
var hasLabel=!!(el.getAttribute('aria-label')||el.getAttribute('title')||(el.textContent||'').trim());
|
|
190
|
+
if(hasLabel)summary.withLabels++;else{summary.withoutLabels++;summary.issues.push('Missing label: '+buildSelector(el));}
|
|
191
|
+
elements.push({selector:buildSelector(el),tagName:el.tagName.toLowerCase(),role:el.getAttribute('role')||undefined,ariaLabel:el.getAttribute('aria-label')||undefined,tabIndex:el.tabIndex,hasLabel:hasLabel,issues:hasLabel?[]:['Missing accessible label']});
|
|
192
|
+
}
|
|
193
|
+
document.querySelectorAll('img').forEach(function(img){if(img.alt)summary.imagesWithAlt++;else{summary.imagesWithoutAlt++;summary.issues.push('Image without alt: '+buildSelector(img));}});
|
|
194
|
+
document.querySelectorAll('h1,h2,h3,h4,h5,h6').forEach(function(h){var lv=h.tagName;summary.headingLevels[lv]=(summary.headingLevels[lv]||0)+1;});
|
|
195
|
+
['banner','navigation','main','complementary','contentinfo'].forEach(function(r){if(document.querySelector('[role="'+r+'"]'))summary.landmarks.push(r);});
|
|
196
|
+
}catch(e){err('Accessibility failed',e);}
|
|
231
197
|
return{timestamp:Date.now(),elements:elements.slice(0,100),summary:summary};
|
|
232
198
|
}
|
|
233
199
|
|
|
234
200
|
function captureResponsive(){
|
|
235
201
|
var bps=[{q:'(max-width: 319px)',matches:false},{q:'(min-width: 320px) and (max-width: 374px)',matches:false},{q:'(min-width: 375px) and (max-width: 767px)',matches:false},{q:'(min-width: 768px) and (max-width: 1023px)',matches:false},{q:'(min-width: 1024px) and (max-width: 1279px)',matches:false},{q:'(min-width: 1280px) and (max-width: 1439px)',matches:false},{q:'(min-width: 1440px)',matches:false}];
|
|
236
202
|
var active=[];
|
|
237
|
-
bps.forEach(function(bp){
|
|
238
|
-
bp.matches=window.matchMedia(bp.q).matches;
|
|
239
|
-
if(bp.matches)active.push(bp.q);
|
|
240
|
-
});
|
|
203
|
+
bps.forEach(function(bp){bp.matches=window.matchMedia(bp.q).matches;if(bp.matches)active.push(bp.q);});
|
|
241
204
|
return{viewport:{width:window.innerWidth,height:window.innerHeight,scrollX:window.scrollX,scrollY:window.scrollY,devicePixelRatio:window.devicePixelRatio,scrollWidth:document.documentElement.scrollWidth,scrollHeight:document.documentElement.scrollHeight},activeMediaQueries:active,breakpoints:bps};
|
|
242
205
|
}
|
|
243
206
|
|
|
244
207
|
function captureSpacing(){
|
|
245
|
-
var entries=[];
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return{timestamp:Date.now(),elements:entries,inconsistencies:[],spacingScale:scale};
|
|
208
|
+
var entries=[],vals={margin:{},padding:{}};
|
|
209
|
+
try{
|
|
210
|
+
var els=document.querySelectorAll('body *');
|
|
211
|
+
for(var i=0;i<Math.min(els.length,50);i++){
|
|
212
|
+
var el=els[i];if(SKIP_TAGS[el.tagName])continue;
|
|
213
|
+
var cs=getComputedStyle(el);
|
|
214
|
+
var m={top:parseFloat(cs.marginTop)||0,right:parseFloat(cs.marginRight)||0,bottom:parseFloat(cs.marginBottom)||0,left:parseFloat(cs.marginLeft)||0};
|
|
215
|
+
var p={top:parseFloat(cs.paddingTop)||0,right:parseFloat(cs.paddingRight)||0,bottom:parseFloat(cs.paddingBottom)||0,left:parseFloat(cs.paddingLeft)||0};
|
|
216
|
+
entries.push({selector:buildSelector(el),margin:m,padding:p,gap:cs.gap||undefined});
|
|
217
|
+
[m.top,m.right,m.bottom,m.left].forEach(function(v){if(v>0)vals.margin[v+'px']=(vals.margin[v+'px']||0)+1;});
|
|
218
|
+
[p.top,p.right,p.bottom,p.left].forEach(function(v){if(v>0)vals.padding[v+'px']=(vals.padding[v+'px']||0)+1;});
|
|
219
|
+
}
|
|
220
|
+
}catch(e){err('Spacing failed',e);}
|
|
221
|
+
return{timestamp:Date.now(),elements:entries,inconsistencies:[],spacingScale:Object.keys(Object.assign({},vals.margin,vals.padding)).sort(function(a,b){return parseFloat(a)-parseFloat(b)})};
|
|
260
222
|
}
|
|
261
223
|
|
|
224
|
+
var _ssLastOk=0,_ssFailing=false;
|
|
225
|
+
function _doCapture(opts){
|
|
226
|
+
var w=Math.min(window.innerWidth,1440),h=Math.min(window.innerHeight,900);
|
|
227
|
+
return html2canvas(document.body,Object.assign({scale:1,width:w,height:h,logging:false,removeContainer:true,imageTimeout:5000},opts)).then(function(canvas){
|
|
228
|
+
var dataUrl=canvas.toDataURL('image/png');
|
|
229
|
+
_ssLastOk=Date.now();_ssFailing=false;
|
|
230
|
+
log('Screenshot OK: '+canvas.width+'x'+canvas.height);
|
|
231
|
+
return{timestamp:Date.now(),type:'viewport',width:canvas.width,height:canvas.height,dataUrl:dataUrl,format:'png'};
|
|
232
|
+
});
|
|
233
|
+
}
|
|
262
234
|
function captureScreenshot(){
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
235
|
+
if(_ssFailing&&Date.now()-_ssLastOk<120000)return Promise.resolve(null);
|
|
236
|
+
return new Promise(function(resolve){
|
|
237
|
+
function run(){
|
|
238
|
+
_doCapture({useCORS:true,allowTaint:false,foreignObjectRendering:false}).then(resolve)
|
|
239
|
+
.catch(function(){
|
|
240
|
+
log('Retrying screenshot without cross-origin images...');
|
|
241
|
+
_doCapture({useCORS:false,allowTaint:false,foreignObjectRendering:false,ignoreElements:function(el){
|
|
242
|
+
if(el.tagName==='IMG'){var s=el.src||'';if(s&&!s.startsWith(location.origin)&&!s.startsWith('data:'))return true;}
|
|
243
|
+
return false;
|
|
244
|
+
}}).then(resolve)
|
|
245
|
+
.catch(function(e){
|
|
246
|
+
_ssFailing=true;
|
|
247
|
+
err('Screenshot failed (will retry in 2min)',e);
|
|
248
|
+
resolve(null);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
try{
|
|
253
|
+
if(typeof html2canvas==='function'){run();}
|
|
254
|
+
else{
|
|
255
|
+
log('Loading html2canvas...');
|
|
256
|
+
var s=document.createElement('script');
|
|
257
|
+
s.src='https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js';
|
|
258
|
+
s.onload=function(){log('html2canvas ready');run();};
|
|
259
|
+
s.onerror=function(){err('CDN load failed');resolve(null);};
|
|
260
|
+
document.head.appendChild(s);
|
|
261
|
+
}
|
|
262
|
+
}catch(e){err('Screenshot error',e);resolve(null);}
|
|
263
|
+
});
|
|
283
264
|
}
|
|
284
265
|
|
|
285
|
-
function
|
|
286
|
-
var
|
|
287
|
-
var
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
captureScreenshot().then(function(shot){
|
|
298
|
-
if(shot)send(JSON.stringify({timestamp:Date.now(),screenshots:[shot]}));
|
|
299
|
-
});
|
|
266
|
+
function send(data){
|
|
267
|
+
var payload=typeof data==='string'?data:JSON.stringify(data);
|
|
268
|
+
var size=payload.length;
|
|
269
|
+
if(ws&&ws.readyState===1){
|
|
270
|
+
try{ws.send(payload);return true;}catch(e){err('WS send failed ('+size+' bytes)',e);}
|
|
271
|
+
}
|
|
272
|
+
try{
|
|
273
|
+
return fetch(HTTP_URL,{method:'POST',headers:{'Content-Type':'application/json'},body:payload,keepalive:size<60000}).then(function(r){
|
|
274
|
+
if(!r.ok)err('HTTP send failed: '+r.status);
|
|
275
|
+
return r.ok;
|
|
276
|
+
}).catch(function(e){err('HTTP send error',e);return false;});
|
|
277
|
+
}catch(e){err('Send failed completely',e);return false;}
|
|
300
278
|
}
|
|
301
279
|
|
|
302
|
-
function
|
|
303
|
-
|
|
304
|
-
|
|
280
|
+
function fullSync(){
|
|
281
|
+
try{
|
|
282
|
+
log('Syncing...');
|
|
283
|
+
var dom=captureDom();
|
|
284
|
+
var elements=captureTopElements();
|
|
285
|
+
var cssVars=captureCssVars();
|
|
286
|
+
var typo=captureTypography();
|
|
287
|
+
var colors=captureColors();
|
|
288
|
+
var acc=captureAccessibility();
|
|
289
|
+
var resp=captureResponsive();
|
|
290
|
+
var spacing=captureSpacing();
|
|
291
|
+
var muts=mutQueue.splice(0);
|
|
292
|
+
var payload={timestamp:Date.now(),url:location.href,userAgent:navigator.userAgent,dom:dom,elements:elements,cssVariables:cssVars,typography:typo,colors:colors,accessibility:acc,responsive:resp,spacing:spacing};
|
|
293
|
+
if(muts.length)payload.mutations=muts;
|
|
294
|
+
send(payload);
|
|
295
|
+
captureScreenshot().then(function(shot){
|
|
296
|
+
if(shot){
|
|
297
|
+
log('Sending screenshot ('+shot.width+'x'+shot.height+')...');
|
|
298
|
+
send({timestamp:Date.now(),screenshots:[shot]});
|
|
299
|
+
}else{
|
|
300
|
+
err('Screenshot was null - check browser console for html2canvas errors');
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
log('Sync complete');
|
|
304
|
+
}catch(e){err('fullSync failed',e);}
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
try{
|
|
@@ -317,20 +317,20 @@ try{
|
|
|
317
317
|
});
|
|
318
318
|
});
|
|
319
319
|
observer.observe(document.documentElement,{childList:true,attributes:true,subtree:true,attributeOldValue:true});
|
|
320
|
-
}catch(e){}
|
|
320
|
+
}catch(e){err('MutationObserver failed',e);}
|
|
321
321
|
|
|
322
322
|
function connectWs(){
|
|
323
323
|
try{
|
|
324
324
|
ws=new WebSocket(WS_URL);
|
|
325
|
-
ws.onopen=function(){
|
|
326
|
-
ws.onclose=function(){ws=null;setTimeout(connectWs,5000);};
|
|
327
|
-
ws.onerror=function(){try{ws.close();}catch(
|
|
328
|
-
}catch(e){setTimeout(connectWs,5000);}
|
|
325
|
+
ws.onopen=function(){log('WebSocket connected to '+WS_URL);fullSync();};
|
|
326
|
+
ws.onclose=function(){ws=null;log('WebSocket closed, reconnecting in 5s...');setTimeout(connectWs,5000);};
|
|
327
|
+
ws.onerror=function(e){err('WebSocket error',e);try{ws.close();}catch(ex){}};
|
|
328
|
+
}catch(e){err('WebSocket connect failed',e);setTimeout(connectWs,5000);}
|
|
329
329
|
}
|
|
330
330
|
connectWs();
|
|
331
331
|
setInterval(fullSync,15000);
|
|
332
|
-
window.addEventListener('beforeunload',function(){
|
|
333
|
-
|
|
332
|
+
window.addEventListener('beforeunload',function(){try{var payload=JSON.stringify({timestamp:Date.now(),url:location.href});if(navigator.sendBeacon)navigator.sendBeacon(HTTP_URL,payload);}catch(e){}});
|
|
333
|
+
log('Initialized! Connecting to '+WS_URL+'...');
|
|
334
334
|
})()`;
|
|
335
335
|
}
|
|
336
336
|
//# sourceMappingURL=connector-script.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "browser-lens-mcp",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "MCP server that connects to your browser for real-time DOM, CSS, layout inspection, screenshot capture, and Figma design comparison — your IDE's AI agent sees exactly what users see",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|