@feimacode/open-design-agent-kit-mcp 0.4.0-beta.1 → 0.4.0-beta.3

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.
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{function re(t){let o=t.findings.length;if(o===0)return`Second look: ${t.verdict}`;let r=t.verdict==="ship"?o===1?"note":"notes":o===1?"fix":"fixes";return`Second look: ${t.verdict}, ${o} ${r}`}function A(t,o){let r=t.getBoundingClientRect();return{left:r.left+o.left,top:r.top+o.top,width:o.width,height:o.height}}function j(t,o){let r=document.createElement("div");return r.className=o,r.style.left=`${t.left}px`,r.style.top=`${t.top}px`,r.style.width=`${t.width}px`,r.style.height=`${t.height}px`,r}function se(t,o){let r=t.getBoundingClientRect(),i=p=>{let m=document.createElement("div");return m.className="od-guide-line od-guide-h",m.style.left=`${r.left}px`,m.style.top=`${p}px`,m.style.width=`${r.width}px`,m},y=p=>{let m=document.createElement("div");return m.className="od-guide-line od-guide-v",m.style.top=`${r.top}px`,m.style.left=`${p}px`,m.style.height=`${r.height}px`,m};return[i(o.top),i(o.top+o.height),y(o.left),y(o.left+o.width)]}function a(t){return t.replace(/[&<>"']/g,o=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[o])}function be(){return`c-${Math.random().toString(36).slice(2,10)}`}function we(t,o,r,i=new Date().toISOString()){return{id:be(),...t.sourceElementId?{elementId:t.sourceElementId}:{},selector:t.selector,htmlHint:t.htmlHint,note:o,status:"open",createdAt:i,updatedAt:i,text:t.textExcerpt||void 0,rect:{x:Math.round(t.docRect.left),y:Math.round(t.docRect.top),width:Math.round(t.docRect.width),height:Math.round(t.docRect.height)},viewport:t.viewport,host:r}}function de(t){let{panel:o,iframe:r}=t,i=[],y=(d,c=[])=>{t.persist(d,c),t.onListChanged()},p=d=>{o.hidden=!1,o.innerHTML=`
1
+ "use strict";(()=>{function se(t){let n=t.findings.length;if(n===0)return`Second look: ${t.verdict}`;let o=t.verdict==="ship"?n===1?"note":"notes":n===1?"fix":"fixes";return`Second look: ${t.verdict}, ${n} ${o}`}function _(t,n){let o=t.getBoundingClientRect();return{left:o.left+n.left,top:o.top+n.top,width:n.width,height:n.height}}function V(t,n){let o=document.createElement("div");return o.className=n,o.style.left=`${t.left}px`,o.style.top=`${t.top}px`,o.style.width=`${t.width}px`,o.style.height=`${t.height}px`,o}function de(t,n){let o=t.getBoundingClientRect(),s=l=>{let p=document.createElement("div");return p.className="od-guide-line od-guide-h",p.style.left=`${o.left}px`,p.style.top=`${l}px`,p.style.width=`${o.width}px`,p},x=l=>{let p=document.createElement("div");return p.className="od-guide-line od-guide-v",p.style.top=`${o.top}px`,p.style.left=`${l}px`,p.style.height=`${o.height}px`,p};return[s(n.top),s(n.top+n.height),x(n.left),x(n.left+n.width)]}function c(t){return t.replace(/[&<>"']/g,n=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[n])}function xe(){return`c-${Math.random().toString(36).slice(2,10)}`}function we(t,n,o,s=new Date().toISOString()){return{id:xe(),...t.sourceElementId?{elementId:t.sourceElementId}:{},selector:t.selector,htmlHint:t.htmlHint,note:n,status:"open",createdAt:s,updatedAt:s,text:t.textExcerpt||void 0,rect:{x:Math.round(t.docRect.left),y:Math.round(t.docRect.top),width:Math.round(t.docRect.width),height:Math.round(t.docRect.height)},viewport:t.viewport,host:o}}function ae(t){let{panel:n,iframe:o}=t,s=[],x=(r,a=[])=>{t.persist(r,a),t.onListChanged()},l=r=>{n.hidden=!1,n.innerHTML=`
2
2
  <div class="od-panel-header">
3
3
  <span class="od-panel-header-title">Add comment</span>
4
4
  <button id="od-comment-close" class="od-panel-close" aria-label="Close">\xD7</button>
@@ -11,37 +11,38 @@
11
11
  <button id="od-comment-cancel" class="od-btn">Cancel</button>
12
12
  <button id="od-comment-save" class="od-btn od-btn-primary">Add</button>
13
13
  </div>
14
- `;let c=document.getElementById("od-comment-text");c.focus();let u=()=>{let h=c.value.trim();if(!h)return;let g=we(d,h,t.host);i.push(g),y([g]),t.closePanel(),t.onAdded?.(g,d)};document.getElementById("od-comment-close").addEventListener("click",t.closePanel),document.getElementById("od-comment-cancel").addEventListener("click",t.closePanel),document.getElementById("od-comment-save").addEventListener("click",u),c.addEventListener("keydown",h=>{h.key==="Enter"&&(h.metaKey||h.ctrlKey)&&u(),h.key==="Escape"&&t.closePanel()})},m=d=>{o.hidden=!1;let c=d.status==="sent"?"Sent to the agent":"Open";o.innerHTML=`
14
+ `;let a=document.getElementById("od-comment-text");a.focus();let g=()=>{let m=a.value.trim();if(!m)return;let h=we(r,m,t.host);s.push(h),x([h]),t.closePanel(),t.onAdded?.(h,r)};document.getElementById("od-comment-close").addEventListener("click",t.closePanel),document.getElementById("od-comment-cancel").addEventListener("click",t.closePanel),document.getElementById("od-comment-save").addEventListener("click",g),a.addEventListener("keydown",m=>{m.key==="Enter"&&(m.metaKey||m.ctrlKey)&&g(),m.key==="Escape"&&t.closePanel()})},p=r=>{n.hidden=!1;let a=r.status==="sent"?"Sent to the agent":"Open";n.innerHTML=`
15
15
  <div class="od-panel-header">
16
- <span class="od-panel-header-title">Comment \xB7 ${a(c)}</span>
16
+ <span class="od-panel-header-title">Comment \xB7 ${c(a)}</span>
17
17
  <button id="od-pin-close" class="od-panel-close" aria-label="Close">\xD7</button>
18
18
  </div>
19
19
  <div class="od-panel-body">
20
- <p class="od-comment-note">${a(d.note)}</p>
21
- <code class="od-comment-target">${a(d.selector)}</code>
20
+ <p class="od-comment-note">${c(r.note)}</p>
21
+ <code class="od-comment-target">${c(r.selector)}</code>
22
22
  </div>
23
23
  <div class="od-panel-footer">
24
24
  <button id="od-pin-delete" class="od-btn od-btn-danger">Delete</button>
25
25
  <span class="od-spacer"></span>
26
26
  <button id="od-pin-resolve" class="od-btn">Resolve</button>
27
- </div>`,document.getElementById("od-pin-close").addEventListener("click",t.closePanel),document.getElementById("od-pin-delete").addEventListener("click",()=>{i=i.filter(u=>u.id!==d.id),y([],[d.id]),t.closePanel()}),document.getElementById("od-pin-resolve").addEventListener("click",()=>{$.patch(d.id,{status:"resolved"}),t.closePanel()})},$={setComments(d){i=Array.isArray(d)?[...d]:[],t.onListChanged()},all:()=>i,open:()=>i.filter(d=>d.status==="open"),openInput:p,forBridge:()=>i.map(d=>({id:d.id,elementId:d.elementId,selector:d.selector,status:d.status,text:d.text,htmlHint:d.htmlHint})),pins(d){let c=[];for(let u of i){if(u.status==="resolved")continue;let h=d.find(b=>b.commentId===u.id)?.rect,g=h?A(r,h):null,f=document.createElement("div");f.className=`od-pin ${g?"anchored":"lost"}${u.status==="sent"?" sent":""}`,f.title=u.note,f.style.left=g?`${g.left+g.width/2}px`:"8px",f.style.top=g?`${g.top}px`:"8px",t.pinDetails&&(f.style.pointerEvents="auto",f.addEventListener("click",b=>{b.stopPropagation(),m(u)})),c.push(f)}return c},markOpenSent(){let d=new Date().toISOString(),c=[];return i=i.map(u=>{if(u.status!=="open")return u;let h={...u,status:"sent",updatedAt:d};return c.push(h),h}),c.length&&y(c),c},patch(d,c){let u=new Date().toISOString(),h;i=i.map(g=>g.id===d?h={...g,...c,updatedAt:u}:g),h&&y([h])},upsertLocal(d){let c=i.findIndex(u=>u.id===d.id);c===-1?i.push(d):i[c]=d,t.onListChanged()}};return $}var Ee={eye:'<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',comment:'<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>',pencil:'<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/>',chevronLeft:'<path d="m15 18-6-6 6-6"/>',chevronRight:'<path d="m9 18 6-6-6-6"/>',chevronDown:'<path d="m6 9 6 6 6-6"/>',refresh:'<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/>',expand:'<path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="m21 3-7 7"/><path d="m3 21 7-7"/>',code:'<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',share:'<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/><polyline points="16 6 12 2 8 6"/><line x1="12" x2="12" y1="2" y2="15"/>',export:'<path d="M21 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h6"/><path d="m21 3-9 9"/><path d="M15 3h6v6"/>',layers:'<path d="m12 2 10 5-10 5L2 7Z"/><path d="m2 17 10 5 10-5"/><path d="m2 12 10 5 10-5"/>',image:'<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"/>',users:'<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',link:'<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',check:'<path d="M20 6 9 17l-5-5"/>',arrowLeft:'<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>',palette:'<circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/>',sliders:'<line x1="4" x2="4" y1="21" y2="14"/><line x1="4" x2="4" y1="10" y2="3"/><line x1="12" x2="12" y1="21" y2="12"/><line x1="12" x2="12" y1="8" y2="3"/><line x1="20" x2="20" y1="21" y2="16"/><line x1="20" x2="20" y1="12" y2="3"/><line x1="2" x2="6" y1="14" y2="14"/><line x1="10" x2="14" y1="8" y2="8"/><line x1="18" x2="22" y1="16" y2="16"/>',send:'<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>',mail:'<rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>',clipboard:'<rect width="8" height="4" x="8" y="2" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>'};function L(t,o=16){return`<svg class="od-icon" width="${o}" height="${o}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${Ee[t]}</svg>`}var Q="bridge";function ae(t){return typeof t=="object"&&t!==null&&t.od===Q&&typeof t.type=="string"}var V=document.getElementById("root"),G=JSON.parse(V.dataset.odConfig??"{}"),le=window.matchMedia("(prefers-color-scheme: dark)"),pe=()=>{document.body.classList.toggle("od-dark",le.matches)};pe();le.addEventListener("change",pe);async function S(t,o){let r=await fetch(t,{method:o?.method??"GET",headers:o?.body!==void 0?{"Content-Type":"application/json"}:void 0,body:o?.body!==void 0?JSON.stringify(o.body):void 0}),i=await r.json().catch(()=>({}));if(!r.ok)throw new Error(i.error??`HTTP ${r.status}`);return i}var R=document.createElement("div");R.className="od-toast";R.hidden=!0;R.setAttribute("role","status");document.body.appendChild(R);var ce=0;function D(t){R.textContent=t,R.hidden=!1,clearTimeout(ce),ce=window.setTimeout(()=>{R.hidden=!0},4e3)}async function me(t){V.innerHTML=`<div class="od-picker"><div class="od-picker-inner">
27
+ </div>`,document.getElementById("od-pin-close").addEventListener("click",t.closePanel),document.getElementById("od-pin-delete").addEventListener("click",()=>{s=s.filter(g=>g.id!==r.id),x([],[r.id]),t.closePanel()}),document.getElementById("od-pin-resolve").addEventListener("click",()=>{I.patch(r.id,{status:"resolved"}),t.closePanel()})},I={setComments(r){s=Array.isArray(r)?[...r]:[],t.onListChanged()},all:()=>s,open:()=>s.filter(r=>r.status==="open"),openInput:l,forBridge:()=>s.map(r=>({id:r.id,elementId:r.elementId,selector:r.selector,status:r.status,text:r.text,htmlHint:r.htmlHint})),pins(r){let a=[];for(let g of s){if(g.status==="resolved")continue;let m=r.find(f=>f.commentId===g.id)?.rect,h=m?_(o,m):null,b=document.createElement("div");b.className=`od-pin ${h?"anchored":"lost"}${g.status==="sent"?" sent":""}`,b.title=g.note,b.style.left=h?`${h.left+h.width/2}px`:"8px",b.style.top=h?`${h.top}px`:"8px",t.pinDetails&&(b.style.pointerEvents="auto",b.addEventListener("click",f=>{f.stopPropagation(),p(g)})),a.push(b)}return a},markOpenSent(){let r=new Date().toISOString(),a=[];return s=s.map(g=>{if(g.status!=="open")return g;let m={...g,status:"sent",updatedAt:r};return a.push(m),m}),a.length&&x(a),a},patch(r,a){let g=new Date().toISOString(),m;s=s.map(h=>h.id===r?m={...h,...a,updatedAt:g}:h),m&&x([m])},upsertLocal(r){let a=s.findIndex(g=>g.id===r.id);a===-1?s.push(r):s[a]=r,t.onListChanged()}};return I}var Ee={eye:'<path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',comment:'<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>',pencil:'<path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/>',chevronLeft:'<path d="m15 18-6-6 6-6"/>',chevronRight:'<path d="m9 18 6-6-6-6"/>',chevronDown:'<path d="m6 9 6 6 6-6"/>',refresh:'<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/>',expand:'<path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="m21 3-7 7"/><path d="m3 21 7-7"/>',code:'<polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/>',share:'<path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/><polyline points="16 6 12 2 8 6"/><line x1="12" x2="12" y1="2" y2="15"/>',export:'<path d="M21 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h6"/><path d="m21 3-9 9"/><path d="M15 3h6v6"/>',layers:'<path d="m12 2 10 5-10 5L2 7Z"/><path d="m2 17 10 5 10-5"/><path d="m2 12 10 5 10-5"/>',image:'<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"/>',users:'<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',link:'<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>',check:'<path d="M20 6 9 17l-5-5"/>',arrowLeft:'<path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>',palette:'<circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/>',sliders:'<line x1="4" x2="4" y1="21" y2="14"/><line x1="4" x2="4" y1="10" y2="3"/><line x1="12" x2="12" y1="21" y2="12"/><line x1="12" x2="12" y1="8" y2="3"/><line x1="20" x2="20" y1="21" y2="16"/><line x1="20" x2="20" y1="12" y2="3"/><line x1="2" x2="6" y1="14" y2="14"/><line x1="10" x2="14" y1="8" y2="8"/><line x1="18" x2="22" y1="16" y2="16"/>',send:'<path d="m22 2-7 20-4-9-9-4Z"/><path d="M22 2 11 13"/>',mail:'<rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>',clipboard:'<rect width="8" height="4" x="8" y="2" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>'};function P(t,n=16){return`<svg class="od-icon" width="${n}" height="${n}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${Ee[t]}</svg>`}function ce(t,n,o,s){let x={iphone:{w:390,h:763,top:47,bottom:34,radius:54,bezel:12},android:{w:412,h:867,top:28,bottom:20,radius:36,bezel:10},"tablet-landscape":{w:1024,h:724,top:24,bottom:20,radius:28,bezel:16},"tablet-portrait":{w:768,h:980,top:24,bottom:20,radius:28,bezel:16},"desktop-app":{w:1280,h:800,top:32,bottom:0,radius:10,bezel:0}},l=n.parentElement&&n.parentElement.classList.contains("od-device")?n.parentElement:null,p=l?l.parentElement:n.parentElement;if(!o){l&&p&&(p.insertBefore(n,l),l.remove(),p.classList.remove("od-device-stage")),n.style.removeProperty("width"),n.style.removeProperty("height");return}if(!t.getElementById("od-device-css")){let y=t.createElement("style");y.id="od-device-css",y.textContent=[".od-device-stage{overflow:auto!important;display:flex!important;align-items:flex-start;justify-content:center;background:#e7e7ec;padding:24px;box-sizing:border-box}",".od-device{position:relative;flex:none;display:flex;flex-direction:column;background:#111;box-sizing:content-box;overflow:hidden;box-shadow:0 12px 40px rgba(0,0,0,.25)}",".od-device>iframe{display:block;flex:none;border:0;background:#fff}",".od-device-bar{flex:none;position:relative;display:flex;align-items:center;justify-content:space-between;font:600 14px/1 -apple-system,system-ui,sans-serif;padding:0 26px;box-sizing:border-box;user-select:none}",".od-device-bar svg{display:block}",".od-device-icons{display:flex;gap:6px;align-items:center}",".od-device-island{position:absolute;left:50%;top:11px;width:122px;height:35px;margin-left:-61px;border-radius:20px;background:#000}",".od-device-punch{position:absolute;left:50%;top:8px;width:12px;height:12px;margin-left:-6px;border-radius:50%;background:#000}",".od-device-home{flex:none;display:flex;align-items:center;justify-content:center}",".od-device-home i{display:block;height:5px;border-radius:3px}",".od-device-win{background:#f3f3f3!important;color:#333!important;border-bottom:1px solid rgba(0,0,0,.12);font-weight:500;font-size:13px;padding:0 12px}",".od-device-lights{display:flex;gap:8px}.od-device-lights i{width:12px;height:12px;border-radius:50%;display:block}",".od-device-caption{display:flex;height:100%}.od-device-caption span{width:46px;display:flex;align-items:center;justify-content:center;font-size:12px}"].join(`
28
+ `),t.head.appendChild(y)}let I=o.device==="tablet"?`tablet-${o.orientation==="portrait"?"portrait":"landscape"}`:o.device,r=x[I];if(!r||!p)return;let a=o.background&&!/^(?:transparent|rgba\(0, 0, 0, 0\))$/i.test(o.background)?o.background:o.theme==="dark"?"#000":"#fff",g=y=>{try{let E=t.createElement("canvas");E.width=1,E.height=1;let v=E.getContext("2d");if(!v||(v.fillStyle="#010203",v.fillStyle=y,String(v.fillStyle)==="#010203"))return;v.fillRect(0,0,1,1);let D=v.getImageData(0,0,1,1).data;return[D[0],D[1],D[2],D[3]/255]}catch{return}},m=/rgba?\((\d+),\s*(\d+),\s*(\d+)/i.exec(a),h=m?[Number(m[1]),Number(m[2]),Number(m[3])]:g(a),b=h?(.299*h[0]+.587*h[1]+.114*h[2])/255:o.theme==="dark"?0:1,f=o.theme==="dark"?"#fff":o.theme==="light"?"#111":b<.5?"#fff":"#111",R=y=>y.replace(/[&<>"]/g,E=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[E]),M=`<span class="od-device-icons"><svg width="17" height="11" viewBox="0 0 17 11" fill="${f}"><rect x="0" y="7" width="3" height="4" rx="1"/><rect x="4.5" y="5" width="3" height="6" rx="1"/><rect x="9" y="2.5" width="3" height="8.5" rx="1"/><rect x="13.5" y="0" width="3" height="11" rx="1"/></svg><svg width="15" height="11" viewBox="0 0 15 11" fill="${f}"><path d="M7.5 2.2c2 0 3.9.8 5.3 2.1l1.1-1.1A9 9 0 0 0 7.5.6 9 9 0 0 0 1.1 3.2l1.1 1.1a7.5 7.5 0 0 1 5.3-2.1Zm0 3.1c1.2 0 2.3.5 3.1 1.2l1.1-1.1a6 6 0 0 0-8.4 0l1.1 1.1c.8-.7 1.9-1.2 3.1-1.2Zm0 3.1c.4 0 .8.2 1 .4L7.5 10 6.5 8.8c.2-.2.6-.4 1-.4Z"/></svg><svg width="25" height="12" viewBox="0 0 25 12" fill="none" stroke="${f}"><rect x=".5" y=".5" width="21" height="11" rx="3" opacity=".4"/><rect x="2" y="2" width="16" height="8" rx="1.5" fill="${f}" stroke="none"/><path d="M23 4v4" opacity=".4"/></svg></span>`,T,A="";if(o.device==="desktop-app"){let y=R(s||"App");T=o.window==="windows"?`<div class="od-device-bar od-device-win" style="height:${r.top}px;padding-right:0"><span>${y}</span><span class="od-device-caption"><span>&#x2500;</span><span>&#x2610;</span><span>&#x2715;</span></span></div>`:`<div class="od-device-bar od-device-win" style="height:${r.top}px"><span class="od-device-lights"><i style="background:#ff5f57"></i><i style="background:#febc2e"></i><i style="background:#28c840"></i></span><span style="position:absolute;left:0;right:0;text-align:center;pointer-events:none">${y}</span><span></span></div>`}else{let y=o.device==="iphone"?'<span class="od-device-island"></span>':o.device==="android"?'<span class="od-device-punch"></span>':"",E=o.device==="android"?"12:30":"9:41";T=`<div class="od-device-bar" style="height:${r.top}px;background:${a};color:${f};${o.device==="android"?"padding:0 16px;font-size:13px;font-weight:500":""}"><span>${E}</span>${y}${M}</div>`;let v=o.device==="android"?"width:108px;height:4px":o.device==="iphone"?"width:134px":"width:200px";A=`<div class="od-device-home" style="height:${r.bottom}px;background:${a}"><i style="${v};background:${f};opacity:.85"></i></div>`}let w=l;w||(w=t.createElement("div"),w.className="od-device",p.insertBefore(w,n),w.appendChild(n)),w.setAttribute("data-device",I),w.style.borderRadius=`${r.radius}px`,w.style.border=r.bezel?`${r.bezel}px solid #111`:"1px solid rgba(0,0,0,.2)",Array.prototype.slice.call(w.querySelectorAll(".od-device-bar,.od-device-home")).forEach(y=>y.remove()),n.insertAdjacentHTML("beforebegin",T),A&&n.insertAdjacentHTML("afterend",A),n.style.width=`${r.w}px`,n.style.height=`${r.h}px`,p.classList.add("od-device-stage")}var Q="bridge";function le(t){return typeof t=="object"&&t!==null&&t.od===Q&&typeof t.type=="string"}var Z=document.getElementById("root"),U=JSON.parse(Z.dataset.odConfig??"{}"),me=window.matchMedia("(prefers-color-scheme: dark)"),he=()=>{document.body.classList.toggle("od-dark",me.matches)};he();me.addEventListener("change",he);async function G(t,n){let o=await fetch(t,{method:n?.method??"GET",headers:n?.body!==void 0?{"Content-Type":"application/json"}:void 0,body:n?.body!==void 0?JSON.stringify(n.body):void 0}),s=await o.json().catch(()=>({}));if(!o.ok)throw new Error(s.error??`HTTP ${o.status}`);return s}var B=document.createElement("div");B.className="od-toast";B.hidden=!0;B.setAttribute("role","status");document.body.appendChild(B);var pe=0;function O(t){B.textContent=t,B.hidden=!1,clearTimeout(pe),pe=window.setTimeout(()=>{B.hidden=!0},4e3)}async function ue(t){Z.innerHTML=`<div class="od-picker"><div class="od-picker-inner">
28
29
  <h1>Open Design preview</h1>
29
- <p>${t?a(t):"Pick a design to preview and comment on."}</p>
30
+ <p>${t?c(t):"Pick a design to preview and comment on."}</p>
30
31
  <ul class="od-picker-list" id="od-picker-list"><li><p>Loading\u2026</p></li></ul>
31
- </div></div>`;let o=document.getElementById("od-picker-list");try{let{artifacts:r}=await S("api/artifacts");o.innerHTML=r.length?r.map(i=>`<li><a href="?entry=${encodeURIComponent(i.entryPath)}">${a(i.title)}<small>${a(i.entryPath)}</small></a></li>`).join(""):"<li><p>No designs are registered in this workspace yet. Ask your agent to make one.</p></li>"}catch(r){o.innerHTML=`<li><p>${a(r instanceof Error?r.message:String(r))}</p></li>`}}async function xe(t){let o;try{o=await S(`api/state?entry=${encodeURIComponent(t)}`)}catch(e){await me(e instanceof Error?e.message:String(e));return}document.title=`${o.title} \xB7 Open Design`;let r=`entry=${encodeURIComponent(t)}`;V.innerHTML=`
32
+ </div></div>`;let n=document.getElementById("od-picker-list");try{let{artifacts:o}=await G("api/artifacts");n.innerHTML=o.length?o.map(s=>`<li><a href="?entry=${encodeURIComponent(s.entryPath)}">${c(s.title)}<small>${c(s.entryPath)}</small></a></li>`).join(""):"<li><p>No designs are registered in this workspace yet. Ask your agent to make one.</p></li>"}catch(o){n.innerHTML=`<li><p>${c(o instanceof Error?o.message:String(o))}</p></li>`}}async function ke(t){let n;try{n=await G(`api/state?entry=${encodeURIComponent(t)}`)}catch(e){await ue(e instanceof Error?e.message:String(e));return}document.title=`${n.title} \xB7 Open Design`;let o=`entry=${encodeURIComponent(t)}`;Z.innerHTML=`
32
33
  <div class="od-shell" style="display:flex;flex-direction:column;height:100%">
33
34
  <div class="od-toolbar" role="toolbar" aria-label="Preview">
34
35
  <div class="od-segmented" role="radiogroup" aria-label="Mode">
35
- <button data-mode="view" class="od-seg-btn active" role="radio" aria-checked="true" title="View">${L("eye")}<span class="od-label">View</span></button>
36
- <button data-mode="comment" class="od-seg-btn" role="radio" aria-checked="false" tabindex="-1" title="Comment on elements">${L("comment")}<span class="od-label">Comment</span></button>
36
+ <button data-mode="view" class="od-seg-btn active" role="radio" aria-checked="true" title="View">${P("eye")}<span class="od-label">View</span></button>
37
+ <button data-mode="comment" class="od-seg-btn" role="radio" aria-checked="false" tabindex="-1" title="Comment on elements">${P("comment")}<span class="od-label">Comment</span></button>
37
38
  </div>
38
- <a class="od-icon-btn" href="./" title="All designs" aria-label="All designs">${L("chevronLeft")}</a>
39
- <span class="od-title">${a(o.title)}</span>
40
- <span class="od-path">${a(t)}</span>
39
+ <a class="od-icon-btn" href="./" title="All designs" aria-label="All designs">${P("chevronLeft")}</a>
40
+ <span class="od-title">${c(n.title)}</span>
41
+ <span class="od-path">${c(t)}</span>
41
42
  <span class="od-toolbar-spacer"></span>
42
43
  <span id="od-live" class="od-live off" title="Reloads when the design changes"><span>Live</span></span>
43
- <button id="od-checks-toggle" class="od-btn" title="Check screenshots: before and after" aria-pressed="false">${L("check")}<span class="od-label">Checks</span><span id="od-checks-dot" class="od-dot" hidden></span></button>
44
- <button id="od-send-comments" class="od-btn od-btn-primary" title="Copy an instruction for your agent to apply the open comments" hidden>${L("send")}<span class="od-label">Send to agent</span><span id="od-send-count" class="od-count"></span></button>
44
+ <button id="od-checks-toggle" class="od-btn" title="Check screenshots: before and after" aria-pressed="false">${P("check")}<span class="od-label">Checks</span><span id="od-checks-dot" class="od-dot" hidden></span></button>
45
+ <button id="od-send-comments" class="od-btn od-btn-primary" title="Copy an instruction for your agent to apply the open comments" hidden>${P("send")}<span class="od-label">Send to agent</span><span id="od-send-count" class="od-count"></span></button>
45
46
  </div>
46
47
  <div class="od-stage">
47
48
  <div id="od-errors" class="od-errors" role="status" hidden>
@@ -53,18 +54,18 @@
53
54
  </div>
54
55
  <div id="od-panel" class="od-panel" hidden></div>
55
56
  <div id="od-checks" class="od-panel od-checks" hidden></div>
56
- </div>`;let i=document.getElementById("od-preview"),y=document.getElementById("od-pins"),p=document.getElementById("od-panel"),m=document.getElementById("od-checks"),$=document.getElementById("od-checks-toggle"),d=document.getElementById("od-checks-dot"),c=document.getElementById("od-send-comments"),u=document.getElementById("od-send-count"),h=document.getElementById("od-live"),g="view",f=null,b=null,k=null,H=[],P=!1,_=!1,O=!1,J={x:0,y:0},q,x=e=>{i.contentWindow?.postMessage({od:Q,...e},G.designOrigin)},ue=()=>{p.hidden=!0,b=null,k=null,x({type:"clear-selection"}),E()},X=()=>{let e=w.open().length;c.hidden=g!=="comment"&&e===0,c.disabled=e===0,u.textContent=e?String(e):""},w=de({panel:p,iframe:i,host:"browser",pinDetails:!0,persist:(e,n)=>{S(`api/comments?${r}`,{method:"POST",body:{changed:e,deletedIds:n}}).catch(l=>D(`Couldn't save the comment: ${l instanceof Error?l.message:String(l)}`))},closePanel:ue,onListChanged:()=>{X(),x({type:"set-comments",comments:w.forBridge()}),E()},onAdded:(e,n)=>void he(e,n)});function E(){if(y.innerHTML="",!(g==="view"||O)){if(f&&y.appendChild(j(A(i,f),"od-hover-box")),b&&k){let e=A(i,k);se(i,e).forEach(n=>y.appendChild(n)),y.appendChild(j(e,"od-select-box"))}w.pins(H).forEach(e=>y.appendChild(e))}}let z=()=>new Promise(e=>requestAnimationFrame(()=>e()));async function he(e,n){if(o.cropSupport==="none")return;O=!0,E(),await z(),await z();let l=i.getBoundingClientRect(),v=A(i,n.rect);try{let s=await S(`api/crop?${r}`,{method:"POST",body:{commentId:e.id,element:{x:v.left,y:v.top,width:v.width,height:v.height},stage:{x:l.left,y:l.top,width:l.width,height:l.height},docRect:{x:n.docRect.left,y:n.docRect.top,width:n.docRect.width,height:n.docRect.height},viewport:n.viewport}});s.comment?w.upsertLocal(s.comment):s.reason&&D(s.reason)}catch(s){D(`The comment was saved without a screenshot: ${s instanceof Error?s.message:String(s)}`)}finally{O=!1,E()}}function ge(){p.hidden=!1,p.innerHTML=`
57
+ </div>`;let s=document.getElementById("od-preview"),x=document.getElementById("od-pins"),l=document.getElementById("od-panel"),p=document.getElementById("od-checks"),I=document.getElementById("od-checks-toggle"),r=document.getElementById("od-checks-dot"),a=document.getElementById("od-send-comments"),g=document.getElementById("od-send-count"),m=document.getElementById("od-live"),h="view",b=null,f=null,R=null,M=[],T=!1,A=!1,w=!1,y={x:0,y:0},E,v=e=>{s.contentWindow?.postMessage({od:Q,...e},U.designOrigin)},D=()=>{l.hidden=!0,f=null,R=null,v({type:"clear-selection"}),$()},J=()=>{let e=C.open().length;a.hidden=h!=="comment"&&e===0,a.disabled=e===0,g.textContent=e?String(e):""},C=ae({panel:l,iframe:s,host:"browser",pinDetails:!0,persist:(e,i)=>{G(`api/comments?${o}`,{method:"POST",body:{changed:e,deletedIds:i}}).catch(u=>O(`Couldn't save the comment: ${u instanceof Error?u.message:String(u)}`))},closePanel:D,onListChanged:()=>{J(),v({type:"set-comments",comments:C.forBridge()}),$()},onAdded:(e,i)=>void ge(e,i)});function $(){if(x.innerHTML="",!(h==="view"||w)){if(b&&x.appendChild(V(_(s,b),"od-hover-box")),f&&R){let e=_(s,R);de(s,e).forEach(i=>x.appendChild(i)),x.appendChild(V(e,"od-select-box"))}C.pins(M).forEach(e=>x.appendChild(e))}}let W=()=>new Promise(e=>requestAnimationFrame(()=>e()));async function ge(e,i){if(n.cropSupport==="none")return;w=!0,$(),await W(),await W();let u=s.getBoundingClientRect(),k=_(s,i.rect);try{let d=await G(`api/crop?${o}`,{method:"POST",body:{commentId:e.id,element:{x:k.left,y:k.top,width:k.width,height:k.height},stage:{x:u.left,y:u.top,width:u.width,height:u.height},docRect:{x:i.docRect.left,y:i.docRect.top,width:i.docRect.width,height:i.docRect.height},viewport:i.viewport}});d.comment?C.upsertLocal(d.comment):d.reason&&O(d.reason)}catch(d){O(`The comment was saved without a screenshot: ${d instanceof Error?d.message:String(d)}`)}finally{w=!1,$()}}function fe(){l.hidden=!1,l.innerHTML=`
57
58
  <div class="od-panel-header">
58
59
  <span class="od-panel-header-title">Comment unavailable</span>
59
60
  <button id="od-bridge-close" class="od-panel-close" aria-label="Close">\xD7</button>
60
61
  </div>
61
- <div class="od-panel-body"><p>This design's page didn't start the preview helper that Comment relies on, usually because one of its own scripts failed first. Check the error banner, or ask your agent to fix the page.</p></div>`,document.getElementById("od-bridge-close").addEventListener("click",()=>{p.hidden=!0})}let M=Array.from(document.querySelectorAll(".od-seg-btn[data-mode]"));function W(e){if(e!=="view"&&_&&!P){ge();return}g=e,M.forEach(n=>{let l=n.dataset.mode===e;n.classList.toggle("active",l),n.setAttribute("aria-checked",String(l)),n.tabIndex=l?0:-1}),p.hidden=!0,b=null,k=null,f=null,H=[],X(),x({type:"set-mode",mode:e}),x({type:"set-comments",comments:w.forBridge()}),E()}M.forEach((e,n)=>{e.addEventListener("click",()=>W(e.dataset.mode)),e.addEventListener("keydown",l=>{let v=l.key==="ArrowRight"?1:l.key==="ArrowLeft"?-1:0;if(!v)return;l.preventDefault();let s=M[(n+v+M.length)%M.length];W(s.dataset.mode),s.focus()})});let Y=document.getElementById("od-errors"),fe=document.getElementById("od-errors-list"),C=[],Z=()=>{Y.hidden=C.length===0,fe.innerHTML=C.slice(0,3).map(e=>`<code>${a(e)}</code>`).join("")+(C.length>3?`<span>and ${C.length-3} more</span>`:"")};document.getElementById("od-errors-close").addEventListener("click",()=>{Y.hidden=!0}),window.addEventListener("message",e=>{if(e.source!==i.contentWindow||e.origin!==G.designOrigin)return;if(typeof e.data?.odPreviewError=="string"){let l=e.data.odPreviewError;!C.includes(l)&&C.length<20&&(C.push(l),Z());return}if(!ae(e.data))return;let n=e.data;switch(n.type){case"ready":P=!0,x({type:"set-mode",mode:g}),x({type:"set-comments",comments:w.forBridge()}),q&&(x({type:"scroll-to",...q}),q=void 0);break;case"select":if(g==="view")break;b=n.element,k=n.element.rect,f=null,E(),w.openInput(b);break;case"rects":f=n.hover,k=b?n.selection:null,H=Array.isArray(n.pins)?n.pins:[],E();break;case"scroll":Number.isFinite(n.x)&&Number.isFinite(n.y)&&(J={x:n.x,y:n.y});break;case"open-local-link":ye(String(n.href??""));break}});async function ye(e){let n=new URL(e,o.designUrl),l=`/${new URL(o.designUrl).pathname.split("/")[1]}/`,v=decodeURIComponent(n.pathname.slice(l.length));try{await S(`api/state?entry=${encodeURIComponent(v)}`),location.search=`?entry=${encodeURIComponent(v)}`}catch{i.src=n.href}}let K=0;function ee(e){P=!1,_=!1,C=[],Z(),f=null,b=null,k=null,H=[],!p.hidden&&p.querySelector("#od-comment-text")||(p.hidden=!0),q=e?J:void 0,K++,i.src=`${o.designUrl}?v=${K}`,E()}i.addEventListener("load",()=>{_=!0,x({type:"hello"}),E()}),window.addEventListener("resize",E),c.addEventListener("click",async()=>{let e=w.open();if(e.length===0)return;let n=`Apply my ${e.length===1?"comment":`${e.length} comments`} on the Open Design artifact "${t}": call get_open_design_artifact for it, address each open comment, then pass their ids as resolvedCommentIds when you re-register it.`;w.markOpenSent();try{await navigator.clipboard.writeText(n),D("Copied. Paste it into your agent.")}catch{p.hidden=!1,p.innerHTML=`
62
+ <div class="od-panel-body"><p>This design's page didn't start the preview helper that Comment relies on, usually because one of its own scripts failed first. Check the error banner, or ask your agent to fix the page.</p></div>`,document.getElementById("od-bridge-close").addEventListener("click",()=>{l.hidden=!0})}let N=Array.from(document.querySelectorAll(".od-seg-btn[data-mode]"));function X(e){if(e!=="view"&&A&&!T){fe();return}h=e,N.forEach(i=>{let u=i.dataset.mode===e;i.classList.toggle("active",u),i.setAttribute("aria-checked",String(u)),i.tabIndex=u?0:-1}),l.hidden=!0,f=null,R=null,b=null,M=[],J(),v({type:"set-mode",mode:e}),v({type:"set-comments",comments:C.forBridge()}),$()}N.forEach((e,i)=>{e.addEventListener("click",()=>X(e.dataset.mode)),e.addEventListener("keydown",u=>{let k=u.key==="ArrowRight"?1:u.key==="ArrowLeft"?-1:0;if(!k)return;u.preventDefault();let d=N[(i+k+N.length)%N.length];X(d.dataset.mode),d.focus()})});let Y=document.getElementById("od-errors"),ye=document.getElementById("od-errors-list"),L=[],K=()=>{Y.hidden=L.length===0,ye.innerHTML=L.slice(0,3).map(e=>`<code>${c(e)}</code>`).join("")+(L.length>3?`<span>and ${L.length-3} more</span>`:"")};document.getElementById("od-errors-close").addEventListener("click",()=>{Y.hidden=!0}),window.addEventListener("message",e=>{if(e.source!==s.contentWindow||e.origin!==U.designOrigin)return;if(typeof e.data?.odPreviewError=="string"){let u=e.data.odPreviewError;!L.includes(u)&&L.length<20&&(L.push(u),K());return}if(!le(e.data))return;let i=e.data;switch(i.type){case"ready":T=!0,ce(document,s,i.device,i.title),v({type:"set-mode",mode:h}),v({type:"set-comments",comments:C.forBridge()}),E&&(v({type:"scroll-to",...E}),E=void 0);break;case"select":if(h==="view")break;f=i.element,R=i.element.rect,b=null,$(),C.openInput(f);break;case"rects":b=i.hover,R=f?i.selection:null,M=Array.isArray(i.pins)?i.pins:[],$();break;case"scroll":Number.isFinite(i.x)&&Number.isFinite(i.y)&&(y={x:i.x,y:i.y});break;case"open-local-link":ve(String(i.href??""));break}});async function ve(e){let i=new URL(e,n.designUrl),u=`/${new URL(n.designUrl).pathname.split("/")[1]}/`,k=decodeURIComponent(i.pathname.slice(u.length));try{await G(`api/state?entry=${encodeURIComponent(k)}`),location.search=`?entry=${encodeURIComponent(k)}`}catch{s.src=i.href}}let ee=0;function te(e){T=!1,A=!1,L=[],K(),b=null,f=null,R=null,M=[],!l.hidden&&l.querySelector("#od-comment-text")||(l.hidden=!0),E=e?y:void 0,ee++,s.src=`${n.designUrl}?v=${ee}`,$()}s.addEventListener("load",()=>{A=!0,v({type:"hello"}),$()}),window.addEventListener("resize",$),a.addEventListener("click",async()=>{let e=C.open();if(e.length===0)return;let i=`Apply my ${e.length===1?"comment":`${e.length} comments`} on the Open Design artifact "${t}": call get_open_design_artifact for it, address each open comment, then pass their ids as resolvedCommentIds when you re-register it.`;C.markOpenSent();try{await navigator.clipboard.writeText(i),O("Copied. Paste it into your agent.")}catch{l.hidden=!1,l.innerHTML=`
62
63
  <div class="od-panel-header"><span class="od-panel-header-title">Paste this into your agent</span><button id="od-copy-close" class="od-panel-close" aria-label="Close">\xD7</button></div>
63
- <div class="od-panel-body"><textarea class="od-textarea od-copy-text" readonly>${a(n)}</textarea></div>`,p.querySelector("textarea").select(),document.getElementById("od-copy-close").addEventListener("click",()=>{p.hidden=!0})}});let I=[],T,U;async function N(){try{({runs:I,critique:T}=await S(`api/checks?${r}`))}catch{I=[],T=void 0}m.hidden||F()}let te=(e,n)=>`api/check-image?${r}&run=${encodeURIComponent(e.id)}&file=${encodeURIComponent(n)}`,ne=e=>`${new Date(e.createdAt).toLocaleString()} \xB7 ${e.errors} error${e.errors===1?"":"s"}, ${e.warnings} warning${e.warnings===1?"":"s"}`;function F(){let e=I.find(s=>s.id===U)??I[0],n=e?I[I.indexOf(e)+1]:void 0,l=e?`<div class="od-check-runs">${I.map(s=>`<button class="od-btn od-check-run${s===e?" active":""}" data-run="${a(s.id)}">${a(new Date(s.createdAt).toLocaleTimeString())}</button>`).join("")}</div>
64
- <p class="od-check-summary">After: ${a(ne(e))}${n?`<br>Before: ${a(ne(n))}`:"<br>No earlier check to compare with."}</p>
65
- ${e.images.map(s=>{let ie=n?.images.find(ve=>ve.label===s.label);return`<div class="od-check-label">${a(s.label)}</div><div class="od-check-pair">
66
- <figure>${ie?`<img src="${te(n,ie.file)}" alt="Before: ${a(s.label)}" loading="lazy">`:'<div class="od-check-empty">No earlier image</div>'}<figcaption>Before</figcaption></figure>
67
- <figure><img src="${te(e,s.file)}" alt="After: ${a(s.label)}" loading="lazy"><figcaption>After</figcaption></figure></div>`}).join("")}
68
- ${e.findings.length?`<div class="od-panel-section-title">Findings</div><ul class="od-shape-findings">${e.findings.map(s=>`<li class="od-shape-finding od-sev-${a(s.severity)}"><b>${a(s.severity)}</b> [${a(s.check)}] ${a(s.message)}</li>`).join("")}</ul>`:""}`:'<p class="od-check-empty">No checks yet. Your agent runs one after making or changing a design.</p>',v=T?`<div class="od-panel-section-title">${a(re(T))}</div>${T.findings.length?`<ul class="od-shape-findings">${T.findings.map(s=>`<li class="od-shape-finding">${s.where?`<b>${a(s.where)}</b> `:""}${s.problem?`${a(s.problem)}. `:""}${a(s.fix)}</li>`).join("")}</ul>`:""}`:"";m.innerHTML=`
64
+ <div class="od-panel-body"><textarea class="od-textarea od-copy-text" readonly>${c(i)}</textarea></div>`,l.querySelector("textarea").select(),document.getElementById("od-copy-close").addEventListener("click",()=>{l.hidden=!0})}});let S=[],H,F;async function j(){try{({runs:S,critique:H}=await G(`api/checks?${o}`))}catch{S=[],H=void 0}p.hidden||z()}let ne=(e,i)=>`api/check-image?${o}&run=${encodeURIComponent(e.id)}&file=${encodeURIComponent(i)}`,oe=e=>`${new Date(e.createdAt).toLocaleString()} \xB7 ${e.errors} error${e.errors===1?"":"s"}, ${e.warnings} warning${e.warnings===1?"":"s"}`;function z(){let e=S.find(d=>d.id===F)??S[0],i=e?S[S.indexOf(e)+1]:void 0,u=e?`<div class="od-check-runs">${S.map(d=>`<button class="od-btn od-check-run${d===e?" active":""}" data-run="${c(d.id)}">${c(new Date(d.createdAt).toLocaleTimeString())}</button>`).join("")}</div>
65
+ <p class="od-check-summary">After: ${c(oe(e))}${i?`<br>Before: ${c(oe(i))}`:"<br>No earlier check to compare with."}</p>
66
+ ${e.images.map(d=>{let re=i?.images.find(be=>be.label===d.label);return`<div class="od-check-label">${c(d.label)}</div><div class="od-check-pair">
67
+ <figure>${re?`<img src="${ne(i,re.file)}" alt="Before: ${c(d.label)}" loading="lazy">`:'<div class="od-check-empty">No earlier image</div>'}<figcaption>Before</figcaption></figure>
68
+ <figure><img src="${ne(e,d.file)}" alt="After: ${c(d.label)}" loading="lazy"><figcaption>After</figcaption></figure></div>`}).join("")}
69
+ ${e.findings.length?`<div class="od-panel-section-title">Findings</div><ul class="od-shape-findings">${e.findings.map(d=>`<li class="od-shape-finding od-sev-${c(d.severity)}"><b>${c(d.severity)}</b> [${c(d.check)}] ${c(d.message)}</li>`).join("")}</ul>`:""}`:'<p class="od-check-empty">No checks yet. Your agent runs one after making or changing a design.</p>',k=H?`<div class="od-panel-section-title">${c(se(H))}</div>${H.findings.length?`<ul class="od-shape-findings">${H.findings.map(d=>`<li class="od-shape-finding">${d.where?`<b>${c(d.where)}</b> `:""}${d.problem?`${c(d.problem)}. `:""}${c(d.fix)}</li>`).join("")}</ul>`:""}`:"";p.innerHTML=`
69
70
  <div class="od-panel-header"><span class="od-panel-header-title">Checks</span><button id="od-checks-close" class="od-panel-close" aria-label="Close">\xD7</button></div>
70
- <div class="od-panel-body">${v}${l}</div>`,document.getElementById("od-checks-close").addEventListener("click",()=>oe(!1)),m.querySelectorAll("[data-run]").forEach(s=>s.addEventListener("click",()=>{U=s.dataset.run,F()}))}function oe(e=m.hidden){m.hidden=!e,$.classList.toggle("active",e),$.setAttribute("aria-pressed",String(e)),e&&(d.hidden=!0,p.hidden=!0,F())}$.addEventListener("click",()=>oe());let B=new EventSource(`events?${r}`);B.addEventListener("open",()=>h.classList.remove("off")),B.addEventListener("error",()=>h.classList.add("off")),B.addEventListener("source-updated",()=>ee(!0)),B.addEventListener("manifest-updated",()=>void N()),B.addEventListener("comments-updated",e=>{let n=JSON.parse(e.data);w.setComments(n.comments??[])}),B.addEventListener("checks-updated",e=>{U=JSON.parse(e.data).runId,m.hidden&&(d.hidden=!1),N()}),w.setComments(o.comments),ee(!1),N()}G.entryPath?xe(G.entryPath):me();})();
71
+ <div class="od-panel-body">${k}${u}</div>`,document.getElementById("od-checks-close").addEventListener("click",()=>ie(!1)),p.querySelectorAll("[data-run]").forEach(d=>d.addEventListener("click",()=>{F=d.dataset.run,z()}))}function ie(e=p.hidden){p.hidden=!e,I.classList.toggle("active",e),I.setAttribute("aria-pressed",String(e)),e&&(r.hidden=!0,l.hidden=!0,z())}I.addEventListener("click",()=>ie());let q=new EventSource(`events?${o}`);q.addEventListener("open",()=>m.classList.remove("off")),q.addEventListener("error",()=>m.classList.add("off")),q.addEventListener("source-updated",()=>te(!0)),q.addEventListener("manifest-updated",()=>void j()),q.addEventListener("comments-updated",e=>{let i=JSON.parse(e.data);C.setComments(i.comments??[])}),q.addEventListener("checks-updated",e=>{F=JSON.parse(e.data).runId,p.hidden&&(r.hidden=!1),j()}),C.setComments(n.comments),te(!1),j()}U.entryPath?ke(U.entryPath):ue();})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@feimacode/open-design-agent-kit-mcp",
3
- "version": "0.4.0-beta.1",
3
+ "version": "0.4.0-beta.3",
4
4
  "mcpName": "io.github.feimacode/open-design",
5
5
  "description": "Open Design as an MCP server — the same skill/design-system/artifact tools the VS Code extension exposes, usable from any MCP-capable coding agent (Claude Code, Codex, and others).",
6
6
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "start": "node ./out/index.js"
44
44
  },
45
45
  "dependencies": {
46
- "@feimacode/open-design-agent-kit-content": "^0.4.0-beta.1",
46
+ "@feimacode/open-design-agent-kit-content": "^0.4.0-beta.3",
47
47
  "@modelcontextprotocol/sdk": "^1.30.0"
48
48
  },
49
49
  "devDependencies": {