notemend 0.1.7 → 0.1.9

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/src/client/run.js CHANGED
@@ -1,79 +1,81 @@
1
- import{categoryOf as oe}from"../store/categories.mjs";import{stateOf as O,STATE_LABEL as hs}from"../store/status.mjs";import{agentName as dt,handleOf as bs,threadOf as ys,workingOn as vs}from"../store/thread.mjs";import{api as U,canvasCopy as $s,host as Es,imageUrl as ws}from"./api";import{DEVTOOLS_DEVICES as fo}from"../devtools-devices.mjs";import{drawDevice as Ss,pageTints as Ls,inkFor as ho}from"./devices";import{recentLogs as xs}from"./logs";function Rs(M){const B=M.breakpoints,Xe=M.categories,se=(B.find(t=>!Number.isFinite(t.max))??B[0]).id,Et=t=>B.find(e=>t>=e.min&&t<=e.max)?.id??se,ct=t=>t.breakpoint||se,Dt=t=>M.devices.find(e=>e.id===t),$=$s,z=(t,e)=>{$||localStorage.setItem(t,e)},re=t=>t.replace(/\/+$/,"")||"/";let P=re(location.pathname);for(const t of document.querySelectorAll(".devtools .dt-icon[title]"))t.dataset.tip=t.title,t.getAttribute("aria-label")||t.setAttribute("aria-label",t.title),t.removeAttribute("title");const Ze=document.querySelector(".dt-grid-btn"),Ot=document.querySelector(".dt-grid-overlay"),Qe="dt-grid",ae=t=>{Ot.hidden=!t,Ze.setAttribute("aria-pressed",String(t)),z(Qe,t?"1":"0"),q({grid:t})};Ze.addEventListener("click",()=>ae(Ot.hidden===!0));const tn=document.querySelector(".dt-pages-name"),en=()=>{let t=null;for(const o of document.querySelectorAll(".dt-pages a"))re(new URL(o.href).pathname)===P?(o.setAttribute("aria-current","page"),t=o):o.removeAttribute("aria-current");const e=document.title.split("\u2014").pop()?.trim(),n=t?.querySelector(".dt-menu-label")?.textContent?.trim();tn.textContent=n||e||tn.textContent};en();const nn=[...document.querySelectorAll(".devtools details")];let ie=!1;const wt=()=>{const t=nn.filter(e=>e.open);for(const e of t)e.open=!1;return t};document.addEventListener("keydown",t=>{if(t.key!=="Escape")return;const[e]=wt();e&&(e.querySelector("summary")?.focus(),t.preventDefault(),t.stopImmediatePropagation())},!0),document.addEventListener("pointerdown",t=>{ie=nn.some(e=>e.open&&!e.contains(t.target))&&wt().length>0},!0),addEventListener("blur",wt);const Z=document.querySelector(".dt-pad-overlay"),on="dt-inspect",bo=[".devtools",".dt-pad-overlay",".dt-grid-overlay",".dt-frame",".dt-history",".dt-review",...M.ignore].join(", "),le=[".devtools",".dt-notes-overlay",".dt-history",".dt-frame",".dt-review",...M.ignore].join(", "),de={pads:document.querySelector(".dt-pad-btn"),sizes:document.querySelector(".dt-size-btn"),type:document.querySelector(".dt-type-btn")};let ut="",ce=0;const k=t=>{const e=parseFloat(getComputedStyle(document.documentElement).fontSize)/16,n=t/e;return Math.round(n*10)%10===0?String(Math.round(n)):n.toFixed(1)},_=(t,e,n,o,s,r="p")=>{if(n<=0||o<=0)return"";const c=s!==""?`<span class="dt-pad-chip dt-pad-chip--${r}" style="left:${t+n/2}px;top:${e+o/2}px">${s}</span>`:"";return`<span class="dt-pad-zone dt-pad-zone--${r}" style="left:${t}px;top:${e}px;width:${n}px;height:${o}px"></span>${c}`},yo=["paddingTop","paddingRight","paddingBottom","paddingLeft","marginTop","marginRight","marginBottom","marginLeft","columnGap","rowGap"],vo=t=>{let e=t;for(let n=0;e&&n<6;n++,e=e.parentElement){const o=getComputedStyle(e);if(yo.some(s=>parseFloat(o[s])>=2))return e}return t},$o=(t,e)=>{const n=parseFloat(e.columnGap)||0,o=parseFloat(e.rowGap)||0;if(!(e.display.includes("flex")||e.display.includes("grid"))||!n&&!o)return"";const s=[...t.children].map(c=>c.getBoundingClientRect()).filter(c=>c.width||c.height);let r="";for(let c=1;c<s.length;c++){const d=s[c-1],a=s[c];if(n&&a.left>=d.right-1){const l=Math.max(d.top,a.top);r+=_(d.right,l,a.left-d.right,Math.min(d.bottom,a.bottom)-l,k(n),"g")}else if(o&&a.top>=d.bottom-1){const l=Math.min(d.left,a.left);r+=_(l,d.bottom,Math.max(d.right,a.right)-l,a.top-d.bottom,k(o),"g")}}return r},ue=t=>`<span class="dt-pad-outline" style="left:${t.left}px;top:${t.top}px;width:${t.width}px;height:${t.height}px"></span>`,me=(t,e,n="")=>`<span class="dt-pad-tag" style="left:${e.left}px;top:${Math.max(2,e.top-22)}px">${t.tagName.toLowerCase()+(t.classList[0]?"."+t.classList[0]:"")}${n}</span>`,Eo=t=>{const e=t.getBoundingClientRect(),n=getComputedStyle(t),o=parseFloat(n.paddingTop),s=parseFloat(n.paddingRight),r=parseFloat(n.paddingBottom),c=parseFloat(n.paddingLeft);let d=ue(e);d+=_(e.left,e.top,e.width,o,o>=2?k(o):""),d+=_(e.left,e.bottom-r,e.width,r,r>=2?k(r):""),d+=_(e.left,e.top+o,c,e.height-o-r,c>=2?k(c):""),d+=_(e.right-s,e.top+o,s,e.height-o-r,s>=2?k(s):"");const a=parseFloat(n.marginTop),l=parseFloat(n.marginRight),m=parseFloat(n.marginBottom),b=parseFloat(n.marginLeft);d+=_(e.left,e.top-a,e.width,a,a>=2?k(a):"","m"),d+=_(e.left,e.bottom,e.width,m,m>=2?k(m):"","m"),d+=_(e.left-b,e.top,b,e.height,b>=2?k(b):"","m"),d+=_(e.right,e.top,l,e.height,l>=2?k(l):"","m"),d+=$o(t,n);const i=parseFloat(n.columnGap)||0,v=parseFloat(n.rowGap)||0,x=(n.display.includes("flex")||n.display.includes("grid"))&&(i||v)?` \xB7 gap ${k(i)}${v&&v!==i?"/"+k(v):""}`:"";Z.innerHTML=d+me(t,e,x)},wo=t=>{const e=t.getBoundingClientRect();Z.innerHTML=ue(e)+`<span class="dt-pad-chip" style="left:${e.left+e.width/2}px;top:${e.top+e.height/2}px">${k(e.width)} \xD7 ${k(e.height)}</span>`+me(t,e)},sn=t=>{const e=(t.match(/[\d.]+/g)||[]).map(Number);if(e.length<3)return t;const n="#"+e.slice(0,3).map(o=>Math.round(o).toString(16).padStart(2,"0")).join("");return e[3]!==void 0&&e[3]<1?`${n} \xB7 ${Math.round(e[3]*100)}%`:n};let pe=null;const So=()=>{if(pe)return pe;const t=getComputedStyle(document.documentElement),e=document.createElement("span");e.style.display="none",document.body.append(e);const n=[];for(const o of Array.from(t)){if(!o.startsWith("--"))continue;const s=t.getPropertyValue(o).trim();if(!/^(#|rgb|hsl|oklch|lab|color\()/i.test(s))continue;e.style.color="rgb(1, 2, 3)",e.style.color=s;const r=getComputedStyle(e).color;r&&r!=="rgb(1, 2, 3)"&&n.push([r,o])}return e.remove(),n.sort((o,s)=>o[1].length-s[1].length),pe=n,n},Lo=t=>So().find(([e])=>e===t)?.[1]??"",xo={100:"Thin",200:"Extra Light",300:"Light",400:"Regular",500:"Medium",600:"Semi Bold",700:"Bold",800:"Extra Bold",900:"Black"},rn=t=>(t.match(/[\d.]+/g)??[]).map(Number).concat([1]).slice(0,4),an=(t,e)=>t.slice(0,3).map((n,o)=>n*t[3]+e[o]*(1-t[3])).concat([1]),To=t=>{const e=[];for(let n=t;n;n=n.parentElement){const o=getComputedStyle(n);if(o.backgroundImage!=="none")return null;const s=rn(o.backgroundColor);if(s[3]>0&&(e.push(s),s[3]>=1))break}return e.reduceRight((n,o)=>an(o,n),[255,255,255,1])},ln=t=>{const[e,n,o]=t.slice(0,3).map(s=>(s/=255,s<=.03928?s/12.92:((s+.055)/1.055)**2.4));return .2126*e+.7152*n+.0722*o},Mo=(t,e,n)=>{const o=To(t);if(!o)return["Contrast","<em>on an image</em>"];const s=an(rn(e.color),o),[r,c]=[ln(s),ln(o)].sort((m,b)=>b-m),d=(r+.05)/(c+.05),a=n>=24||n>=18.66&&Number(e.fontWeight)>=700,l=d>=(a?4.5:7)?"AAA":d>=(a?3:4.5)?"AA":"fails AA";return["Contrast",`${d.toFixed(2)}:1 <em class="${l==="fails AA"?"dt-type-bad":""}">${l}${a?" \xB7 large":""}</em>`]},ko=t=>{const e=t.getBoundingClientRect(),n=getComputedStyle(t),o=parseFloat(n.fontSize),s=n.lineHeight==="normal"?0:parseFloat(n.lineHeight),r=parseFloat(n.letterSpacing)||0,c=Lo(n.color),d=i=>`${(i*100).toFixed(1).replace(/\.0$/,"")}%`,a=[["Font",n.fontFamily.split(",")[0].replace(/["']/g,"")+(n.fontStyle!=="normal"?` ${n.fontStyle}`:"")],["Weight",`${xo[n.fontWeight]??""} <em>${n.fontWeight}</em>`],["Size",`${k(o)}px`],["Line",s?`${d(s/o)} <em>${k(s)}px</em>`:"normal"],["Letter",r?`${d(r/o)} <em>${r.toFixed(2).replace(/\.?0+$/,"")}px</em>`:"0"],["Color",`<i class="dt-type-sw" style="background:${n.color}"></i>${c?`${c} <em>${sn(n.color)}</em>`:sn(n.color)}`],Mo(t,n,o)],m=e.bottom+150<innerHeight?e.bottom+8:Math.max(8,e.top-158),b=Math.min(Math.max(8,e.left),innerWidth-210);Z.innerHTML=ue(e)+me(t,e)+`<div class="dt-type-card" style="left:${b}px;top:${m}px">${a.map(([i,v])=>`<span class="dt-type-row"><b>${i}</b><span>${v}</span></span>`).join("")}</div>`},dn=t=>{ce||(ce=requestAnimationFrame(()=>{ce=0,Z.hidden=!0;let e=document.elementFromPoint(t.clientX,t.clientY);if(Z.hidden=!1,!e||e.closest(bo)){Z.innerHTML="";return}t.altKey&&e.parentElement&&e.parentElement!==document.body&&(e=e.parentElement),ut==="sizes"?wo(e):ut==="type"?ko(e):Eo(t.altKey?e:vo(e))}))},Pt=t=>{ut=t;for(const[e,n]of Object.entries(de))n.setAttribute("aria-pressed",String(e===t));z(on,t),q({inspect:t}),Z.hidden=!t,Z.innerHTML="",t?document.addEventListener("mousemove",dn):document.removeEventListener("mousemove",dn)};for(const[t,e]of Object.entries(de))e.addEventListener("click",()=>{t!==ut&&rt(!1),Pt(ut===t?"":t)});const cn=document.querySelector(".dt-notes-btn"),ge=[...document.querySelectorAll(".dt-bp")],Ft=document.querySelector(".dt-history-btn"),D=document.querySelector(".dt-history"),fe=document.querySelector(".dt-studio-btn"),w=document.querySelector(".dt-device"),un=document.querySelector(".dt-shell"),St=document.querySelector('.dt-chrome[data-at="top"]'),jt=document.querySelector('.dt-chrome[data-at="bottom"]'),Lt=document.querySelector(".dt-ruler"),G=document.querySelector(".dt-devices"),mt=document.querySelector(".dt-notes-hi"),Ho=mt.querySelector(".dt-hi-box"),mn=mt.querySelector(".dt-hi-tag"),Ao=[...document.querySelectorAll(".dt-frame-handle")],pn=document.querySelector(".dt-frame-size"),he=document.querySelector(".dt-frame-rotate"),xt=document.querySelector(".dt-frame-bars"),C=document.querySelector(".dt-frame"),S=C.querySelector("iframe"),be=document.querySelector(".dt-notes-count"),f=document.querySelector(".dt-notes-overlay"),Co=".devtools, .dt-tab, .dt-notes-overlay, .dt-history, .dt-frame, .dt-review";for(const t of document.querySelectorAll(Co))for(const e of["pointerdown","mousedown","pointerup","mouseup","touchstart","touchend","click","focusin","focusout"])t.addEventListener(e,n=>n.stopPropagation());const gn="dt-notes";let h=[],H=!1,y=null,u=null,ye=0,F="",Q=[],L=null,R=[];const Kt=(t=u)=>!!(t&&(t.text?.trim()||t.images?.length)),j=()=>{u&&Kt()&&R.push(u),u=null};let Tt=null,J=null;const fn=()=>`dt-draft:${P}${$?":canvas":""}`;let ft=fn(),Wt=0;const ve=()=>{if(!u&&!R.length&&!F){localStorage.removeItem(ft);return}const t={draft:u,parked:R,reply:F?{for:Tt,text:F}:null};try{localStorage.setItem(ft,JSON.stringify(t))}catch{const e=n=>({...n,images:void 0});try{localStorage.setItem(ft,JSON.stringify({...t,draft:u&&e(u),parked:R.map(e)}))}catch{}}},zt=()=>{clearTimeout(Wt),Wt=setTimeout(ve,200)};addEventListener("pagehide",()=>{clearTimeout(Wt),ve()});let tt=localStorage.getItem("dt-resolved")!=="0";const No=[[/Edg\/(\d+)/,"Edge"],[/OPR\/(\d+)/,"Opera"],[/Firefox\/(\d+)/,"Firefox"],[/Chrome\/(\d+)/,"Chrome"],[/Version\/(\d+).*Safari/,"Safari"]],Bo=[[/iPhone|iPad/,"iOS"],[/Android/,"Android"],[/Mac OS X/,"macOS"],[/Windows/,"Windows"],[/Linux/,"Linux"]],Ro=()=>{const t=navigator.userAgent,e=r=>r.find(([c])=>c.test(t)),n=e(No),o=e(Bo),s=n?n[0].exec(t)?.[1]:null;return[n?`${n[1]}${s?" "+s:""}`:"unknown browser",o?.[1]].filter(Boolean).join(" \xB7 ")},et=()=>Et(innerWidth),_t=()=>J??et(),Mt=()=>{const t=_t();for(const e of ge)e.setAttribute("aria-pressed",String(e.dataset.bp===t))},qo=t=>{const e=[];let n=t;for(;n&&n.tagName!=="HTML"&&e.length<8;){if(n.id){e.unshift("#"+CSS.escape(n.id));break}const o=n.parentElement,s=n.tagName.toLowerCase(),r=o?[...o.children].filter(c=>c.tagName===n.tagName):[];e.unshift(r.length>1?`${s}:nth-of-type(${r.indexOf(n)+1})`:s),n=o}return e.join(">")},$e=(t,e)=>!e||K(t.textContent||"").slice(0,60)===e,Io=(t,e)=>[t||"*",...(e||[]).map(n=>"."+CSS.escape(n))].join(""),hn=t=>{try{return[...document.querySelectorAll(Io(t.tag,t.classes))]}catch{return[]}},bn=t=>{const e=K(t.textContent||"").replace(/\s+/g," ");for(let n=t.parentElement,o=0;n&&n!==document.body&&o<4;n=n.parentElement,o++){const s=K(n.textContent||"").replace(/\s+/g," ");if(s&&s!==e)return s}return""},Do=t=>bn(t).slice(0,80),Ee=(t,e)=>!e||bn(t).startsWith(e),Y=t=>{let e=null;try{e=document.querySelector(t.selector)}catch{e=null}if(e&&$e(e,t.label)&&Ee(e,t.ctx))return e;const n=hn(t),o=K(t.label)?n.filter(r=>$e(r,t.label)):[];return(o.find(r=>Ee(r,t.ctx))??n.find(r=>t.ctx&&Ee(r,t.ctx)&&!K(t.label)))||o[0]||(e&&$e(e,t.label)?e:null)||(t.nth!=null?n[t.nth]:null)||n[0]||e},Oo=t=>{let e=null;for(let n=t.parentElement;n&&n!==document.body;n=n.parentElement){const o=getComputedStyle(n);if(o.overflowX==="visible"&&o.overflowY==="visible")continue;const s=n.getBoundingClientRect();e=e?{l:Math.max(e.l,s.left),t:Math.max(e.t,s.top),r:Math.min(e.r,s.right),b:Math.min(e.b,s.bottom)}:{l:s.left,t:s.top,r:s.right,b:s.bottom}}return e},V=t=>{const e=Y(t);if(!e)return null;const n=e.getBoundingClientRect();if(!n.width&&!n.height)return null;const o=n.left+n.width*t.rx,s=n.top+n.height*t.ry,r=Oo(e);if(!r)return{x:o,y:s,off:""};if(r.r-r.l<18||r.b-r.t<18)return null;const c=Math.min(Math.max(o,r.l),r.r-18),d=Math.min(Math.max(s,r.t+18),r.b),a=o<r.l?"l":o>r.r-18?"r":s<r.t+18?"t":s>r.b?"b":"";return{x:c,y:d,off:a}},yn=t=>{for(let e=t;e&&e!==document.body;e=e.parentElement)if(e.getAnimations().some(n=>n.playState==="running"))return!0;return!1};let Gt=[];const we=t=>{for(const e of Gt)e.play();Gt=[];for(let e=t;e&&e!==document.body;e=e.parentElement)for(const n of e.getAnimations())n.playState==="running"&&(n.pause(),Gt.push(n))},vn=()=>{if(u)return Y(u);const t=y!=null?h.find(n=>n.id===y):null;if(!t)return null;const e=V(t);return e&&!e.off?Y(t):null},$n=t=>t?new Date(t).toLocaleString(void 0,{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"}):"",Yt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4 6h12M8 6V4.2h4V6M6.6 6l.55 9.8h5.7L13.4 6"/></svg>',Se='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4.8 10.4 8.2 13.8l7-7.6" stroke-linejoin="round"/></svg>',Le='<svg viewBox="0 0 20 20" width="12" height="12" aria-hidden="true"><path d="M12.6 4.4l3 3-8.4 8.4H4.2v-3z" stroke-linejoin="round"/></svg>',Vt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M5.4 5.4l9.2 9.2M14.6 5.4l-9.2 9.2"/></svg>',kt=t=>`<svg viewBox="0 0 24 24" width="${t}" height="${t}" aria-hidden="true" class="dt-claude"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>`,En=()=>{try{return localStorage.getItem("nm-for")??"claude"}catch{return"claude"}},wn=t=>t==="claude"?"#d97757":t?"#0d99ff":"#717171",Sn=(t,e)=>`<label class="dt-pill" style="--cat:${wn(t)}"><select class="dt-for-select"${e?` data-id="${e}"`:""} aria-label="Who this is for">
2
- <option value="claude"${t==="claude"?" selected":""}>AI agent</option>
3
- <option value=""${t?"":" selected"}>Anyone</option>
4
- ${(M.team??[]).filter(n=>n.email!==M.me?.email).map(n=>`<option value="${g(n.email)}"${t===n.email?" selected":""}>${g(n.name||n.email)}</option>`).join("")}
5
- </select></label>`,Ln=t=>{const e=K(t?.textContent).replace(/\s+/g," ");return e&&e.length<=2e3?e:""},Po=t=>`<div class="dt-suggest dt-suggest--read"><del>${g(t.from)}</del><ins>${g(t.to)}</ins></div>`,K=t=>(t??"").replace(/[\u200B-\u200D\uFEFF\u2060]/g,"").trim(),xn=t=>K(t)?`<span class="dt-note-info" data-tip="${g(K(t))}"
6
- ><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><circle cx="10" cy="10" r="7.4"/><path d="M10 9.2v4.4M10 6.4v.6"/></svg></span>`:"",Tn=(t,e)=>`<span class="dt-pill" style="--cat:${oe(t).color}"><select class="dt-cat-select"${e?` data-id="${e}"`:""} aria-label="Type">${Xe.map(n=>`<option value="${n.id}"${n.id===t?" selected":""}>${n.label}</option>`).join("")}</select></span>`,Fo='<svg viewBox="0 0 20 20" width="9" height="9" aria-hidden="true"><path d="M5.5 5.5l9 9M14.5 5.5l-9 9"/></svg>',Mn=t=>t.startsWith("data:video/")||/\.webm(\?|$)/i.test(t),kn=(t,e,n=t)=>`<span class="dt-shot${Mn(n)?" dt-shot--video":""}">${Mn(n)?`<video src="${t}" controls preload="metadata" playsinline></video>`:`<a href="${t}" target="_blank"><img src="${t}" alt="" loading="lazy" /></a>`}${e===void 0?"":`<button class="dt-shot-rm" data-act="unshot" ${e} aria-label="Remove">${Fo}</button>`}</span>`,Hn=(t=[],e)=>t.length?`<div class="dt-note-shots">${t.map(n=>{const o=n.split("/").pop(),s=ws(o);return kn(s,e===void 0?void 0:`data-id="${e}" data-img="${g(o)}"`,o)}).join("")}</div>`:"",An=(t=[])=>t.length?`<div class="dt-note-shots">${t.map((e,n)=>kn(e,`data-i="${n}"`)).join("")}</div>`:"",jo='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><rect x="2.5" y="5.5" width="11" height="9" rx="2"/><path d="m13.5 9 4-2.5v7l-4-2.5"/></svg>',Ko=!1,Wo=!1,zo=!!navigator.mediaDevices?.getDisplayMedia&&typeof MediaRecorder<"u";let pt=null;const _o=async t=>{if(pt){pt.stop();return}let e;try{e=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:12},audio:!1})}catch{return}const n=await navigator.mediaDevices.getUserMedia({audio:!0}).catch(()=>null),o=new MediaStream([...e.getVideoTracks(),...n?.getAudioTracks()??[]]),s=["video/webm;codecs=vp9,opus","video/webm;codecs=vp8,opus","video/webm"].find(l=>MediaRecorder.isTypeSupported(l));if(!s){for(const l of e.getTracks())l.stop();st("This browser cannot record WebM video.");return}const r=new MediaRecorder(o,{mimeType:s,videoBitsPerSecond:6e5,audioBitsPerSecond:32e3}),c=[],d=!!Number(t?.dataset.id);r.ondataavailable=l=>{l.data.size&&c.push(l.data)};const a=setTimeout(()=>{r.state!=="inactive"&&r.stop()},3e4);r.onstop=async()=>{clearTimeout(a);for(const b of[...e.getTracks(),...n?.getTracks()??[]])b.stop();pt=null;const l=new Blob(c,{type:"video/webm"});if(l.size>32e5){st("That recording is too big to send \u2014 keep it shorter."),p();return}const m=await new Promise(b=>{const i=new FileReader;i.onload=()=>b(String(i.result)),i.readAsDataURL(l)});d?Q.push(m):u&&(u.images??=[]).push(m),p()},e.getVideoTracks()[0]?.addEventListener("ended",()=>{r.state!=="inactive"&&r.stop()}),pt=r,r.start(1e3),p()},Go='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><rect x="3" y="4" width="14" height="12" rx="2"/><circle cx="7.5" cy="8.5" r="1.4"/><path d="m3.5 14.5 4-4 3 3 2-2 4 4"/></svg>',Cn=(t,e,n,o,s="")=>`<div class="dt-note-foot"><div class="dt-compose">
1
+ import{categoryOf as de}from"../store/categories.mjs";import{stateOf as C,STATE_LABEL as ds}from"../store/status.mjs";import{agentName as J,handleOf as cs,held as us,threadOf as ps,workingOn as ms}from"../store/thread.mjs";import{api as B,canvasCopy as gs,host as fs,imageUrl as hs}from"./api";import{DEVTOOLS_DEVICES as co}from"../devtools-devices.mjs";import{drawDevice as bs,pageTints as ys,inkFor as uo}from"./devices";import{recentLogs as vs}from"./logs";import{inspectors as $s}from"./inspect";import{anchors as Es,clean as wt}from"./anchor";import{fieldMenus as ws}from"./field-menu";function Is(b){const I=b.breakpoints,Xe=b.categories,ce=(I.find(t=>!Number.isFinite(t.max))??I[0]).id,St=t=>I.find(e=>t>=e.min&&t<=e.max)?.id??ce,G=t=>t.breakpoint||ce,Wt=t=>b.devices.find(e=>e.id===t),v=gs,_=(t,e)=>{v||localStorage.setItem(t,e)},ue=t=>t.replace(/\/+$/,"")||"/";let K=ue(location.pathname);for(const t of document.querySelectorAll(".devtools .dt-icon[title]"))t.dataset.tip=t.title,t.getAttribute("aria-label")||t.setAttribute("aria-label",t.title),t.removeAttribute("title");const Ze=document.querySelector(".dt-grid-btn"),_t=document.querySelector(".dt-grid-overlay"),Qe="dt-grid",pe=t=>{_t.hidden=!t,Ze.setAttribute("aria-pressed",String(t)),_(Qe,t?"1":"0"),D({grid:t})};Ze.addEventListener("click",()=>pe(_t.hidden===!0));const tn=document.querySelector(".dt-pages-name"),en=()=>{let t=null;for(const o of document.querySelectorAll(".dt-pages a"))ue(new URL(o.href).pathname)===K?(o.setAttribute("aria-current","page"),t=o):o.removeAttribute("aria-current");const e=document.title.split("\u2014").pop()?.trim(),n=t?.querySelector(".dt-menu-label")?.textContent?.trim();tn.textContent=n||e||tn.textContent};en();const nn=[...document.querySelectorAll(".devtools details")];let me=!1;const Lt=()=>{const t=nn.filter(e=>e.open);for(const e of t)e.open=!1;return t};document.addEventListener("keydown",t=>{if(t.key!=="Escape")return;const[e]=Lt();e&&(e.querySelector("summary")?.focus(),t.preventDefault(),t.stopImmediatePropagation())},!0),document.addEventListener("pointerdown",t=>{me=nn.some(e=>e.open&&!e.contains(t.target))&&Lt().length>0},!0),addEventListener("blur",Lt);const gt=document.querySelector(".dt-pad-overlay"),on="dt-inspect",po=[".devtools",".dt-pad-overlay",".dt-grid-overlay",".dt-frame",".dt-history",".dt-review",".dt-field-menu",...b.ignore].join(", "),ge=[".devtools",".dt-notes-overlay",".dt-history",".dt-frame",".dt-review",".dt-field-menu",'[aria-modal="true"]',...b.ignore].join(", "),fe={pads:document.querySelector(".dt-pad-btn"),sizes:document.querySelector(".dt-size-btn"),type:document.querySelector(".dt-type-btn")};let lt="",he=0;const{spacer:mo,drawPads:go,drawSize:fo,drawType:ho}=$s(gt),sn=t=>{he||(he=requestAnimationFrame(()=>{he=0,gt.hidden=!0;let e=document.elementFromPoint(t.clientX,t.clientY);if(gt.hidden=!1,!e||e.closest(po)){gt.innerHTML="";return}t.altKey&&e.parentElement&&e.parentElement!==document.body&&(e=e.parentElement),lt==="sizes"?fo(e):lt==="type"?ho(e):go(t.altKey?e:mo(e))}))},zt=t=>{lt=t;for(const[e,n]of Object.entries(fe))n.setAttribute("aria-pressed",String(e===t));_(on,t),D({inspect:t}),gt.hidden=!t,gt.innerHTML="",t?document.addEventListener("mousemove",sn):document.removeEventListener("mousemove",sn)};for(const[t,e]of Object.entries(fe))e.addEventListener("click",()=>{t!==lt&&st(!1),zt(lt===t?"":t)});const an=document.querySelector(".dt-notes-btn"),be=[...document.querySelectorAll(".dt-bp")],Ut=document.querySelector(".dt-history-btn"),P=document.querySelector(".dt-history"),ye=document.querySelector(".dt-studio-btn"),E=document.querySelector(".dt-device"),rn=document.querySelector(".dt-shell"),Tt=document.querySelector('.dt-chrome[data-at="top"]'),Vt=document.querySelector('.dt-chrome[data-at="bottom"]'),xt=document.querySelector(".dt-ruler"),z=document.querySelector(".dt-devices"),dt=document.querySelector(".dt-notes-hi"),bo=dt.querySelector(".dt-hi-box"),ln=dt.querySelector(".dt-hi-tag"),yo=[...document.querySelectorAll(".dt-frame-handle")],dn=document.querySelector(".dt-frame-size"),ve=document.querySelector(".dt-frame-rotate"),Mt=document.querySelector(".dt-frame-bars"),A=document.querySelector(".dt-frame"),w=A.querySelector("iframe"),$e=document.querySelector(".dt-notes-count"),f=document.querySelector(".dt-notes-overlay"),vo=".devtools, .dt-tab, .dt-notes-overlay, .dt-history, .dt-frame, .dt-review";for(const t of document.querySelectorAll(vo))for(const e of["pointerdown","mousedown","pointerup","mouseup","touchstart","touchend","click","focusin","focusout"])t.addEventListener(e,n=>n.stopPropagation());const cn="dt-notes";let h=[],M=!1,y=null,d=null,Ee=0,F="",tt=[],S=null,q=[];const Yt=(t=d)=>!!(t&&(t.text?.trim()||t.images?.length)),W=()=>{d&&Yt()&&q.push(d),d=null};let kt=null,X=null;const un=()=>`dt-draft:${K}${v?":canvas":""}`;let ft=un(),Jt=0;const we=()=>{if(!d&&!q.length&&!F){localStorage.removeItem(ft);return}const t={draft:d,parked:q,reply:F?{for:kt,text:F}:null};try{localStorage.setItem(ft,JSON.stringify(t))}catch{const e=n=>({...n,images:void 0});try{localStorage.setItem(ft,JSON.stringify({...t,draft:d&&e(d),parked:q.map(e)}))}catch{}}},Ht=()=>{clearTimeout(Jt),Jt=setTimeout(we,200)};addEventListener("pagehide",()=>{clearTimeout(Jt),we()});let U=localStorage.getItem("dt-resolved")!=="0";const $o=[[/Edg\/(\d+)/,"Edge"],[/OPR\/(\d+)/,"Opera"],[/Firefox\/(\d+)/,"Firefox"],[/Chrome\/(\d+)/,"Chrome"],[/Version\/(\d+).*Safari/,"Safari"]],Eo=[[/iPhone|iPad/,"iOS"],[/Android/,"Android"],[/Mac OS X/,"macOS"],[/Windows/,"Windows"],[/Linux/,"Linux"]],wo=()=>{const t=navigator.userAgent,e=r=>r.find(([c])=>c.test(t)),n=e($o),o=e(Eo),s=n?n[0].exec(t)?.[1]:null;return[n?`${n[1]}${s?" "+s:""}`:"unknown browser",o?.[1]].filter(Boolean).join(" \xB7 ")},et=()=>St(innerWidth),Gt=()=>X??et(),At=()=>{const t=Gt();for(const e of be)e.setAttribute("aria-pressed",String(e.dataset.bp===t))},{cssPath:So,poolOf:Lo,contextOf:To,resolveEl:Z,anchorOf:V}=Es(),pn=t=>{for(let e=t;e&&e!==document.body;e=e.parentElement)if(e.getAnimations().some(n=>n.playState==="running"))return!0;return!1};let Xt=[];const Se=t=>{for(const e of Xt)e.play();Xt=[];for(let e=t;e&&e!==document.body;e=e.parentElement)for(const n of e.getAnimations())n.playState==="running"&&(n.pause(),Xt.push(n))},mn=()=>{if(d)return Z(d);const t=y!=null?h.find(n=>n.id===y):null;if(!t)return null;const e=V(t);return e&&!e.off?Z(t):null},gn=t=>t?new Date(t).toLocaleString(void 0,{day:"numeric",month:"short",hour:"2-digit",minute:"2-digit"}):"",Zt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4 6h12M8 6V4.2h4V6M6.6 6l.55 9.8h5.7L13.4 6"/></svg>',xo='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M3.5 4.5h13v3h-13zM4.8 7.5v8h10.4v-8M8.2 10.5h3.6"/></svg>',Nt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4.8 10.4 8.2 13.8l7-7.6" stroke-linejoin="round"/></svg>',Le='<svg viewBox="0 0 20 20" width="12" height="12" aria-hidden="true"><path d="M12.6 4.4l3 3-8.4 8.4H4.2v-3z" stroke-linejoin="round"/></svg>',Qt='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M5.4 5.4l9.2 9.2M14.6 5.4l-9.2 9.2"/></svg>',Mo='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M12 5l-5 5 5 5" stroke-linejoin="round"/></svg>',ko='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M8 5l5 5-5 5" stroke-linejoin="round"/></svg>',Ho='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M11 2.5 4.5 11h5l-1 6.5L15.5 9h-5z" stroke-linejoin="round"/></svg>',Ao='<svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M4.5 8.5h7.5a3.5 3.5 0 0 1 0 7H8.5M7.5 5.5l-3 3 3 3" stroke-linejoin="round"/></svg>',Ct=t=>`<svg viewBox="0 0 24 24" width="${t}" height="${t}" aria-hidden="true" class="dt-claude"><path d="m4.7144 15.9555 4.7174-2.6471.079-.2307-.079-.1275h-.2307l-.7893-.0486-2.6956-.0729-2.3375-.0971-2.2646-.1214-.5707-.1215-.5343-.7042.0546-.3522.4797-.3218.686.0608 1.5179.1032 2.2767.1578 1.6514.0972 2.4468.255h.3886l.0546-.1579-.1336-.0971-.1032-.0972L6.973 9.8356l-2.55-1.6879-1.3356-.9714-.7225-.4918-.3643-.4614-.1578-1.0078.6557-.7225.8803.0607.2246.0607.8925.686 1.9064 1.4754 2.4893 1.8336.3643.3035.1457-.1032.0182-.0728-.164-.2733-1.3539-2.4467-1.445-2.4893-.6435-1.032-.17-.6194c-.0607-.255-.1032-.4674-.1032-.7285L6.287.1335 6.6997 0l.9957.1336.419.3642.6192 1.4147 1.0018 2.2282 1.5543 3.0296.4553.8985.2429.8318.091.255h.1579v-.1457l.1275-1.706.2368-2.0947.2307-2.6957.0789-.7589.3764-.9107.7468-.4918.5828.2793.4797.686-.0668.4433-.2853 1.8517-.5586 2.9021-.3643 1.9429h.2125l.2429-.2429.9835-1.3053 1.6514-2.0643.7286-.8196.85-.9046.5464-.4311h1.0321l.759 1.1293-.34 1.1657-1.0625 1.3478-.8804 1.1414-1.2628 1.7-.7893 1.36.0729.1093.1882-.0183 2.8535-.607 1.5421-.2794 1.8396-.3157.8318.3886.091.3946-.3278.8075-1.967.4857-2.3072.4614-3.4364.8136-.0425.0304.0486.0607 1.5482.1457.6618.0364h1.621l3.0175.2247.7892.522.4736.6376-.079.4857-1.2142.6193-1.6393-.3886-3.825-.9107-1.3113-.3279h-.1822v.1093l1.0929 1.0686 2.0035 1.8092 2.5075 2.3314.1275.5768-.3218.4554-.34-.0486-2.2039-1.6575-.85-.7468-1.9246-1.621h-.1275v.17l.4432.6496 2.3436 3.5214.1214 1.0807-.17.3521-.6071.2125-.6679-.1214-1.3721-1.9246L14.38 17.959l-1.1414-1.9428-.1397.079-.674 7.2552-.3156.3703-.7286.2793-.6071-.4614-.3218-.7468.3218-1.4753.3886-1.9246.3157-1.53.2853-1.9004.17-.6314-.0121-.0425-.1397.0182-1.4328 1.9672-2.1796 2.9446-1.7243 1.8456-.4128.164-.7164-.3704.0667-.6618.4008-.5889 2.386-3.0357 1.4389-1.882.929-1.0868-.0062-.1579h-.0546l-6.3385 4.1164-1.1293.1457-.4857-.4554.0608-.7467.2307-.2429 1.9064-1.3114Z"/></svg>`,fn=()=>{try{return localStorage.getItem("nm-for")??"claude"}catch{return"claude"}},Bt=t=>t==="claude"?"#d97757":t?"#0d99ff":"#717171",hn=(t,e)=>`<label class="dt-field" title="Who it is for"><span class="dt-field-box" style="--cat:${Bt(t)}"><select class="dt-for-select"${e?` data-id="${e}"`:""} aria-label="Who this is for">
2
+ <option value="claude" data-c="${Bt("claude")}"${t==="claude"?" selected":""}>AI agent</option>
3
+ <option value="" data-c="${Bt("")}"${t?"":" selected"}>Anyone</option>
4
+ ${(b.team??[]).filter(n=>n.email!==b.me?.email).map(n=>`<option value="${g(n.email)}" data-c="${Bt(n.email)}"${t===n.email?" selected":""}>${g(n.name||n.email)}</option>`).join("")}
5
+ </select></span></label>`,bn=t=>{const e=wt(t?.textContent).replace(/\s+/g," ");return e&&e.length<=2e3?e:""},No=t=>`<div class="dt-suggest dt-suggest--read"><del>${g(t.from)}</del><ins>${g(t.to)}</ins></div>`,yn=t=>wt(t)?`<span class="dt-note-info" data-tip="${g(wt(t))}"
6
+ ><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><circle cx="10" cy="10" r="7.4"/><path d="M10 9.2v4.4M10 6.4v.6"/></svg></span>`:"",vn=(t,e)=>`<label class="dt-field" title="Type"><span class="dt-field-box" style="--cat:${de(t).color}"><select class="dt-cat-select"${e?` data-id="${e}"`:""} aria-label="Type">${Xe.map(n=>`<option value="${n.id}" data-c="${n.color}"${n.id===t?" selected":""}>${n.label}</option>`).join("")}</select></span></label>`,$n=[["urgent","Urgent","#e5484d"],["high","High","#ff5a00"],["normal","Normal","#f5c451"],["low","Low","#4f8f41"]],En=(t,e)=>{const n=t&&t!=="normal"?t:"normal";return`<label class="dt-field" title="Priority"><span class="dt-field-box${n==="normal"?" dt-field-box--unset":""}" style="--cat:${$n.find(o=>o[0]===n)[2]}"><select class="dt-prio-select"${e?` data-id="${e}"`:""} aria-label="Priority">${$n.map(([o,s,r])=>`<option value="${o}" data-c="${r}" data-label="${s}"${o===n?" selected":""}>${o==="normal"&&o===n?"Priority":s}</option>`).join("")}</select></span></label>`},Co='<svg viewBox="0 0 20 20" width="9" height="9" aria-hidden="true"><path d="M5.5 5.5l9 9M14.5 5.5l-9 9"/></svg>',wn=t=>t.startsWith("data:video/")||/\.webm(\?|$)/i.test(t),Sn=(t,e,n=t)=>`<span class="dt-shot${wn(n)?" dt-shot--video":""}">${wn(n)?`<video src="${t}" controls preload="metadata" playsinline></video>`:`<a href="${t}" target="_blank"><img src="${t}" alt="" loading="lazy" /></a>`}${e===void 0?"":`<button class="dt-shot-rm" data-act="unshot" ${e} aria-label="Remove">${Co}</button>`}</span>`,Ln=(t=[],e)=>t.length?`<div class="dt-note-shots">${t.map(n=>{const o=n.split("/").pop(),s=hs(o);return Sn(s,e===void 0?void 0:`data-id="${e}" data-img="${g(o)}"`,o)}).join("")}</div>`:"",Tn=(t=[])=>t.length?`<div class="dt-note-shots">${t.map((e,n)=>Sn(e,`data-i="${n}"`)).join("")}</div>`:"",Bo='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><rect x="2.5" y="5.5" width="11" height="9" rx="2"/><path d="m13.5 9 4-2.5v7l-4-2.5"/></svg>',Io='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><path d="M3.5 5.5h8M7.5 5.5v10M11 15.5l5-5 1.5 1.5-5 5H11z" stroke-linejoin="round"/></svg>',qo=!!navigator.mediaDevices?.getDisplayMedia&&typeof MediaRecorder<"u";let ct=null;const Ro=async t=>{if(ct){ct.stop();return}let e;try{e=await navigator.mediaDevices.getDisplayMedia({video:{frameRate:12},audio:!1})}catch{return}const n=await navigator.mediaDevices.getUserMedia({audio:!0}).catch(()=>null),o=new MediaStream([...e.getVideoTracks(),...n?.getAudioTracks()??[]]),s=["video/webm;codecs=vp9,opus","video/webm;codecs=vp8,opus","video/webm"].find(l=>MediaRecorder.isTypeSupported(l));if(!s){for(const l of e.getTracks())l.stop();j("This browser cannot record WebM video.");return}const r=new MediaRecorder(o,{mimeType:s,videoBitsPerSecond:6e5,audioBitsPerSecond:32e3}),c=[],u=!!Number(t?.dataset.id);r.ondataavailable=l=>{l.data.size&&c.push(l.data)};const a=setTimeout(()=>{r.state!=="inactive"&&r.stop()},3e4);r.onstop=async()=>{clearTimeout(a);for(const L of[...e.getTracks(),...n?.getTracks()??[]])L.stop();ct=null;const l=new Blob(c,{type:"video/webm"});if(l.size>32e5){j("That recording is too big to send \u2014 keep it shorter."),m();return}const p=await new Promise(L=>{const i=new FileReader;i.onload=()=>L(String(i.result)),i.readAsDataURL(l)});u?tt.push(p):d&&(d.images??=[]).push(p),m()},e.getVideoTracks()[0]?.addEventListener("ended",()=>{r.state!=="inactive"&&r.stop()}),ct=r,r.start(1e3),m()},Do='<svg viewBox="0 0 20 20" width="15" height="15" aria-hidden="true"><rect x="3" y="4" width="14" height="12" rx="2"/><circle cx="7.5" cy="8.5" r="1.4"/><path d="m3.5 14.5 4-4 3 3 2-2 4 4"/></svg>',xn=(t,e,n,o,s="",r="")=>`<div class="dt-note-foot"><div class="dt-compose">
7
7
  <textarea class="${t}" rows="1" placeholder="${e}">${g(n)}</textarea>
8
8
  ${s}
9
9
  <div class="dt-compose-bar">
10
- <span class="dt-compose-tools"><button class="dt-attach" data-act="attach" title="Attach a screenshot \u2014 or paste or drop one">${Go}</button>
11
- ${Wo&&zo?`<button class="dt-record${pt?" is-on":""}" data-act="record" title="${pt?"Stop recording":"Record the screen, up to 30 seconds"}">${pt?"Stop":jo}</button>`:""}</span>
10
+ <span class="dt-compose-tools"><button class="dt-attach" data-act="attach" title="Attach a screenshot \u2014 or paste or drop one">${Do}</button>
11
+ ${r}${qo?`<button class="dt-record${ct?" is-on":""}" data-act="record" title="${ct?"Stop recording":"Record the screen, up to 30 seconds"}">${ct?"Stop":Bo}</button>`:""}</span>
12
12
  <button class="dt-send${n.trim()?" is-ready":""}" ${o} title="Send (Enter)"
13
13
  ><svg viewBox="0 0 20 20" width="14" height="14" aria-hidden="true"><path d="M10 15.5v-11M5.5 9 10 4.5 14.5 9"/></svg></button>
14
14
  </div>
15
- </div></div>`,xe=(t,e)=>(t||"element")+(e?.[0]?"."+e[0]:""),Nn=()=>R.map((t,e)=>({i:e,el:xe(t.tag,t.classes),text:K(t.text??""),shots:t.images?.length??0,orphan:!V(t)}));let Te=[],Bn="";const Yo=(t,e)=>t!=="claude"?"":`<button class="dt-note-state" data-act="reopen" data-id="${e}"
16
- title="Resolved by ${g(dt(h.find(n=>n.id===e)?.doneAgent))} \u2014 click to clear">${kt(13)}</button>`,Rn=(t,e)=>{const n=t==="done";return`${Yo(t,e)}<button data-act="${n?"reopen":"done"}" data-id="${e}"
17
- class="dt-note-resolve${n?" is-on":""}" title="${n?"Reopen":t==="claude"?"Looks right \u2014 mark it resolved":"Resolve"}">${Se}</button>`},Vo=(t,e)=>U("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(e?{id:t,status:"done",doneBy:"you"}:{id:t,status:"open",doneBy:null})}),Ht=async(t,e,n)=>{const o=h,s=ot;h=t(h),ot=t(ot),p();const r=await e().catch(()=>null);if(!r?.ok){h=o,ot=s,p(),st(`${n} did not go through${r?` (${r.status})`:""}.`);return}Zt()},Ut=(t,e)=>Ht(n=>n.map(o=>o.id===t?{...o,status:e?"done":"open",doneBy:e?"you":null}:o),()=>Vo(t,e),e?"Resolving":"Reopening"),qn=t=>Ht(e=>e.filter(n=>n.id!==t),()=>U(`comments?id=${t}`,{method:"DELETE"}),"Deleting"),g=t=>t.replace(/[&<>"]/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[e]),Uo=t=>{const e=h.filter(s=>ct(s)===t),n=e.filter(s=>O(s)==="open").length,o=e.filter(s=>O(s)==="claude").length;be.innerHTML=n?String(n):o?kt(9):"\u2713",be.dataset.state=n?"open":o?"claude":"done",be.hidden=e.length===0},p=()=>{if(zt(),$){const a=Nn(),l=JSON.stringify(a);l!==Bn&&(Bn=l,parent.postMessage({dt:!0,drafts:a},location.origin))}Mt(),y!==Tt&&(F="",Q=[],Tt=y),L&&L.id!==y&&(L=null);const t=_t();if(Uo(t),!H){f.innerHTML="",we(null);return}const e=t;let n="";const o=h.filter(a=>ct(a)===e&&(tt||O(a)!=="done"));for(const a of o){const l=V(a);if(!l&&y!==a.id)continue;const m=O(a),b=m==="done",i=!l,v=l??{x:0,y:0},x=oe(a.category),N=vs(a);if(i||(n+=`<button class="dt-pin dt-pin--${m}${N?" dt-pin--working":""}" data-id="${a.id}"${l?.off?` data-off="${l.off}"`:""} aria-label="Comment ${a.id}, ${m==="open"?"open":m==="claude"?`resolved by ${g(dt(a.doneAgent))}`:"resolved"}" aria-expanded="${y===a.id}"
18
- style="left:${v.x}px;top:${v.y}px;--cat:${x.color}"
19
- title="${g(a.text.slice(0,80))} \xB7 ${x.label}${N?` \xB7 ${g(dt(N.agent))} is on it`:""}${m==="claude"?` \xB7 resolved by ${g(dt(a.doneAgent))} \u2014 tick to confirm`:m==="done"?" \xB7 resolved":""}">${m==="done"?"\u2713":m==="claude"?kt(11):""}</button>`),y===a.id){const lt=ys(a);n+=`<div class="dt-note${i?" dt-note--orphan":""}" data-id="${a.id}" role="dialog" aria-label="Comment ${a.id}"
20
- style="left:${v.x}px;top:${v.y}px">
15
+ </div></div>`,Te=(t,e)=>(t||"element")+(e?.[0]?"."+e[0]:""),Mn=()=>q.map((t,e)=>({i:e,el:Te(t.tag,t.classes),text:wt(t.text??""),shots:t.images?.length??0,orphan:!V(t)}));let xe=[],kn="";const Oo=(t,e)=>t!=="claude"?"":`<button class="dt-note-state" data-act="reopen" data-id="${e}"
16
+ title="Resolved by ${g(J(h.find(n=>n.id===e)?.doneAgent))} \u2014 click to clear">${Ct(13)}</button>`,Hn=(t,e)=>{const n=t==="done";return`${Oo(t,e)}<button data-act="${n?"reopen":"done"}" data-id="${e}"
17
+ class="dt-note-resolve${n?" is-on":""}" title="${n?"Reopen":t==="claude"?"Looks right \u2014 mark it resolved":"Resolve"}">${Nt}</button>`},Po=(t,e)=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(e?{id:t,status:"done",doneBy:"you"}:{id:t,status:"open",doneBy:null})}),nt=async(t,e,n)=>{const o=h,s=Y;h=t(h),Y=t(Y),m();const r=await e().catch(()=>null);if(!r?.ok){h=o,Y=s,m(),j(`${n} did not go through${r?` (${r.status})`:""}.`);return}se()},It=(t,e)=>nt(n=>n.map(o=>o.id===t?{...o,status:e?"done":"open",doneBy:e?"you":null}:o),()=>Po(t,e),e?"Resolving":"Reopening"),jo=t=>nt(e=>e.map(n=>n.id===t?{...n,status:"done",doneBy:n.status==="done"?n.doneBy:"you",archivedAt:new Date().toISOString()}:n),()=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:t,archive:!0})}),"Archiving"),An=t=>nt(e=>e.filter(n=>n.id!==t),()=>B(`comments?id=${t}`,{method:"DELETE"}),"Deleting"),g=t=>t.replace(/[&<>"]/g,e=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[e]),Ko=t=>{const e=h.filter(s=>G(s)===t),n=e.filter(s=>C(s)==="open").length,o=e.filter(s=>C(s)==="claude").length;$e.innerHTML=n?String(n):o?Ct(9):"\u2713",$e.dataset.state=n?"open":o?"claude":"done",$e.hidden=e.length===0},m=()=>{if(Ht(),v){const a=Mn(),l=JSON.stringify(a);l!==kn&&(kn=l,parent.postMessage({dt:!0,drafts:a},location.origin))}At(),y!==kt&&(F="",tt=[],kt=y),S&&S.id!==y&&(S=null);const t=Gt();if(Ko(t),!M){f.innerHTML="",Se(null);return}const e=t;let n="";const o=h.filter(a=>G(a)===e&&(U||C(a)!=="done"));for(const a of o){const l=V(a);if(!l&&y!==a.id)continue;const p=C(a),L=p==="done",i=!l,x=l??{x:0,y:0},H=de(a.category),N=ms(a);if(i||(n+=`<button class="dt-pin dt-pin--${p}${N?" dt-pin--working":""}" data-id="${a.id}"${l?.off?` data-off="${l.off}"`:""} aria-label="Comment ${a.id}, ${p==="open"?"open":p==="claude"?`resolved by ${g(J(a.doneAgent))}`:"resolved"}" aria-expanded="${y===a.id}"
18
+ style="left:${x.x}px;top:${x.y}px;--cat:${H.color}"
19
+ title="${g(a.text.slice(0,80))} \xB7 ${H.label}${N?` \xB7 ${g(J(N.agent))} is on it`:""}${p==="claude"?` \xB7 resolved by ${g(J(a.doneAgent))} \u2014 tick to confirm`:p==="done"?" \xB7 resolved":""}">${p==="done"?"\u2713":p==="claude"?Ct(11):""}</button>`),y===a.id){const it=ps(a);n+=`<div class="dt-note${i?" dt-note--orphan":""}" data-id="${a.id}" role="dialog" aria-label="Comment ${a.id}"
20
+ style="left:${x.x}px;top:${x.y}px">
21
21
  <div class="dt-note-bar">
22
- <span class="dt-note-el">${g(xe(a.tag,a.classes))}</span>
23
- ${xn(a.label)}
22
+ <span class="dt-note-el">${b.client?`Comment #${Wo(a)}`:g(Te(a.tag,a.classes))}</span>
23
+ ${yn(a.label)}
24
24
  <span class="dt-note-tools">
25
- ${Rn(m,a.id)}
25
+ ${!b.client&&p==="open"&&!us(a)?`<button data-act="fixnow" data-id="${a.id}" title="Fix now \u2014 the agent in turbo takes it next, even while paused">${Ho}</button>`:""}
26
+ ${Hn(p,a.id)}
26
27
  <i class="dt-note-sep"></i>
27
- <button data-act="rm" data-id="${a.id}" title="Delete this thread">${Yt}</button>
28
- <button data-act="close" data-id="${a.id}" title="Close">${Vt}</button>
28
+ ${b.client?"":`<button data-act="archive" data-id="${a.id}" title="Archive \u2014 resolved and put away">${xo}</button>`}
29
+ <button data-act="rm" data-id="${a.id}" title="Delete this thread">${Zt}</button>
30
+ <button data-act="close" data-id="${a.id}" title="Close">${Qt}</button>
29
31
  </span>
30
32
  </div>
31
- ${N?`<p class="dt-note-working"><i></i>${g(dt(N.agent))} is on it</p>`:""}
33
+ ${N?`<p class="dt-note-working"><i></i>${g(J(N.agent))} is on it</p>`:""}
32
34
  ${i?'<p class="dt-note-orphan">The element this was pinned to is not on the page right now.</p>':""}
33
- <div class="dt-note-meta">${Tn(oe(a.category).id,a.id)}${Sn(a.assignee??"",a.id)}</div>
35
+ ${(()=>{const T=vn(de(a.category).id,a.id)+(b.client?"":hn(a.assignee??"",a.id)+En(a.priority,a.id))+(a.host&&a.host!==location.host?`<span class="dt-note-host" title="Written on ${g(a.host)}">${g(a.host)}</span>`:"");return T?`<div class="dt-note-meta">${T}</div>`:""})()}
34
36
  <div class="dt-note-thread">
35
- ${lt.map((T,$t)=>{const mo=$t===0?null:T.at??null,Ve=T.author==="you"&&(!T.by||T.by===M.me?.email),po=Ve&&L?.id===a.id&&L.at===mo,Ue=T.author==="claude"?null:M.team?.find(Je=>Je.email===T.by),fs=T.author==="claude"?dt(T.agent):Ve?"You":Ue?.name||T.byName||T.by||"You",go=`<div class="dt-msg-head">${Ue?.avatar_url?`<img class="dt-msg-face" src="${g(Ue.avatar_url)}" alt="">`:""}<b>${g(fs)}</b><time>${$n(T.at)}</time>${Ve&&!po?`<button class="dt-msg-edit" data-act="edit" data-id="${a.id}" data-at="${g(mo??"")}" title="Edit">${Le}</button>`:""}</div>`;return po?`<div class="dt-msg">${go}<div class="dt-compose">
36
- <textarea class="dt-note-edit-input" rows="1">${g(L.text)}</textarea>
37
- ${Hn(T.images.filter(Je=>!L.drop.includes(Je.split("/").pop())),a.id)}
37
+ ${it.map((T,Et)=>{const ro=Et===0?null:T.at??null,Ye=T.author==="you"&&(!T.by||T.by===b.me?.email),io=Ye&&S?.id===a.id&&S.at===ro,Je=T.author==="claude"?null:b.team?.find(Ge=>Ge.email===T.by),ls=T.author==="claude"?J(T.agent):Ye?"You":Je?.name||T.byName||T.by||"You",lo=`<div class="dt-msg-head">${Je?.avatar_url?`<img class="dt-msg-face" src="${g(Je.avatar_url)}" alt="">`:""}<b>${g(ls)}</b><time>${gn(T.at)}</time>${Ye&&!io?`<button class="dt-msg-edit" data-act="edit" data-id="${a.id}" data-at="${g(ro??"")}" title="Edit">${Le}</button>`:""}</div>`;return io?`<div class="dt-msg">${lo}<div class="dt-compose">
38
+ <textarea class="dt-note-edit-input" rows="1">${g(S.text)}</textarea>
39
+ ${Ln(T.images.filter(Ge=>!S.drop.includes(Ge.split("/").pop())),a.id)}
38
40
  <div class="dt-compose-bar">
39
41
  <button class="dt-edit-cancel" data-act="edit-cancel">Cancel</button>
40
- <button class="dt-send${L.text.trim()?" is-ready":""}" data-act="edit-save" title="Save (Enter)">${Se}</button>
42
+ <button class="dt-send${S.text.trim()?" is-ready":""}" data-act="edit-save" title="Save (Enter)">${Nt}</button>
41
43
  </div>
42
- </div></div>`:`<div class="dt-msg" data-msg="${a.id}:${g(T.at??"0")}">${go}<p>${g(T.text)}</p>${$t===0&&a.suggest?Po(a.suggest):""}${Hn(T.images)}</div>`}).join("")}
44
+ </div></div>`:`<div class="dt-msg" data-msg="${a.id}:${g(T.at??"0")}">${lo}<p>${g(T.text)}</p>${Et===0&&a.suggest?No(a.suggest):""}${Ln(T.images)}</div>`}).join("")}
43
45
  </div>
44
- ${Cn("dt-note-reply-input","Reply",F,`data-act="reply" data-id="${a.id}"`,An(Q))}
45
- </div>`}}R.forEach((a,l)=>{const m=V(a);m&&(n+=`<button class="dt-pin dt-pin--draft" data-parked="${l}" data-act="draft-open" data-i="${l}"
46
- style="left:${m.x}px;top:${m.y}px" title="Draft, not sent \u2014 click to finish it">${Le}</button>`)});const s=u&&V(u);if(u){const a=s?.x??0,l=s?.y??0;n+=`${s?`<span class="dt-pin dt-pin--draft" data-draft style="left:${a}px;top:${l}px"></span>`:""}
46
+ ${xn("dt-note-reply-input","Reply",F,`data-act="reply" data-id="${a.id}"`,Tn(tt))}
47
+ </div>`}}q.forEach((a,l)=>{const p=V(a);p&&(n+=`<button class="dt-pin dt-pin--draft" data-parked="${l}" data-act="draft-open" data-i="${l}"
48
+ style="left:${p.x}px;top:${p.y}px" title="Draft, not sent \u2014 click to finish it">${Le}</button>`)});const s=d&&V(d);if(d){const a=s?.x??0,l=s?.y??0;n+=`${s?`<span class="dt-pin dt-pin--draft" data-draft style="left:${a}px;top:${l}px"></span>`:""}
47
49
  <div class="dt-note${s?"":" dt-note--orphan"}" data-draft style="left:${a}px;top:${l}px">
48
50
  <div class="dt-note-bar">
49
- <span class="dt-note-el">${g(xe(u.tag,u.classes))}</span>
50
- ${xn(u.label)}
51
- ${Kt()?'<span class="dt-note-draft">Draft</span>':""}
51
+ <span class="dt-note-el">${b.client?"New comment":g(Te(d.tag,d.classes))}</span>
52
+ ${yn(d.label)}
53
+ ${Yt()?'<span class="dt-note-draft">Draft</span>':""}
52
54
  <span class="dt-note-tools">
53
- <button data-act="discard" title="Discard this draft">${Yt}</button>
54
- <button data-act="cancel" title="Close \u2014 the draft stays">${Vt}</button>
55
+ <button data-act="discard" title="Discard this draft">${Zt}</button>
56
+ <button data-act="cancel" title="Close \u2014 the draft stays">${Qt}</button>
55
57
  </span>
56
58
  </div>
57
59
  ${s?"":'<p class="dt-note-orphan">The element this was pinned to is not on the page right now.</p>'}
58
- ${(()=>{const m=s?Y(u):null,b=m&&h.find(i=>i.id>0&&O(i)==="open"&&Y(i)===m);return b?`<p class="dt-note-twin">Already open here: \u201C${g(b.text.slice(0,60))}${b.text.length>60?"\u2026":""}\u201D <button data-act="twin" data-id="${b.id}">Open it</button></p>`:""})()}
59
- <div class="dt-note-meta">${Tn(u.category)}${Sn(u.assignee??En())}</div>
60
- ${u.suggest?`<div class="dt-suggest"><span class="dt-suggest-head">Should read<button data-act="unsuggest" title="No text change">${Vt}</button></span>
61
- <textarea class="dt-suggest-input" rows="2">${g(u.suggest.to)}</textarea></div>`:Ko&&Ln(s?Y(u):null)?'<button class="dt-suggest-btn" data-act="suggest">Suggest the text</button>':""}
62
- ${Cn("dt-note-input",u.suggest?"Why (optional)":"Comment",u.text??"",'data-act="save"',An(u.images))}
63
- </div>`}const r=new Map([...f.querySelectorAll(".dt-note[data-id] .dt-note-thread")].map(a=>[a.closest(".dt-note").dataset.id,{top:a.scrollTop,end:a.scrollTop+a.clientHeight>=a.scrollHeight-4}])),c=new Set([...f.querySelectorAll("[data-msg]")].map(a=>a.dataset.msg));f.innerHTML=n;for(const a of f.querySelectorAll(".dt-note[data-id] .dt-note-thread")){const l=a.closest(".dt-note").dataset.id,m=r.get(l);if(!m)continue;const b=[...a.querySelectorAll("[data-msg]")].filter(i=>!c.has(i.dataset.msg));for(const i of b)i.classList.add("dt-msg--new");a.scrollTop=m.end&&b.length?a.scrollHeight:m.top}for(const a of f.querySelectorAll(".dt-note")){const l=a.getBoundingClientRect();l.bottom>innerHeight-8&&(a.dataset.flip="1"),l.right>innerWidth-8&&(a.dataset.flipx="1")}In(e),we(vn()),nt();for(const a of f.querySelectorAll(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input"))De(a);const d=f.querySelector(".dt-note-input");d&&(d.focus(),d.setSelectionRange(d.value.length,d.value.length))},Jo=()=>{let t=!1;for(const e of f.querySelectorAll(".dt-pin[data-id], .dt-note[data-id]")){if(e.classList.contains("dt-note--orphan"))continue;const n=h.find(s=>s.id===Number(e.dataset.id)),o=n&&V(n);if(!o){e.style.visibility="hidden";continue}e.style.visibility="",e.style.left=`${o.x}px`,e.style.top=`${o.y}px`,e.classList.contains("dt-pin")&&(o.off?e.dataset.off=o.off:delete e.dataset.off),n&&yn(Y(n))&&(t=!0)}for(const e of f.querySelectorAll("[data-draft], [data-parked]")){if(e.classList.contains("dt-note--orphan"))continue;const n=e.dataset.parked?R[Number(e.dataset.parked)]:u,o=n&&V(n);if(!o){e.style.visibility="hidden";continue}e.style.visibility="",e.style.left=`${o.x}px`,e.style.top=`${o.y}px`}if(!Gt.length&&(u||y!=null)){const e=vn();e&&yn(e)&&we(e)}t&&nt()},In=t=>{if(D.hidden)return;const e=h.filter(i=>ct(i)===t),n=new Map(e.map((i,v)=>[i.id,v+1])),o={open:[],claude:[],done:[]};for(const i of e)o[O(i)].push(i);const s=i=>{const v=(i.replies?.length??0)+(i.note?1:0),x=oe(i.category),N=O(i),lt=N==="claude",T=!V(i),$t=i.replies?.length?i.replies[i.replies.length-1]:i.note?{author:"claude",text:i.note}:{author:"you",text:i.text};return`<div class="dt-hist-row is-${N}${T?" is-orphan":""}">
60
+ ${(()=>{const p=s?Z(d):null,L=p&&h.find(i=>i.id>0&&C(i)==="open"&&Z(i)===p);return L?`<p class="dt-note-twin">Already open here: \u201C${g(L.text.slice(0,60))}${L.text.length>60?"\u2026":""}\u201D <button data-act="twin" data-id="${L.id}">Open it</button></p>`:""})()}
61
+ <div class="dt-note-meta">${vn(d.category)}${b.client?"":hn(d.assignee??fn())+En(d.priority)}</div>
62
+ ${d.suggest?`<div class="dt-suggest"><span class="dt-suggest-head">Should read<button data-act="unsuggest" title="No text change">${Qt}</button></span>
63
+ <textarea class="dt-suggest-input" rows="2">${g(d.suggest.to)}</textarea></div>`:""}
64
+ ${xn("dt-note-input",d.suggest?"Why (optional)":"Comment",d.text??"",'data-act="save"',Tn(d.images),!d.suggest&&bn(s?Z(d):null)?`<button class="dt-attach" data-act="suggest" title="Suggest the new text">${Io}</button>`:"")}
65
+ </div>`}const r=new Map([...f.querySelectorAll(".dt-note[data-id] .dt-note-thread")].map(a=>[a.closest(".dt-note").dataset.id,{top:a.scrollTop,end:a.scrollTop+a.clientHeight>=a.scrollHeight-4}])),c=new Set([...f.querySelectorAll("[data-msg]")].map(a=>a.dataset.msg));f.innerHTML=n;for(const a of f.querySelectorAll(".dt-note[data-id] .dt-note-thread")){const l=a.closest(".dt-note").dataset.id,p=r.get(l);if(!p)continue;const L=[...a.querySelectorAll("[data-msg]")].filter(i=>!c.has(i.dataset.msg));for(const i of L)i.classList.add("dt-msg--new");a.scrollTop=p.end&&L.length?a.scrollHeight:p.top}for(const a of f.querySelectorAll(".dt-note")){const l=a.getBoundingClientRect();l.bottom>innerHeight-8&&(a.dataset.flip="1"),l.right>innerWidth-8&&(a.dataset.flipx="1")}Nn(e),Se(mn()),ot();for(const a of f.querySelectorAll(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input"))De(a);const u=f.querySelector(".dt-note-input");u&&(u.focus(),u.setSelectionRange(u.value.length,u.value.length))},Fo=()=>{let t=!1;for(const e of f.querySelectorAll(".dt-pin[data-id], .dt-note[data-id]")){if(e.classList.contains("dt-note--orphan"))continue;const n=h.find(s=>s.id===Number(e.dataset.id)),o=n&&V(n);if(!o){e.style.visibility="hidden";continue}e.style.visibility="",e.style.left=`${o.x}px`,e.style.top=`${o.y}px`,e.classList.contains("dt-pin")&&(o.off?e.dataset.off=o.off:delete e.dataset.off),n&&pn(Z(n))&&(t=!0)}for(const e of f.querySelectorAll("[data-draft], [data-parked]")){if(e.classList.contains("dt-note--orphan"))continue;const n=e.dataset.parked?q[Number(e.dataset.parked)]:d,o=n&&V(n);if(!o){e.style.visibility="hidden";continue}e.style.visibility="",e.style.left=`${o.x}px`,e.style.top=`${o.y}px`}if(!Xt.length&&(d||y!=null)){const e=mn();e&&pn(e)&&Se(e)}t&&ot()},Wo=t=>h.filter(e=>G(e)===G(t)).findIndex(e=>e.id===t.id)+1,Nn=t=>{if(P.hidden)return;const e=h.filter(i=>G(i)===t),n=new Map(e.map((i,x)=>[i.id,x+1])),o={open:[],claude:[],done:[]};for(const i of e)o[C(i)].push(i);const s=i=>{const x=(i.replies?.length??0)+(i.note?1:0),H=de(i.category),N=C(i),it=N==="claude",T=!V(i),Et=i.replies?.length?i.replies[i.replies.length-1]:i.note?{author:"claude",text:i.note}:{author:"you",text:i.text};return`<div class="dt-hist-row is-${N}${T?" is-orphan":""}">
64
66
  <button class="dt-hist-go" data-go="${i.id}">
65
- <span class="dt-hist-n" style="--cat:${x.color}">${lt?kt(8):""}</span>
67
+ <span class="dt-hist-n" style="--cat:${H.color}">${it?Ct(8):""}</span>
66
68
  <span class="dt-hist-body">
67
- <span class="dt-hist-id">#${n.get(i.id)}<em>${x.label}</em>${lt?`<b class="dt-hist-claude">${kt(9)}${g(dt(i.doneAgent))}</b>`:""}${T?'<b class="dt-hist-orphan" title="The element this was pinned to is not on the page right now">no pin</b>':""}</span>
68
- <span class="dt-hist-text">${$t.author==="claude"?`<b>${g(dt($t.agent))}:</b> `:""}${g($t.text)}</span>
69
- <span class="dt-hist-meta">${$n(i.updatedAt||i.createdAt)}${i.device?` \xB7 ${g(i.device)}`:i.browser?` \xB7 ${g(i.browser)}`:""}${v?` \xB7 ${v} repl${v===1?"y":"ies"}`:""}</span>
69
+ <span class="dt-hist-id">#${n.get(i.id)}<em>${H.label}</em>${it?`<b class="dt-hist-claude" data-unmark="${i.id}" role="button" tabindex="0" title="Resolved by ${g(J(i.doneAgent))} \u2014 click to clear: back to open">${Ct(9)}${g(J(i.doneAgent))}<i aria-hidden="true">\xD7</i></b>`:""}${T?'<b class="dt-hist-orphan" title="The element this was pinned to is not on the page right now">no pin</b>':""}</span>
70
+ <span class="dt-hist-text">${Et.author==="claude"?`<b>${g(J(Et.agent))}:</b> `:""}${g(Et.text)}</span>
71
+ <span class="dt-hist-meta">${gn(i.updatedAt||i.createdAt)}${i.device?` \xB7 ${g(i.device)}`:i.browser?` \xB7 ${g(i.browser)}`:""}${x?` \xB7 ${x} repl${x===1?"y":"ies"}`:""}</span>
70
72
  </span>
71
73
  </button>
72
- <span class="dt-note-tools dt-hist-tools">${Rn(N,i.id)}<i class="dt-note-sep"></i
73
- ><button data-rm="${i.id}" title="Delete this comment">${Yt}</button></span>
74
- </div>`},r=B.find(i=>i.id===t),c=B.map(i=>{const v=h.filter(x=>ct(x)===i.id&&O(x)!=="done");return{band:i,open:v.filter(x=>O(x)==="open").length,total:v.length}}).filter(i=>i.total&&i.band.id!==t),d=c.length?`<i class="dt-hist-sep"></i><div class="dt-hist-bands">${c.map(({band:i,open:v,total:x})=>`<button data-bp="${i.id}" data-state="${v?"open":"claude"}"
75
- title="${i.label}: ${v} open \xB7 ${x-v} to check"
76
- ><svg viewBox="0 0 20 20" width="11" height="11" aria-hidden="true">${i.icon}</svg><i>${x}</i></button>`).join("")}</div>`:"",l=["open","claude","done"].filter(i=>o[i].length&&(i!=="done"||tt)),m=C.hidden?Nn():Te,b=i=>`<div class="dt-hist-row is-draft">
74
+ <span class="dt-note-tools dt-hist-tools">${Hn(N,i.id)}<i class="dt-note-sep"></i
75
+ ><button data-rm="${i.id}" title="Delete this comment">${Zt}</button></span>
76
+ </div>`},r=I.find(i=>i.id===t),c=I.map(i=>{const x=h.filter(H=>G(H)===i.id&&C(H)!=="done");return{band:i,open:x.filter(H=>C(H)==="open").length,total:x.length}}).filter(i=>i.total&&i.band.id!==t),u=c.length?`<i class="dt-hist-sep"></i><div class="dt-hist-bands">${c.map(({band:i,open:x,total:H})=>`<button data-bp="${i.id}" data-state="${x?"open":"claude"}"
77
+ title="${i.label}: ${x} open \xB7 ${H-x} to check"
78
+ ><svg viewBox="0 0 20 20" width="11" height="11" aria-hidden="true">${i.icon}</svg><i>${H}</i></button>`).join("")}</div>`:"",l=["open","claude","done"].filter(i=>o[i].length&&(i!=="done"||U)),p=A.hidden?Mn():xe,L=i=>`<div class="dt-hist-row is-draft">
77
79
  <button class="dt-hist-go" data-draft-go="${i.i}">
78
80
  <span class="dt-hist-n">${Le}</span>
79
81
  <span class="dt-hist-body">
@@ -81,21 +83,29 @@ import{categoryOf as oe}from"../store/categories.mjs";import{stateOf as O,STATE_
81
83
  <span class="dt-hist-text">${i.text?g(i.text):`${i.shots} screenshot${i.shots===1?"":"s"}`}</span>
82
84
  </span>
83
85
  </button>
84
- <span class="dt-note-tools dt-hist-tools"><button data-draft-rm="${i.i}" title="Discard this draft">${Yt}</button></span>
85
- </div>`;D.innerHTML=`<div class="dt-hist-head">
86
+ <span class="dt-note-tools dt-hist-tools"><button data-draft-rm="${i.i}" title="Discard this draft">${Zt}</button></span>
87
+ </div>`;P.innerHTML=`<div class="dt-hist-head">
86
88
  <span class="dt-hist-here" title="${r?.label??t}"
87
89
  ><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true">${r?.icon??""}</svg></span>
88
90
  <span class="dt-hist-title">Comments</span>
89
- ${d}
90
- ${Ct().length&&!$?`<button class="dt-review-btn" data-review title="${Ct().length} ${Ct().length===1?"fix waits":"fixes wait"} for a look across every page of the project \u2014 the list below is this page only. Walk through them">Check all ${Ct().length}</button>`:""}
91
+ ${u}
92
+ ${ut().length&&!v?`<button class="dt-review-btn" data-review aria-label="Check all ${ut().length} ${ut().length===1?"fix":"fixes"}" data-tip="${ut().length} ${ut().length===1?"fix waits":"fixes wait"} for a look across every page \u2014 walk through them">${Nt}${ut().length}</button>`:""}
91
93
  <button class="dt-hist-refresh" data-refresh aria-label="Reload comments from the file">
92
94
  <svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M16 10a6 6 0 1 1-1.8-4.3"/><path d="M16.3 3.4v3.4h-3.4"/></svg>
93
95
  </button>
94
96
  <button class="dt-hist-fold" data-fold aria-label="Collapse or expand the panel">
95
97
  <svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><path d="M5.5 8.5 10 12.5l4.5-4"/></svg>
96
98
  </button>
97
- </div>`+(l.length||m.length?`<div class="dt-hist-list">${m.length?`<p class="dt-hist-group">Drafts<em>${m.length}</em></p>${m.map(b).join("")}`:""}${l.map(i=>`<p class="dt-hist-group">${hs[i]}<em>${o[i].length}</em></p>`+o[i].map(s).join("")).join("")}</div>`:`<p class="dt-hist-empty">${o.done.length?"Everything here is resolved.":"No comments at this breakpoint yet. Click anything on the page to leave one."}</p>`)},Me=t=>D.toggleAttribute("data-collapsed",t);D.addEventListener("click",async t=>{const e=t.target.closest("[data-refresh]");if(e){e.dataset.spin="1",await Zt(),setTimeout(()=>delete e.dataset.spin,500);return}if(D.hasAttribute("data-collapsed")&&t.target.closest(".dt-hist-head")){Me(!1);return}if(t.target.closest("[data-fold]")){Me(!D.hasAttribute("data-collapsed"));return}const n=t.target.closest(".dt-hist-bands [data-bp]");if(n){We(n.dataset.bp);return}const o=t.target.closest("[data-draft-go], [data-draft-rm]");if(o){const a=o.dataset.draftRm!==void 0,l=Number(a?o.dataset.draftRm:o.dataset.draftGo);C.hidden?a?Dn(l):He(l):q(a?{dropDraft:l}:{openDraft:l});return}const s=t.target.closest(".dt-hist-tools [data-act]");if(s){await Ut(Number(s.dataset.id),s.dataset.act==="done");return}const r=t.target.closest("[data-rm]");if(r){y=null,await qn(Number(r.dataset.rm));return}if(t.target.closest("[data-review]")){Xo();return}const c=t.target.closest("[data-go]");if(!c)return;const d=Number(c.dataset.go);if(!C.hidden){q({open:d});return}ke(d)});const ke=t=>{y=t,j(),p();const e=h.find(o=>o.id===t),n=e&&V(e);n?scrollTo({top:scrollY+n.y-innerHeight/2,behavior:"smooth"}):e&&Y(e)?.scrollIntoView({block:"center",behavior:"smooth"}),f.querySelector(`.dt-pin[data-id="${t}"]`)?.animate([{transform:"scale(1)"},{transform:"scale(1.5)"},{transform:"scale(1)"}],400)},He=t=>{const[e]=R.splice(t,1);if(!e)return;j(),u=e,y=null;const n=V(e);n&&(n.y<0||n.y>innerHeight)&&scrollTo({top:scrollY+n.y-innerHeight/3,behavior:"instant"}),p()},Dn=t=>{R.splice(t,1),p()},Ae="nm-review",Ce=()=>{try{return JSON.parse(sessionStorage.getItem(Ae)||"null")}catch{return null}},At=t=>{try{t?sessionStorage.setItem(Ae,JSON.stringify(t)):sessionStorage.removeItem(Ae)}catch{}},W=document.createElement("div");W.className="dt-review",W.setAttribute("role","region"),W.setAttribute("aria-label","Checking fixes"),W.hidden=!0,$||document.body.append(W);const Ct=()=>ot.filter(t=>O(t)==="claude"),Xo=()=>{const t=Ct().sort((e,n)=>+(n.route===P)-+(e.route===P)||String(e.route).localeCompare(String(n.route))||e.id-n.id).map(e=>e.id);t.length&&(At({ids:t,i:0}),Ne())},Ne=()=>{const t=Ce();if(!t||$){W.hidden=!0;return}for(;t.i<t.ids.length&&O(ot.find(n=>n.id===t.ids[t.i])??{status:"done"})!=="claude";)t.i++;if(t.i>=t.ids.length){At(null),W.hidden=!0,st("Every fix is checked.");return}At(t);const e=ot.find(n=>n.id===t.ids[t.i]);if(e.route&&e.route!==P){location.assign(e.route+location.search);return}if(H||rt(!0),ct(e)!==_t()){We(ct(e));for(const n of[600,1500])setTimeout(()=>q({open:e.id}),n)}else ke(e.id);W.innerHTML=`<b>Check fixes</b><span class="dt-review-n">${t.i+1} of ${t.ids.length}</span>
98
- <span class="dt-review-text">${g(K(e.text).slice(0,90))}</span>
99
- <button data-r="ok" class="dt-review-ok">${Se} Looks right</button><button data-r="no">Reopen</button>
100
- <button data-r="skip">Skip</button><button data-r="stop" aria-label="Stop checking" title="Stop">${Vt}</button>`,W.hidden=!1};W.addEventListener("click",async t=>{const e=t.target.closest("[data-r]"),n=Ce();if(!e||!n)return;if(e.dataset.r==="stop"){At(null),W.hidden=!0;return}const o=n.ids[n.i];At({...n,i:n.i+1});const s=e.dataset.r==="ok"?Ut(o,!0):e.dataset.r==="no"?Ut(o,!1):null;Ne(),await s});const Zo=t=>{D.hidden=!t,Ft.setAttribute("aria-pressed",String(t)),z("dt-history",t?"1":"0"),p()},Be=document.querySelector(".dt-resolved-btn"),On=t=>{tt=t,Be.setAttribute("aria-pressed",String(t)),z("dt-resolved",t?"1":"0"),q({resolved:t}),p(),Jt()};Be.addEventListener("click",()=>On(!tt)),Be.setAttribute("aria-pressed",String(tt)),Ft.addEventListener("click",()=>{const t=D.hidden===!0;t&&!H&&rt(!0),t&&Me(!1),Zo(t)});const nt=()=>{ye||!H||(ye=requestAnimationFrame(()=>{ye=0,Jo()}))},Pn=new MutationObserver(t=>{t.every(e=>e.target.closest?.(".dt-notes-overlay"))||nt()}),Fn=new ResizeObserver(()=>nt());let ot=[];const jn=t=>{ot=t;const e=()=>({open:0,claude:0,done:0}),n={};for(const d of t){const a=O(d),l=n[d.route??""]??={...e(),bands:{}};l[a]++;const m=ct(d);(l.bands[m]??=e())[a]++}const o=["open","claude","done"],s={open:"open",claude:"resolved by an agent, to check",done:"resolved"},r=d=>o.map(a=>[a,a==="done"&&!tt?0:d[a]]),c=d=>r(d).reduce((a,[,l])=>a+l,0);for(const d of document.querySelectorAll(".dt-pages a")){const a=d.querySelector(".dt-pages-n");if(!a)continue;const l=n[new URL(d.href).pathname.replace(/\/+$/,"")||"/"];for(const i of B){const v=l?.bands[i.id];for(const[x,N]of r(v??e())){const lt=a.querySelector(`[data-bp="${i.id}"][data-state="${x}"]`);lt.hidden=!N,N&&(lt.querySelector("i").textContent=String(N),lt.title=`${i.label}: ${N} ${s[x]}`)}}const m=l?c(l):0;a.hidden=!m;const b=l?B.filter(i=>l.bands[i.id]&&c(l.bands[i.id])).map(i=>`${i.label} ${c(l.bands[i.id])}`).join(" \xB7 "):"";a.title=m?`${l.open} open \xB7 ${l.claude} resolved by an agent, to check \xB7 ${l.done} resolved
101
- ${b}`:""}},Nt=t=>(Array.isArray(t)?t:[]).filter(e=>e&&Number.isInteger(Number(e.id))&&typeof e.text=="string").map(e=>({...e,id:Number(e.id),rx:Number(e.rx)||0,ry:Number(e.ry)||0,route:typeof e.route=="string"&&/^\/(?!\/)/.test(e.route)?e.route:"/",replies:Array.isArray(e.replies)?e.replies.filter(n=>typeof n?.text=="string"):[],images:Array.isArray(e.images)?e.images.filter(n=>typeof n=="string"):[]})),Jt=async()=>{try{jn(Nt((await(await U("comments")).json()).comments)),!D.hidden&&!$&&p()}catch{}};let Xt="",Re=!1;const Bt=async()=>{if(!(document.hidden||Re)){Re=!0;try{const t=await U(`comments${Xt?`?since=${Xt}`:""}`);if(t.status!==200)return;const e=await t.json();Xt=e.version??"";const n=Nt(e.comments);jn(n);const o=n.filter(s=>s.route===P);if(JSON.stringify(o)===JSON.stringify(h))return;if(f.contains(document.activeElement)&&document.activeElement.matches("textarea, input")){Xt="",setTimeout(Bt,5e3);return}h=o,p(),q({reload:!0})}catch{}finally{Re=!1}}},gt=async()=>{try{const t=await U(`comments?route=${encodeURIComponent(P)}`);h=Nt((await t.json()).comments)}catch{h=[]}p()};let qe=0;const Kn=t=>{qe||(qe=requestAnimationFrame(()=>{qe=0;const e=t.target;if(!H||e.closest(le)){mt.hidden=!0;return}mt.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(mt.hidden=!1,!n)return;const o=n.getBoundingClientRect();Ho.style.cssText=`left:${o.left}px;top:${o.top}px;width:${o.width}px;height:${o.height}px`,mn.textContent=n.tagName.toLowerCase()+([...n.classList].find(s=>!/^(astro|svelte)-/.test(s))?"."+[...n.classList].find(s=>!/^(astro|svelte)-/.test(s)):"")+` ${Math.round(o.width)}\xD7${Math.round(o.height)}`,mn.style.cssText=`left:${o.left}px;top:${Math.max(2,o.top-20)}px`}))},Wn=t=>{if(!(t.key!=="Escape"||t.isComposing)){if(t.preventDefault(),L){L=null,p();return}if(u){j(),p();return}if(y!==null){y=null,p();return}rt(!1)}},zn=["pointerdown","mousedown","pointerup","mouseup","touchstart","touchend"],_n=t=>{t.target.closest?.(le)||t.stopPropagation()},Gn=t=>{if(t.target.closest(le))return;if(t.preventDefault(),t.stopPropagation(),ie){ie=!1;return}if(!getSelection()?.isCollapsed)return;f.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(f.hidden=!1,!n)return;j();const o=n.getBoundingClientRect(),s=n.tagName.toLowerCase(),r=[...n.classList].filter(c=>!/^(astro|svelte|css)-/.test(c)).slice(0,2);u={selector:qo(n),tag:s,classes:r,nth:hn({tag:s,classes:r}).indexOf(n),rx:o.width?(t.clientX-o.left)/o.width:.5,ry:o.height?(t.clientY-o.top)/o.height:.5,label:K(n.textContent||"").slice(0,60),ctx:Do(n),category:Xe[0].id},y=null,mt.hidden=!0,p()},Qo=2200,ts=900*1024,es=8*1024*1024,st=t=>{const e=document.createElement("div");e.className="dt-toast",e.textContent=t,document.body.append(e),setTimeout(()=>e.remove(),2800)},ns=t=>new Promise(e=>{const n=new FileReader;n.onload=()=>e(String(n.result)),n.readAsDataURL(t)}),os=async t=>{const e=await createImageBitmap(t),n=Math.min(1,Qo/Math.max(e.width,e.height));if(n===1&&t.size<=ts)return e.close(),ns(t);const o=document.createElement("canvas");return o.width=Math.round(e.width*n),o.height=Math.round(e.height*n),o.getContext("2d").drawImage(e,0,0,o.width,o.height),e.close(),o.toDataURL("image/jpeg",.85)},Ie=async(t,e)=>{const n=[];for(const o of t){let s;try{s=await os(o)}catch{st("That image could not be read.");continue}if(s.length>es){st("Screenshot is too large even after shrinking.");continue}n.push(s)}if(n.length){if(!Number(e?.dataset.id)){u&&((u.images??=[]).push(...n),p());return}Q.push(...n),p(),Vn(".dt-note-reply-input")}},Yn=t=>[...t??[]].filter(e=>e.kind==="file"&&e.type.startsWith("image/")).map(e=>e.getAsFile()).filter(Boolean);f.addEventListener("paste",t=>{const e=Yn(t.clipboardData?.items);e.length&&(t.preventDefault(),Ie(e,t.target.closest(".dt-note")))}),f.addEventListener("dragover",t=>{t.target.closest(".dt-note")&&(t.preventDefault(),t.target.closest(".dt-note").querySelector(".dt-compose")?.setAttribute("data-drop",""))}),f.addEventListener("dragleave",t=>{t.target.closest(".dt-note")?.querySelector(".dt-compose")?.removeAttribute("data-drop")}),f.addEventListener("drop",t=>{const e=t.target.closest(".dt-note");if(!e)return;t.preventDefault(),e.querySelector(".dt-compose")?.removeAttribute("data-drop");const n=Yn(t.dataTransfer?.items);n.length&&Ie(n,e)});const Vn=t=>{const e=f.querySelector(t);e?.focus(),e?.setSelectionRange(e.value.length,e.value.length)},Un=()=>{Vn(".dt-note-edit-input"),f.querySelector(".dt-msg .dt-compose")?.scrollIntoView({block:"nearest"})},De=t=>{t.style.overflowY="hidden",t.style.height="auto",t.style.height=`${t.scrollHeight}px`,t.style.overflowY=t.scrollHeight>t.clientHeight?"auto":"hidden"},ss=t=>/(?:^|\s)@([^\s@]*)$/.exec(t.value.slice(0,t.selectionStart??t.value.length)),rs=t=>{t.closest(".dt-compose").querySelector(".dt-mentions")?.remove();const n=ss(t);if(!n||!M.team?.length)return;const o=n[1].toLowerCase(),s=M.team.filter(r=>[r.name,r.nickname,r.email].some(c=>c?.toLowerCase().startsWith(o))).slice(0,5);s.length&&t.insertAdjacentHTML("afterend",`<div class="dt-mentions" role="listbox" aria-label="Mention someone">${s.map((r,c)=>`<button type="button" role="option" aria-selected="${c===0}" data-act="mention" data-handle="${g(bs(r))}">${g(r.name||r.email)}${r.name?` <span>${g(r.email)}</span>`:""}</button>`).join("")}</div>`)},Jn=(t,e)=>{const n=t.selectionStart??t.value.length,o=t.value.slice(0,n).lastIndexOf("@");t.value=`${t.value.slice(0,o)}@${e} ${t.value.slice(n)}`,t.selectionStart=t.selectionEnd=o+e.length+2,t.closest(".dt-compose")?.querySelector(".dt-mentions")?.remove(),t.dispatchEvent(new Event("input",{bubbles:!0})),t.focus()},as=(t,e)=>{if(!t){u&&(u.category=e),p();return}Ht(n=>n.map(o=>o.id===t?{...o,category:e}:o),()=>U("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:t,category:e})}),"Changing the type")};f.addEventListener("change",t=>{const e=t.target.closest(".dt-cat-select");if(e){as(Number(e.dataset.id)||0,e.value);return}const n=t.target.closest(".dt-for-select");if(!n)return;n.parentElement?.style.setProperty("--cat",wn(n.value));const o=Number(n.dataset.id);if(o){const s=n.value||null;Ht(r=>r.map(c=>c.id===o?{...c,assignee:s??void 0}:c),()=>U("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,assignee:s})}),"Reassigning");return}if(u){u.assignee=n.value;try{localStorage.setItem("nm-for",n.value)}catch{}zt()}}),f.addEventListener("input",t=>{const e=t.target.closest(".dt-suggest-input");if(e&&u?.suggest){u.suggest.to=e.value,zt(),De(e);return}const n=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");n&&(rs(n),n.classList.contains("dt-note-input")?u&&(u.text=n.value):n.classList.contains("dt-note-edit-input")?L&&(L.text=n.value):F=n.value,zt(),n.closest(".dt-compose")?.querySelector(".dt-send")?.classList.toggle("is-ready",n.value.trim()!==""),De(n))}),f.addEventListener("keydown",t=>{const e=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");if(!e)return;const n=e.closest(".dt-compose")?.querySelector(".dt-mentions button");if(n&&(t.key==="Enter"||t.key==="Tab")&&!t.isComposing){t.preventDefault(),Jn(e,n.dataset.handle);return}if(n&&t.key==="Escape"){t.stopPropagation(),n.parentElement.remove();return}t.key!=="Enter"||t.shiftKey||t.isComposing||(t.preventDefault(),e.closest(".dt-compose")?.querySelector(".dt-send")?.click())}),f.addEventListener("click",async t=>{const e=t.target.closest("button");if(!e)return;const n=e.dataset.act,o=Number(e.dataset.id);if(n==="mention"){const s=e.closest(".dt-compose")?.querySelector("textarea");s&&Jn(s,e.dataset.handle);return}if(!n){if(y=y===o?null:o,y!=null&&e.dataset.off){const s=h.find(c=>c.id===o);(s&&Y(s))?.scrollIntoView({block:"nearest",inline:"center",behavior:"smooth"})}j(),p();return}if(n==="record"){_o(e.closest(".dt-note"));return}if(n==="attach"){const s=Object.assign(document.createElement("input"),{type:"file",accept:"image/*",multiple:!0}),r=e.closest(".dt-note");s.addEventListener("change",()=>{s.files?.length&&Ie([...s.files],r)}),s.click();return}if(n==="unshot"){o?L&&L.drop.push(e.dataset.img):(e.closest("[data-draft]")?u?.images??[]:Q).splice(Number(e.dataset.i),1),p(),L&&Un();return}if(n==="edit"){const s=h.find(d=>d.id===o),r=e.dataset.at||null,c=r?s?.replies?.find(d=>d.at===r)?.text:s?.text;if(c===void 0)return;L={id:o,at:r,text:c,drop:[]},p(),Un();return}if(n==="edit-cancel"){L=null,p();return}if(n==="edit-save"){const s=L;if(!s)return;const r=s.text.trim();if(!r){f.querySelector(".dt-note-edit-input")?.focus();return}L=null;const c=d=>s.drop.includes(d.split("/").pop());await Ht(d=>d.map(a=>a.id!==s.id?a:{...a,...s.at==null?{text:r}:{replies:(a.replies??[]).map(l=>l.at===s.at?{...l,text:r}:l)},images:(a.images??[]).filter(l=>!c(l))}),()=>U("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:s.id,edit:{at:s.at,text:r},...s.drop.length?{removeImage:s.drop}:{}})}).then(d=>(d.ok||(L=s),d)),"Saving the edit");return}if(n==="cancel"){j(),p();return}if(n==="twin"){j(),y=Number(e.dataset.id),p();return}if(n==="discard"){u=null,p();return}if(n==="draft-open"){He(Number(e.dataset.i));return}if(n==="close"){y=null,p();return}if(n==="suggest"&&u){const s=Ln(Y(u));u.suggest={from:s,to:s},p();const r=f.querySelector(".dt-suggest-input");r?.focus(),r?.select();return}if(n==="unsuggest"&&u){u.suggest=null,p();return}if(n==="save"){if(!u)return;const s=u.suggest&&u.suggest.to.trim()!==u.suggest.from?{from:u.suggest.from,to:u.suggest.to.trim()}:null,r=f.querySelector(".dt-note-input").value.trim()||(s?"Change the text":"");if(!r){f.querySelector(".dt-note-input")?.focus();return}const c=u,d={...c,route:P,text:r,suggest:s,assignee:c.assignee??En(),breakpoint:et(),browser:Ro(),device:$?Xn:"",viewport:{w:innerWidth,h:innerHeight},logs:xs()},a={...c,id:-Date.now(),text:r,route:P,status:"open",note:"",doneBy:null,breakpoint:d.breakpoint,replies:[],images:[],createdAt:new Date().toISOString(),...s?{suggest:s}:{},by:M.me?.email,byName:M.me?.name};h=[...h,a],u=null,p();const l=await U("comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(d)});if(!l.ok){h=h.filter(b=>b!==a),u=c,p(),st(`Comment was not saved (${l.status}).`);return}const m=Nt([await l.json().catch(()=>null)])[0];h=h.map(b=>b===a&&m?m:b),p(),Zt();return}if(n==="reply"){const s=f.querySelector(".dt-note-reply-input"),r=s.value.trim();if(!r){s.focus();return}const c=Q;F="",Q=[];const d=h;h=h.map(m=>m.id===o?{...m,replies:[...m.replies??[],{author:"you",text:r,at:new Date().toISOString(),by:M.me?.email}]}:m),p();const a=await U("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,reply:r,images:c})});if(!a.ok){h=d,F=r,Q=c,p(),st(`Reply was not sent (${a.status}).`);return}const l=Nt([await a.json().catch(()=>null)])[0];l&&(h=h.map(m=>m.id===l.id?l:m),p()),Zt();return}y=null,n==="rm"?await qn(o):await Ut(o,n==="done")});let Rt="overlay",ht="",Xn="";const q=t=>{C.hidden||S.contentWindow?.postMessage({dt:!0,...t},location.origin)},is=()=>({notes:H,grid:!Ot.hidden,inspect:ut,resolved:tt,scrollbar:Rt,device:ht});addEventListener("message",t=>{if(t.origin!==location.origin||!t.data?.dt)return;const e=t.data;if(!$&&t.source===S.contentWindow){if(e.key){lo(e.key[0],e.key[1])?.run();return}if(e.closeMenus){wt();return}if(e.drafts){Te=e.drafts,In(_t());return}}if($&&typeof e.openDraft=="number"){He(e.openDraft);return}if($&&typeof e.dropDraft=="number"){Dn(e.dropDraft);return}if($&&typeof e.device=="string"&&(Xn=e.device),$&&e.scrollbar&&document.documentElement.classList.toggle("dt-sb-classic",e.scrollbar==="classic"),e.hello&&t.source===S.contentWindow){q(is());return}typeof e.notes=="boolean"&&e.notes!==H&&rt(e.notes,!1),typeof e.open=="number"&&ke(e.open),typeof e.grid=="boolean"&&e.grid===Ot.hidden&&ae(e.grid),typeof e.inspect=="string"&&e.inspect!==ut&&Pt(e.inspect),typeof e.resolved=="boolean"&&e.resolved!==tt&&On(e.resolved),e.reload&&(gt(),Jt())});const Zt=async()=>{await gt(),Jt(),q({reload:!0}),$&&parent.postMessage({dt:!0,reload:!0},location.origin)},rt=(t,e=!0)=>{if(H=t,cn.setAttribute("aria-pressed",String(t)),t?!$&&D.hidden&&localStorage.getItem("dt-history")!=="0"&&(D.hidden=!1,Ft.setAttribute("aria-pressed","true")):(D.hidden=!0,Ft.setAttribute("aria-pressed","false")),z(gn,t?"1":"0"),q({notes:t}),$&&e&&parent.postMessage({dt:!0,notes:t},location.origin),f.hidden=!t||!C.hidden,document.documentElement.classList.toggle("dt-noting",t),t){Pt(""),document.addEventListener("click",Gn,!0);for(const n of zn)document.addEventListener(n,_n,!0);document.addEventListener("keydown",Wn),document.addEventListener("mousemove",Kn),addEventListener("scroll",nt,!0),addEventListener("resize",nt),Pn.observe(document.body,{childList:!0,subtree:!0,characterData:!0}),Fn.observe(document.body),gt()}else{j(),y=null,document.removeEventListener("click",Gn,!0);for(const n of zn)document.removeEventListener(n,_n,!0);document.removeEventListener("keydown",Wn),document.removeEventListener("mousemove",Kn),mt.hidden=!0,removeEventListener("scroll",nt,!0),removeEventListener("resize",nt),Pn.disconnect(),Fn.disconnect(),f.innerHTML=""}},Qt="dt-w",Oe="dt-canvas",bt="dt-device";let at=localStorage.getItem(Oe)==="1",E=localStorage.getItem(bt)||"";E&&!Dt(E)&&(E="",localStorage.setItem(bt,""));let A=Number(localStorage.getItem(Qt))||0;const Zn="dt-emu";let I=(()=>{try{return JSON.parse(localStorage.getItem(Zn)||"null")}catch{return null}})();const te=()=>I?fo.find(t=>t.id===I.id)??null:null,ls=()=>{const t=te();return t?I.turned?{w:t.h,h:t.w}:{w:t.w,h:t.h}:null};let qt=localStorage.getItem("dt-bars-min")==="1";const yt=t=>{I=t,z(Zn,t?JSON.stringify(t):"")},Pe=t=>{pn.textContent=t,C.style.setProperty("--dt-badge-w",`${pn.offsetWidth}px`)},Qn=t=>{if(!t){Lt.innerHTML="";return}let e="";for(let n=0;n<=t;n+=50)e+=`<span class="dt-tick${n%200===0?" is-major":""}" style="left:${n}px"></span>`;for(const n of B)for(const o of[n.min,n.max])o>0&&Number.isFinite(o)&&o<=t&&(e+=`<span class="dt-edge" style="left:${o}px" title="${n.label} edge"></span>`);Lt.innerHTML=e,Lt.style.width=`${t}px`},Fe=()=>{const t=parseFloat(w.style.width)||0,e=parseFloat(w.style.height)||0;if(!t||!e){w.style.transform="",delete w.dataset.scaled;return}const n=E||I?Math.min(1,(innerWidth-80)/t,(innerHeight-120)/e):Math.min(1,(innerWidth-80)/t);w.style.transform=n<1?`scale(${n})`:"",w.dataset.scaled=n<1?String(Math.round(n*100)):""},ds=t=>fo.find(e=>e.w===t.w&&e.h===t.h&&e.cutout?.shape==="pill")?.cutout,ee=()=>{try{return S.contentDocument}catch{return null}},to=()=>ee()?.title.split("\u2014").pop()?.trim()||"",je=()=>{const t=ee(),e=E?Dt(E):null;if(!t?.body||!e)return;const n=Ls(t),o=e.browser==="chrome-android"?n.theme||"rgb(255, 255, 255)":n.top,s=e.browser==="chrome-android"?"rgb(255, 255, 255)":n.bottom;w.style.setProperty("--dt-top",o),w.style.setProperty("--dt-top-ink",ho(o)),w.style.setProperty("--dt-bottom",s),w.style.setProperty("--dt-bottom-ink",ho(s));const r=St.querySelector(".dt-win-tab > span");r&&(r.textContent=to()||location.host)};let Ke=0;S.addEventListener("load",()=>{ee()&&(je(),S.contentWindow?.addEventListener("scroll",()=>{Ke||(Ke=requestAnimationFrame(()=>{Ke=0,je()}))},{passive:!0}))});for(const t of[St,jt])t.addEventListener("click",e=>{const n=e.target.closest("[data-nav]")?.dataset.nav;if(n)try{const o=S.contentWindow?.navigation;if(!ee()||!o)throw new Error("foreign");n==="back"?o.canGoBack&&o.back():n==="fwd"?o.canGoForward&&o.forward():o.reload()}catch{(n==="reload"||n==="back")&&(S.src=location.href)}});xt.addEventListener("click",()=>{qt=!qt,z("dt-bars-min",qt?"1":"0"),X()});const X=()=>{if($)return;const t=E?Dt(E)??null:null;if(E&&!t&&(E="",localStorage.setItem(bt,"")),!t&&!at){C.hidden=!0,S.removeAttribute("src"),document.documentElement.classList.remove("dt-framing"),f.hidden=!H,Lt.innerHTML="",Mt(),he.hidden=!0,xt.hidden=!0,J=null,ht="",Te=[],Mt(),_e(),H?gt():p();return}if(C.hidden=!1,document.documentElement.classList.add("dt-framing"),f.hidden=!0,S.src||(S.src=location.href),t){const e=Ss(t,{host:location.host,title:to(),now:new Date,min:qt,cutout:ds(t)}),{screen:n}=e;C.dataset.mode="device",w.dataset.shell=t.shell,w.dataset.browser=t.browser,w.style.width=`${e.footprint.w}px`,w.style.height=`${e.footprint.h}px`,w.style.setProperty("--dt-r",`${n.r}px`),w.style.setProperty("--dt-rb",`${n.rb}px`),un.innerHTML=e.shell;const o=(c,d,a,l)=>{c.innerHTML=l,c.style.cssText=`left:${n.x}px;top:${d}px;width:${n.w}px;height:${a}px`};o(St,n.y,e.topH,e.top),o(jt,n.y+n.h-e.bottomH,e.bottomH,e.bottom);const s=n.h-e.topH-e.bottomH;S.style.position="absolute",S.style.left=`${n.x}px`,S.style.top=`${n.y+e.topH}px`,S.style.width=`${n.w}px`,S.style.height=`${s}px`,Lt.innerHTML="";const r=qt&&e.canMinimize;Rt=e.scrollbar,ht=`${t.label}${r?" \xB7 bars folded":""}`,J=Et(t.w),q({notes:H,scrollbar:Rt,device:ht}),xt.hidden=!e.canMinimize,xt.setAttribute("aria-pressed",String(r)),Pe(`${t.label} \xB7 page ${t.w}\xD7${s} of ${t.w}\xD7${t.h}${r?" \xB7 bars folded":""} \xB7 ${B.find(c=>c.id===J)?.label??""}`),je()}else{const e=ls();e||yt(null);const n=e?.w||A||B.find(r=>r.id===et()).ideal;A=n,C.dataset.mode="canvas",delete w.dataset.shell,delete w.dataset.browser,un.innerHTML=St.innerHTML=jt.innerHTML="",St.style.cssText=jt.style.cssText="",xt.hidden=!0,Rt="overlay",w.style.width=`${n}px`,w.style.height=`${e?.h??innerHeight-84}px`,S.style.position="",S.style.left=S.style.top="",S.style.width="100%",S.style.height="100%",Qn(n),q({notes:H});const o=B.find(r=>r.id===Et(n)),s=te();ht=s?`${s.label}${I?.turned?" \xB7 landscape":""}`:"",q({scrollbar:Rt,device:ht}),Pe(s&&e?`${s.label} \xB7 ${e.w}\xD7${e.h} \xB7 ${o.label}`:`${n}px \xB7 ${o.label}`),J=Et(n)}he.hidden=!(te()?.rotates&&!t),_e(),Fe(),Mt(),H?gt():p()},We=t=>{const e=B.find(n=>n.id===t);E="",localStorage.setItem(bt,""),yt(null),at=t!==se,A=at?e.ideal:0,J=at?t:null,localStorage.setItem(Oe,at?"1":"0"),localStorage.setItem(Qt,String(A)),y=null,j(),X()};for(const t of ge)t.addEventListener("click",()=>We(t.dataset.bp));for(const t of document.querySelectorAll("[data-device]"))t.addEventListener("click",()=>{E=t.dataset.device===E?"":t.dataset.device,localStorage.setItem(bt,E),G.open=!1,X()});for(const t of document.querySelectorAll("[data-emu]"))t.addEventListener("click",()=>{const e=I?.id===t.dataset.emu&&!E;E="",localStorage.setItem(bt,""),yt(e?null:{id:t.dataset.emu,turned:!1}),at=!e,A=0,localStorage.setItem(Oe,at?"1":"0"),J=null,y=null,j(),G.open=!1,X()});he.addEventListener("click",()=>{I&&(yt({...I,turned:!I.turned}),y=null,j(),X())});const eo=[...G.querySelectorAll("[data-tab]")],cs=[...G.querySelectorAll("[data-panel]")],no=t=>{for(const e of eo)e.setAttribute("aria-selected",String(e.dataset.tab===t));for(const e of cs)e.hidden=e.dataset.panel!==t;z("dt-devices-tab",t)};for(const t of eo)t.addEventListener("click",()=>no(t.dataset.tab));no(localStorage.getItem("dt-devices-tab")==="devtools"?"devtools":"preview");const ze=G.querySelector(".dt-emu-search");ze.addEventListener("input",()=>{const t=ze.value.trim().toLowerCase();let e=null,n=!1;const o=()=>{e&&(e.hidden=!n)};for(const s of ze.parentElement.children){if(s.classList.contains("dt-devices-group")){o(),e=s,n=!1;continue}s.dataset.emu&&(s.hidden=!!t&&!s.textContent.toLowerCase().includes(t),n||=!s.hidden)}o()});const us=G.querySelector(".dt-devices-name");function _e(){for(const e of G.querySelectorAll("[data-device]"))e.setAttribute("aria-pressed",String(e.dataset.device===E));const t=!E&&!C.hidden?I?.id:void 0;for(const e of G.querySelectorAll("[data-emu]"))e.setAttribute("aria-pressed",String(e.dataset.emu===t));us.textContent=E&&Dt(E)?.label||t&&te()?.label||"Device"}const Ge=t=>B.find(e=>e.id===t),ms=t=>{const e=Ge(J??et());return Math.max(e.min||320,Math.min(Number.isFinite(e.max)?e.max:2560,Math.round(t)))};for(const t of Ao){const e=t.dataset.edge==="l"?-1:1;t.addEventListener("pointerdown",n=>{if(E)return;n.preventDefault(),I&&(yt(null),X()),t.setPointerCapture(n.pointerId);const o=n.clientX,s=A,r=Number(w.dataset.scaled||100)/100;C.dataset.dragging="1";const c=a=>{A=ms(s+e*(a.clientX-o)*2/r),w.style.width=`${A}px`,Qn(A),Pe(`${A}px \xB7 ${Ge(Et(A)).label}`),Fe()},d=()=>{t.removeEventListener("pointermove",c),t.removeEventListener("pointerup",d),delete C.dataset.dragging,localStorage.setItem(Qt,String(A)),X()};t.addEventListener("pointermove",c),t.addEventListener("pointerup",d)}),t.addEventListener("dblclick",()=>{if(E)return;yt(null);const n=Ge(J??et()),o=[n.min||320,Number.isFinite(n.max)?n.max:n.ideal];A=Math.abs(A-o[0])<Math.abs(A-o[1])?o[0]:o[1],localStorage.setItem(Qt,String(A)),X()})}let oo=et();addEventListener("resize",()=>{Mt(),et()!==oo&&(oo=et(),p()),C.hidden||(!E&&!I&&(w.style.height=`${innerHeight-84}px`),Fe())});const so="dt-studio",ro=t=>{fe.setAttribute("aria-pressed",String(t)),document.documentElement.classList.toggle("dt-no-studio",!t),z(so,t?"1":"0")};fe.addEventListener("click",()=>ro(fe.getAttribute("aria-pressed")!=="true")),ro(localStorage.getItem(so)!=="0"),cn.addEventListener("click",()=>rt(!H));const vt=document.querySelector(".devtools"),It=document.querySelector(".dt-tab"),ao=t=>{vt.toggleAttribute("data-collapsed",t),It.toggleAttribute("data-collapsed",t),It.setAttribute("aria-expanded",String(!t)),It.setAttribute("aria-label",t?"Show the bar":"Hide the bar");for(const e of vt.querySelectorAll(".dt-group"))e.inert=t;t&&wt(),z("dt-collapsed",t?"1":"0")};It.addEventListener("click",()=>ao(!vt.hasAttribute("data-collapsed")));const Ye=document.querySelector(".dt-keys"),it=t=>()=>vt.querySelector(t)?.click(),io=t=>()=>{const e=[...document.querySelectorAll(".dt-pages a")];e[e.findIndex(n=>n.hasAttribute("aria-current"))+t]?.click()},ne=[{group:"Comments",code:"KeyC",hint:"C",label:"Comment mode",el:".dt-notes-btn",run:it(".dt-notes-btn")},{group:"Comments",code:"KeyC",shift:!0,hint:"\u21E7C",label:"Comments panel",el:".dt-history-btn",run:it(".dt-history-btn")},{group:"Comments",code:"KeyR",hint:"R",label:"Show resolved",el:".dt-resolved-btn",run:it(".dt-resolved-btn")},{group:"Inspect",code:"KeyG",hint:"G",label:"Grid",el:".dt-grid-btn",run:it(".dt-grid-btn")},{group:"Inspect",code:"KeyP",hint:"P",label:"Spacing",el:".dt-pad-btn",run:it(".dt-pad-btn")},{group:"Inspect",code:"KeyS",hint:"S",label:"Size",el:".dt-size-btn",run:it(".dt-size-btn")},{group:"Inspect",code:"KeyT",hint:"T",label:"Typography",el:".dt-type-btn",run:it(".dt-type-btn")},...M.sanity?[{group:"Inspect",code:"KeyE",hint:"E",label:"Sanity overlay",el:".dt-studio-btn",run:it(".dt-studio-btn")}]:[],...ge.slice(0,9).map((t,e)=>({group:"Breakpoints",code:`Digit${e+1}`,hint:String(e+1),label:t.dataset.tip??t.title,el:`.dt-bp[data-bp="${t.dataset.bp}"]`,run:()=>t.click()})),{group:"View",code:"KeyD",hint:"D",label:"Devices",run:()=>{G.open=!G.open}},{group:"View",code:"BracketLeft",hint:"[",label:"Previous page",run:io(-1)},{group:"View",code:"BracketRight",hint:"]",label:"Next page",run:io(1)},{group:"View",code:"Backslash",hint:"\\",label:"Hide the bar",run:()=>It.click()},{group:"View",code:"Slash",shift:!0,hint:"?",label:"This list",el:".dt-keys summary",run:()=>{Ye.open=!Ye.open}}],lo=(t,e)=>ne.find(n=>n.code===t&&!n.shift==!e),ps=t=>t instanceof HTMLElement&&(t.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName));if(M.shortcuts){for(const e of ne){const n=e.el&&vt.querySelector(e.el);n&&(n.dataset.tip=`${n.dataset.tip??e.label} \xB7 ${e.hint}`,n.setAttribute("aria-keyshortcuts",e.hint.startsWith("\u21E7")?`Shift+${e.hint.slice(1)}`:e.hint))}const t=(e,n)=>`<div class="dt-key-row"><span>${g(e)}</span><kbd>${g(n)}</kbd></div>`;if(Ye.querySelector(".dt-keys-menu").innerHTML='<p class="dt-menu-note">One key, no modifier, in any keyboard layout. Not while you type.</p>'+[...new Set(ne.map(e=>e.group))].map(e=>`<p class="dt-devices-group">${e}</p>`+ne.filter(n=>n.group===e).map(n=>t(n.label,n.hint)).join("")).join("")+'<p class="dt-devices-group">In a comment</p>'+t("Send","Enter")+t("New line","\u21E7Enter")+t("Close, cancel, back out","Esc"),document.addEventListener("keydown",e=>{if(e.repeat||e.isComposing||e.metaKey||e.ctrlKey||e.altKey||e.defaultPrevented||ps(e.target))return;const n=lo(e.code,e.shiftKey);n&&(e.preventDefault(),$?parent.postMessage({dt:!0,key:[e.code,e.shiftKey]},location.origin):n.run())}),$){const e=()=>parent.postMessage({dt:!0,closeMenus:!0},location.origin);document.addEventListener("pointerdown",e,!0),document.addEventListener("keydown",n=>{n.key==="Escape"&&e()})}}if(!$){ao(localStorage.getItem("dt-collapsed")==="1"),requestAnimationFrame(()=>requestAnimationFrame(()=>vt.setAttribute("data-ready",""))),at||E?X():_e(),ae(localStorage.getItem(Qe)==="1");const t=localStorage.getItem(on);t&&t in de&&Pt(t),rt(localStorage.getItem(gn)==="1")}const co=()=>{try{const t=JSON.parse(localStorage.getItem(ft)||"null");R=(t?.parked??[]).filter(e=>Kt(e)),t?.draft&&document.querySelector(t.draft.selector)?(u=t.draft,!H&&!$&&rt(!0)):Kt(t?.draft)&&R.push(t.draft),t?.reply?.text&&(F=t.reply.text,Tt=y=t.reply.for??null),(u||R.length||F)&&p()}catch{localStorage.removeItem(ft)}};co();const uo=()=>setTimeout(()=>{const t=re(location.pathname);t!==P&&(clearTimeout(Wt),ve(),P=t,ft=fn(),u=null,R=[],F="",Tt=null,y=null,L=null,h=[],en(),co(),gt())});for(const t of["pushState","replaceState"]){const e=window.history[t];window.history[t]=function(...n){e.apply(this,n),uo()}}addEventListener("popstate",uo),H||gt(),Jt().then(()=>{Ce()&&Ne()}),document.addEventListener("visibilitychange",()=>{document.hidden||Bt()}),addEventListener("focus",Bt),addEventListener("notemend:changed",()=>{$||Bt()});let gs=0;$||setInterval(()=>{(!Es.live||++gs%6===0)&&Bt()},2e4),$&&parent.postMessage({dt:!0,hello:!0},location.origin)}export{Rs as run};
99
+ </div>`+(l.length||p.length?`<div class="dt-hist-list">${p.length?`<p class="dt-hist-group">Drafts<em>${p.length}</em></p>${p.map(L).join("")}`:""}${l.map(i=>`<p class="dt-hist-group">${ds[i]}<em>${o[i].length}</em></p>`+o[i].map(s).join("")).join("")}</div>`:`<p class="dt-hist-empty">${o.done.length?"Everything here is resolved.":"No comments at this breakpoint yet. Click anything on the page to leave one."}</p>`)+`<div class="dt-hist-foot">
100
+ <button class="dt-hist-resolved" data-resolved role="switch" aria-checked="${U}"
101
+ ><svg viewBox="0 0 20 20" width="13" height="13" aria-hidden="true"><circle cx="10" cy="10" r="7.5"/><path d="M6.8 10.2 9 12.4l4-4.4" stroke-linejoin="round"/></svg
102
+ ><span>Show resolved</span><kbd>R</kbd><i class="dt-hist-switch" aria-hidden="true"></i></button>
103
+ </div>`},Me=t=>P.toggleAttribute("data-collapsed",t);P.addEventListener("click",async t=>{const e=t.target.closest("[data-refresh]");if(e){e.dataset.spin="1",await se(),setTimeout(()=>delete e.dataset.spin,500);return}if(P.hasAttribute("data-collapsed")&&t.target.closest(".dt-hist-head")){Me(!1);return}if(t.target.closest("[data-fold]")){Me(!P.hasAttribute("data-collapsed"));return}const n=t.target.closest(".dt-hist-bands [data-bp]");if(n){We(n.dataset.bp);return}const o=t.target.closest("[data-draft-go], [data-draft-rm]");if(o){const l=o.dataset.draftRm!==void 0,p=Number(l?o.dataset.draftRm:o.dataset.draftGo);A.hidden?l?Cn(p):He(p):D(l?{dropDraft:p}:{openDraft:p});return}const s=t.target.closest("[data-unmark]");if(s){t.stopPropagation(),await It(Number(s.dataset.unmark),!1);return}const r=t.target.closest(".dt-hist-tools [data-act]");if(r){await It(Number(r.dataset.id),r.dataset.act==="done");return}const c=t.target.closest("[data-rm]");if(c){y=null,await An(Number(c.dataset.rm));return}if(t.target.closest("[data-review]")){_o();return}if(t.target.closest("[data-resolved]")){Ce(!U);return}const u=t.target.closest("[data-go]");if(!u)return;const a=Number(u.dataset.go);if(!A.hidden){D({open:a});return}ke(a)});const ke=t=>{y=t,W(),m();const e=h.find(o=>o.id===t),n=e&&V(e);n?scrollTo({top:scrollY+n.y-innerHeight/2,behavior:"smooth"}):e&&Z(e)?.scrollIntoView({block:"center",behavior:"smooth"}),f.querySelector(`.dt-pin[data-id="${t}"]`)?.animate([{transform:"scale(1)"},{transform:"scale(1.5)"},{transform:"scale(1)"}],400)},He=t=>{const[e]=q.splice(t,1);if(!e)return;W(),d=e,y=null;const n=V(e);n&&(n.y<0||n.y>innerHeight)&&scrollTo({top:scrollY+n.y-innerHeight/3,behavior:"instant"}),m()},Cn=t=>{q.splice(t,1),m()},Ae="nm-review",te=()=>{try{return JSON.parse(sessionStorage.getItem(Ae)||"null")}catch{return null}},ht=t=>{try{t?sessionStorage.setItem(Ae,JSON.stringify(t)):sessionStorage.removeItem(Ae)}catch{}},R=document.createElement("div");R.className="dt-review",R.setAttribute("role","region"),R.setAttribute("aria-label","Checking fixes"),R.hidden=!0,v||document.body.append(R);const ut=()=>Y.filter(t=>C(t)==="claude"),_o=()=>{const t=ut().sort((e,n)=>+(n.route===K)-+(e.route===K)||String(e.route).localeCompare(String(n.route))||e.id-n.id).map(e=>e.id);t.length&&(ht({ids:t,i:0}),ee())},ee=()=>{const t=te();if(!t||v){R.hidden=!0;return}for(;t.i<t.ids.length&&C(Y.find(o=>o.id===t.ids[t.i])??{status:"done"})!=="claude";)t.i++;if(t.i>=t.ids.length){ht(null),R.hidden=!0,j("Every fix is checked.");return}ht(t);const e=Y.find(o=>o.id===t.ids[t.i]);if(e.route&&e.route!==K){location.assign(e.route+location.search);return}if(M||st(!0),G(e)!==Gt()){We(G(e));for(const o of[600,1500])setTimeout(()=>D({open:e.id}),o)}else ke(e.id);const n=t.ids.slice(0,t.i).some(o=>C(Y.find(s=>s.id===o)??{status:"done"})==="claude");R.innerHTML=`<b><span class="dt-review-dot" aria-hidden="true"></span>Check fixes</b>
104
+ <span class="dt-review-nav"><button data-r="prev" aria-label="Previous fix" data-tip="Previous \xB7 \u2190"${n?"":" disabled"}>${Mo}</button>
105
+ <span class="dt-review-n">${t.i+1} of ${t.ids.length}</span>
106
+ <button data-r="skip" aria-label="Next fix" data-tip="Next \xB7 \u2192">${ko}</button></span>
107
+ <span class="dt-review-text">${g(wt(e.text).slice(0,90))}</span>
108
+ <button data-r="ok" class="dt-review-ok" aria-label="Looks right \u2014 mark it resolved" data-tip="Looks right \u2014 resolve it">${Nt}</button>
109
+ <button data-r="no" aria-label="Reopen" data-tip="Not yet \u2014 reopen it">${Ao}</button>
110
+ <button data-r="stop" aria-label="Stop checking" data-tip="Stop checking">${Qt}</button>`,R.hidden=!1};R.addEventListener("click",async t=>{const e=t.target.closest("[data-r]"),n=te();if(!e||!n)return;if(e.dataset.r==="stop"){ht(null),R.hidden=!0;return}if(e.dataset.r==="prev"){Bn();return}const o=n.ids[n.i];ht({...n,i:n.i+1});const s=e.dataset.r==="ok"?It(o,!0):e.dataset.r==="no"?It(o,!1):null;ee(),await s});const Bn=()=>{const t=te();if(t){for(let e=t.i-1;e>=0;e--)if(C(Y.find(n=>n.id===t.ids[e])??{status:"done"})==="claude"){ht({...t,i:e}),ee();return}}};document.addEventListener("keydown",t=>{R.hidden||t.metaKey||t.ctrlKey||t.altKey||t.key!=="ArrowLeft"&&t.key!=="ArrowRight"||t.target.closest?.("input, textarea, select, [contenteditable]")||(t.preventDefault(),t.key==="ArrowLeft"?Bn():R.querySelector('[data-r="skip"]')?.click())});const zo=t=>{P.hidden=!t,Ut.setAttribute("aria-pressed",String(t)),_("dt-history",t?"1":"0"),m()},Ne=document.querySelector(".dt-resolved-btn"),Ce=t=>{U=t,Ne.setAttribute("aria-pressed",String(t)),_("dt-resolved",t?"1":"0"),D({resolved:t}),m(),ne()};Ne.addEventListener("click",()=>Ce(!U)),Ne.setAttribute("aria-pressed",String(U)),Ut.addEventListener("click",()=>{const t=P.hidden===!0;t&&!M&&st(!0),t&&Me(!1),zo(t)});const ot=()=>{Ee||!M||(Ee=requestAnimationFrame(()=>{Ee=0,Fo()}))},In=new MutationObserver(t=>{t.every(e=>e.target.closest?.(".dt-notes-overlay"))||ot()}),qn=new ResizeObserver(()=>ot());let Y=[];const Rn=t=>{Y=t;const e=()=>({open:0,claude:0,done:0}),n={};for(const u of t){const a=C(u),l=n[u.route??""]??={...e(),bands:{}};l[a]++;const p=G(u);(l.bands[p]??=e())[a]++}const o=["open","claude","done"],s={open:"open",claude:"resolved by an agent, to check",done:"resolved"},r=u=>o.map(a=>[a,a==="done"&&!U?0:u[a]]),c=u=>r(u).reduce((a,[,l])=>a+l,0);for(const u of document.querySelectorAll(".dt-pages a")){const a=u.querySelector(".dt-pages-n");if(!a)continue;const l=n[new URL(u.href).pathname.replace(/\/+$/,"")||"/"];for(const i of I){const x=l?.bands[i.id];for(const[H,N]of r(x??e())){const it=a.querySelector(`[data-bp="${i.id}"][data-state="${H}"]`);it.hidden=!N,N&&(it.querySelector("i").textContent=String(N),it.title=`${i.label}: ${N} ${s[H]}`)}}const p=l?c(l):0;a.hidden=!p;const L=l?I.filter(i=>l.bands[i.id]&&c(l.bands[i.id])).map(i=>`${i.label} ${c(l.bands[i.id])}`).join(" \xB7 "):"";a.title=p?`${l.open} open \xB7 ${l.claude} resolved by an agent, to check \xB7 ${l.done} resolved
111
+ ${L}`:""}},qt=t=>(Array.isArray(t)?t:[]).filter(e=>e&&Number.isInteger(Number(e.id))&&typeof e.text=="string").filter(e=>!b.client||e.by===b.me?.email||e.assignee===b.me?.email).map(e=>({...e,id:Number(e.id),rx:Number(e.rx)||0,ry:Number(e.ry)||0,route:typeof e.route=="string"&&/^\/(?!\/)/.test(e.route)?e.route:"/",replies:Array.isArray(e.replies)?e.replies.filter(n=>typeof n?.text=="string"):[],images:Array.isArray(e.images)?e.images.filter(n=>typeof n=="string"):[]})),ne=async()=>{try{Rn(qt((await(await B("comments")).json()).comments)),!P.hidden&&!v&&m()}catch{}};let Rt=null,Dt=null;const pt=document.querySelector(".dt-turbo"),Be="/notemend:turbo",Ot=()=>{const t=!!Rt&&Date.now()-Date.parse(Rt.at)<18e4,e=t?Dt?.paused?"paused":"on":"none",n=t?J(Rt.agent):"",o=e==="none"?`Turbo is off. Run ${Be} in Claude Code and comments for the agent are taken as they land \u2014 click to copy it`:e==="on"?`Turbo on: ${n} takes comments for the agent as they land \u2014 click to pause`:`Turbo paused: ${n} is listening but waits \u2014 click to resume`;pt.dataset.state=e,pt.dataset.tip=o,pt.setAttribute("aria-label",o),pt.setAttribute("aria-checked",String(e==="on")),v&&(pt.hidden=!0)};setInterval(Ot,3e4),pt.addEventListener("click",async()=>{const t=pt.dataset.state;if(t==="none"){await navigator.clipboard?.writeText(Be).catch(()=>{}),j(`Copied ${Be} \u2014 paste it in Claude Code`);return}const e=t==="on"?"off":"on";Dt={paused:e==="off"},Ot();try{const n=await B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({turbo:e})});if(!n.ok)throw new Error(String(n.status));j(e==="off"?"Turbo paused":"Turbo on")}catch{Dt={paused:e==="on"},Ot(),j("Could not switch turbo \u2014 try again")}});let oe="",Ie=!1;const Pt=async()=>{if(!(document.hidden||Ie)){Ie=!0;try{const t=await B(`comments${oe?`?since=${oe}`:""}`);if(t.status!==200)return;const e=await t.json();oe=e.version??"",Rt=e.listening??null,Dt=e.turbo??null,Ot();const n=qt(e.comments);Rn(n);const o=n.filter(s=>s.route===K);if(JSON.stringify(o)===JSON.stringify(h))return;if(f.contains(document.activeElement)&&document.activeElement.matches("textarea, input")){oe="",setTimeout(Pt,5e3);return}h=o,m(),D({reload:!0})}catch{}finally{Ie=!1}}},mt=async()=>{try{const e=await(await B(`comments?route=${encodeURIComponent(K)}`)).json();h=qt(e.comments),Rt=e.listening??null,Dt=e.turbo??null,Ot()}catch{h=[]}m()};let qe=0;const Dn=t=>{qe||(qe=requestAnimationFrame(()=>{qe=0;const e=t.target;if(!M||e.closest(ge)){dt.hidden=!0;return}dt.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(dt.hidden=!1,!n)return;const o=n.getBoundingClientRect();bo.style.cssText=`left:${o.left}px;top:${o.top}px;width:${o.width}px;height:${o.height}px`,ln.textContent=n.tagName.toLowerCase()+([...n.classList].find(s=>!/^(astro|svelte)-/.test(s))?"."+[...n.classList].find(s=>!/^(astro|svelte)-/.test(s)):"")+` ${Math.round(o.width)}\xD7${Math.round(o.height)}`,ln.style.cssText=`left:${o.left}px;top:${Math.max(2,o.top-20)}px`}))},On=t=>{if(!(t.key!=="Escape"||t.isComposing)){if(t.preventDefault(),S){S=null,m();return}if(d){W(),m();return}if(y!==null){y=null,m();return}st(!1)}},Pn=["pointerdown","mousedown","pointerup","mouseup","touchstart","touchend"],jn=t=>{t.target.closest?.(ge)||t.stopPropagation()},Kn=t=>{if(t.target.closest(ge))return;if(t.preventDefault(),t.stopPropagation(),me){me=!1;return}if(!getSelection()?.isCollapsed)return;f.hidden=!0;const n=document.elementFromPoint(t.clientX,t.clientY);if(f.hidden=!1,!n)return;W();const o=n.getBoundingClientRect(),s=n.tagName.toLowerCase(),r=[...n.classList].filter(c=>!/^(astro|svelte|css)-/.test(c)).slice(0,2);d={selector:So(n),tag:s,classes:r,nth:Lo({tag:s,classes:r}).indexOf(n),rx:o.width?(t.clientX-o.left)/o.width:.5,ry:o.height?(t.clientY-o.top)/o.height:.5,label:wt(n.textContent||"").slice(0,60),ctx:To(n),category:Xe[0].id},y=null,dt.hidden=!0,m()},Uo=2200,Vo=900*1024,Yo=8*1024*1024,j=t=>{const e=document.createElement("div");e.className="dt-toast",e.textContent=t,document.body.append(e),setTimeout(()=>e.remove(),2800)},Jo=t=>new Promise(e=>{const n=new FileReader;n.onload=()=>e(String(n.result)),n.readAsDataURL(t)}),Go=async t=>{const e=await createImageBitmap(t),n=Math.min(1,Uo/Math.max(e.width,e.height));if(n===1&&t.size<=Vo)return e.close(),Jo(t);const o=document.createElement("canvas");return o.width=Math.round(e.width*n),o.height=Math.round(e.height*n),o.getContext("2d").drawImage(e,0,0,o.width,o.height),e.close(),o.toDataURL("image/jpeg",.85)},Re=async(t,e)=>{const n=[];for(const o of t){let s;try{s=await Go(o)}catch{j("That image could not be read.");continue}if(s.length>Yo){j("Screenshot is too large even after shrinking.");continue}n.push(s)}if(n.length){if(!Number(e?.dataset.id)){d&&((d.images??=[]).push(...n),m());return}tt.push(...n),m(),Wn(".dt-note-reply-input")}},Fn=t=>[...t??[]].filter(e=>e.kind==="file"&&e.type.startsWith("image/")).map(e=>e.getAsFile()).filter(Boolean);f.addEventListener("paste",t=>{const e=Fn(t.clipboardData?.items);e.length&&(t.preventDefault(),Re(e,t.target.closest(".dt-note")))}),f.addEventListener("dragover",t=>{t.target.closest(".dt-note")&&(t.preventDefault(),t.target.closest(".dt-note").querySelector(".dt-compose")?.setAttribute("data-drop",""))}),f.addEventListener("dragleave",t=>{t.target.closest(".dt-note")?.querySelector(".dt-compose")?.removeAttribute("data-drop")}),f.addEventListener("drop",t=>{const e=t.target.closest(".dt-note");if(!e)return;t.preventDefault(),e.querySelector(".dt-compose")?.removeAttribute("data-drop");const n=Fn(t.dataTransfer?.items);n.length&&Re(n,e)});const Wn=t=>{const e=f.querySelector(t);e?.focus(),e?.setSelectionRange(e.value.length,e.value.length)},_n=()=>{Wn(".dt-note-edit-input"),f.querySelector(".dt-msg .dt-compose")?.scrollIntoView({block:"nearest"})},De=t=>{t.style.overflowY="hidden",t.style.height="auto",t.style.height=`${t.scrollHeight}px`,t.style.overflowY=t.scrollHeight>t.clientHeight?"auto":"hidden"},Xo=t=>/(?:^|\s)@([^\s@]*)$/.exec(t.value.slice(0,t.selectionStart??t.value.length)),Zo=t=>{t.closest(".dt-compose").querySelector(".dt-mentions")?.remove();const n=Xo(t);if(!n||!b.team?.length)return;const o=n[1].toLowerCase(),s=b.team.filter(r=>[r.name,r.nickname,r.email].some(c=>c?.toLowerCase().startsWith(o))).slice(0,5);s.length&&t.insertAdjacentHTML("afterend",`<div class="dt-mentions" role="listbox" aria-label="Mention someone">${s.map((r,c)=>`<button type="button" role="option" aria-selected="${c===0}" data-act="mention" data-handle="${g(cs(r))}">${g(r.name||r.email)}${r.name?` <span>${g(r.email)}</span>`:""}</button>`).join("")}</div>`)},zn=(t,e)=>{const n=t.selectionStart??t.value.length,o=t.value.slice(0,n).lastIndexOf("@");t.value=`${t.value.slice(0,o)}@${e} ${t.value.slice(n)}`,t.selectionStart=t.selectionEnd=o+e.length+2,t.closest(".dt-compose")?.querySelector(".dt-mentions")?.remove(),t.dispatchEvent(new Event("input",{bubbles:!0})),t.focus()},Qo=(t,e)=>{if(!t){d&&(d.category=e),m();return}nt(n=>n.map(o=>o.id===t?{...o,category:e}:o),()=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:t,category:e})}),"Changing the type")};ws(f,g,Nt),f.addEventListener("change",t=>{const e=t.target.closest(".dt-prio-select");if(e){const r=e.value==="normal"?null:e.value,c=Number(e.dataset.id);c?nt(u=>u.map(a=>a.id===c?{...a,priority:r??void 0}:a),()=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:c,priority:r})}),"Setting the priority"):d&&(d.priority=r??void 0,Ht(),m());return}const n=t.target.closest(".dt-cat-select");if(n){Qo(Number(n.dataset.id)||0,n.value);return}const o=t.target.closest(".dt-for-select");if(!o)return;o.parentElement?.style.setProperty("--cat",Bt(o.value));const s=Number(o.dataset.id);if(s){const r=o.value||null;nt(c=>c.map(u=>u.id===s?{...u,assignee:r??void 0}:u),()=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:s,assignee:r})}),"Reassigning");return}if(d){d.assignee=o.value;try{localStorage.setItem("nm-for",o.value)}catch{}Ht()}}),f.addEventListener("input",t=>{const e=t.target.closest(".dt-suggest-input");if(e&&d?.suggest){d.suggest.to=e.value,Ht(),De(e);return}const n=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");n&&(Zo(n),n.classList.contains("dt-note-input")?d&&(d.text=n.value):n.classList.contains("dt-note-edit-input")?S&&(S.text=n.value):F=n.value,Ht(),n.closest(".dt-compose")?.querySelector(".dt-send")?.classList.toggle("is-ready",n.value.trim()!==""),De(n))}),f.addEventListener("keydown",t=>{const e=t.target.closest(".dt-note-input, .dt-note-reply-input, .dt-note-edit-input");if(!e)return;const n=e.closest(".dt-compose")?.querySelector(".dt-mentions button");if(n&&(t.key==="Enter"||t.key==="Tab")&&!t.isComposing){t.preventDefault(),zn(e,n.dataset.handle);return}if(n&&t.key==="Escape"){t.stopPropagation(),n.parentElement.remove();return}t.key!=="Enter"||t.shiftKey||t.isComposing||(t.preventDefault(),e.closest(".dt-compose")?.querySelector(".dt-send")?.click())}),f.addEventListener("click",async t=>{const e=t.target.closest("button");if(!e)return;const n=e.dataset.act,o=Number(e.dataset.id);if(n==="mention"){const s=e.closest(".dt-compose")?.querySelector("textarea");s&&zn(s,e.dataset.handle);return}if(!n){if(y=y===o?null:o,y!=null&&e.dataset.off){const s=h.find(c=>c.id===o);(s&&Z(s))?.scrollIntoView({block:"nearest",inline:"center",behavior:"smooth"})}W(),m();return}if(n==="record"){Ro(e.closest(".dt-note"));return}if(n==="attach"){const s=Object.assign(document.createElement("input"),{type:"file",accept:"image/*",multiple:!0}),r=e.closest(".dt-note");s.addEventListener("change",()=>{s.files?.length&&Re([...s.files],r)}),s.click();return}if(n==="unshot"){o?S&&S.drop.push(e.dataset.img):(e.closest("[data-draft]")?d?.images??[]:tt).splice(Number(e.dataset.i),1),m(),S&&_n();return}if(n==="edit"){const s=h.find(u=>u.id===o),r=e.dataset.at||null,c=r?s?.replies?.find(u=>u.at===r)?.text:s?.text;if(c===void 0)return;S={id:o,at:r,text:c,drop:[]},m(),_n();return}if(n==="edit-cancel"){S=null,m();return}if(n==="edit-save"){const s=S;if(!s)return;const r=s.text.trim();if(!r){f.querySelector(".dt-note-edit-input")?.focus();return}S=null;const c=u=>s.drop.includes(u.split("/").pop());await nt(u=>u.map(a=>a.id!==s.id?a:{...a,...s.at==null?{text:r}:{replies:(a.replies??[]).map(l=>l.at===s.at?{...l,text:r}:l)},images:(a.images??[]).filter(l=>!c(l))}),()=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:s.id,edit:{at:s.at,text:r},...s.drop.length?{removeImage:s.drop}:{}})}).then(u=>(u.ok||(S=s),u)),"Saving the edit");return}if(n==="cancel"){W(),m();return}if(n==="twin"){W(),y=Number(e.dataset.id),m();return}if(n==="discard"){d=null,m();return}if(n==="draft-open"){He(Number(e.dataset.i));return}if(n==="close"){y=null,m();return}if(n==="suggest"&&d){const s=bn(Z(d));d.suggest={from:s,to:s},m();const r=f.querySelector(".dt-suggest-input");r?.focus(),r?.select();return}if(n==="unsuggest"&&d){d.suggest=null,m();return}if(n==="save"){if(!d)return;const s=d.suggest&&d.suggest.to.trim()!==d.suggest.from?{from:d.suggest.from,to:d.suggest.to.trim()}:null,r=f.querySelector(".dt-note-input").value.trim()||(s?"Change the text":"");if(!r){f.querySelector(".dt-note-input")?.focus();return}const c=d,u={...c,route:K,text:r,suggest:s,assignee:b.client?void 0:c.assignee??fn(),breakpoint:et(),browser:wo(),device:v?Un:"",viewport:{w:innerWidth,h:innerHeight},logs:vs(),host:location.host},a={...c,id:-Date.now(),text:r,route:K,status:"open",note:"",doneBy:null,breakpoint:u.breakpoint,replies:[],images:[],createdAt:new Date().toISOString(),...s?{suggest:s}:{},by:b.me?.email,byName:b.me?.name};h=[...h,a],d=null,m();const l=await B("comments",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(u)});if(!l.ok){h=h.filter(L=>L!==a),d=c,m(),j(`Comment was not saved (${l.status}).`);return}const p=qt([await l.json().catch(()=>null)])[0];h=h.map(L=>L===a&&p?p:L),m(),se();return}if(n==="reply"){const s=f.querySelector(".dt-note-reply-input"),r=s.value.trim();if(!r){s.focus();return}const c=tt;F="",tt=[];const u=h;h=h.map(p=>p.id===o?{...p,replies:[...p.replies??[],{author:"you",text:r,at:new Date().toISOString(),by:b.me?.email}]}:p),m();const a=await B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,reply:r,images:c})});if(!a.ok){h=u,F=r,tt=c,m(),j(`Reply was not sent (${a.status}).`);return}const l=qt([await a.json().catch(()=>null)])[0];l&&(h=h.map(p=>p.id===l.id?l:p),m()),se();return}if(n==="fixnow"){nt(s=>s.map(r=>r.id===o?{...r,assignee:"claude"}:r),()=>B("comments",{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({id:o,fixNow:!0})}),"Sending it to the agent"),j("Sent to the agent \u2014 it takes it next");return}y=null,n==="rm"?await An(o):n==="archive"?await jo(o):await It(o,n==="done")});let jt="overlay",bt="",Un="";const D=t=>{A.hidden||w.contentWindow?.postMessage({dt:!0,...t},location.origin)},ts=()=>({notes:M,grid:!_t.hidden,inspect:lt,resolved:U,scrollbar:jt,device:bt});addEventListener("message",t=>{if(t.origin!==location.origin||!t.data?.dt)return;const e=t.data;if(!v&&t.source===w.contentWindow){if(e.key){oo(e.key[0],e.key[1])?.run();return}if(e.closeMenus){Lt();return}if(e.drafts){xe=e.drafts,Nn(Gt());return}}if(v&&typeof e.openDraft=="number"){He(e.openDraft);return}if(v&&typeof e.dropDraft=="number"){Cn(e.dropDraft);return}if(v&&typeof e.device=="string"&&(Un=e.device),v&&e.scrollbar&&document.documentElement.classList.toggle("dt-sb-classic",e.scrollbar==="classic"),e.hello&&t.source===w.contentWindow){D(ts());return}typeof e.notes=="boolean"&&e.notes!==M&&st(e.notes,!1),typeof e.open=="number"&&ke(e.open),typeof e.grid=="boolean"&&e.grid===_t.hidden&&pe(e.grid),typeof e.inspect=="string"&&e.inspect!==lt&&zt(e.inspect),typeof e.resolved=="boolean"&&e.resolved!==U&&Ce(e.resolved),e.reload&&(mt(),ne())});const se=async()=>{await mt(),ne(),D({reload:!0}),v&&parent.postMessage({dt:!0,reload:!0},location.origin)},st=(t,e=!0)=>{if(M=t,an.setAttribute("aria-pressed",String(t)),t?!v&&P.hidden&&localStorage.getItem("dt-history")!=="0"&&(P.hidden=!1,Ut.setAttribute("aria-pressed","true")):(P.hidden=!0,Ut.setAttribute("aria-pressed","false")),_(cn,t?"1":"0"),D({notes:t}),v&&e&&parent.postMessage({dt:!0,notes:t},location.origin),f.hidden=!t||!A.hidden,document.documentElement.classList.toggle("dt-noting",t),t){zt(""),document.addEventListener("click",Kn,!0);for(const n of Pn)document.addEventListener(n,jn,!0);document.addEventListener("keydown",On),document.addEventListener("mousemove",Dn),addEventListener("scroll",ot,!0),addEventListener("resize",ot),In.observe(document.body,{childList:!0,subtree:!0,characterData:!0}),qn.observe(document.body),mt()}else{W(),y=null,document.removeEventListener("click",Kn,!0);for(const n of Pn)document.removeEventListener(n,jn,!0);document.removeEventListener("keydown",On),document.removeEventListener("mousemove",Dn),dt.hidden=!0,removeEventListener("scroll",ot,!0),removeEventListener("resize",ot),In.disconnect(),qn.disconnect(),f.innerHTML=""}},ae="dt-w",Oe="dt-canvas",yt="dt-device";let at=localStorage.getItem(Oe)==="1",$=localStorage.getItem(yt)||"";$&&!Wt($)&&($="",localStorage.setItem(yt,""));let k=Number(localStorage.getItem(ae))||0;const Vn="dt-emu";let O=(()=>{try{return JSON.parse(localStorage.getItem(Vn)||"null")}catch{return null}})();const re=()=>O?co.find(t=>t.id===O.id)??null:null,es=()=>{const t=re();return t?O.turned?{w:t.h,h:t.w}:{w:t.w,h:t.h}:null};let Kt=localStorage.getItem("dt-bars-min")==="1";const vt=t=>{O=t,_(Vn,t?JSON.stringify(t):"")},Pe=t=>{dn.textContent=t,A.style.setProperty("--dt-badge-w",`${dn.offsetWidth}px`)},Yn=t=>{if(!t){xt.innerHTML="";return}let e="";for(let n=0;n<=t;n+=50)e+=`<span class="dt-tick${n%200===0?" is-major":""}" style="left:${n}px"></span>`;for(const n of I)for(const o of[n.min,n.max])o>0&&Number.isFinite(o)&&o<=t&&(e+=`<span class="dt-edge" style="left:${o}px" title="${n.label} edge"></span>`);xt.innerHTML=e,xt.style.width=`${t}px`},je=()=>{const t=parseFloat(E.style.width)||0,e=parseFloat(E.style.height)||0;if(!t||!e){E.style.transform="",delete E.dataset.scaled;return}const n=$||O?Math.min(1,(innerWidth-80)/t,(innerHeight-120)/e):Math.min(1,(innerWidth-80)/t);E.style.transform=n<1?`scale(${n})`:"",E.dataset.scaled=n<1?String(Math.round(n*100)):""},ns=t=>co.find(e=>e.w===t.w&&e.h===t.h&&e.cutout?.shape==="pill")?.cutout,ie=()=>{try{return w.contentDocument}catch{return null}},Jn=()=>ie()?.title.split("\u2014").pop()?.trim()||"",Ke=()=>{const t=ie(),e=$?Wt($):null;if(!t?.body||!e)return;const n=ys(t),o=e.browser==="chrome-android"?n.theme||"rgb(255, 255, 255)":n.top,s=e.browser==="chrome-android"?"rgb(255, 255, 255)":n.bottom;E.style.setProperty("--dt-top",o),E.style.setProperty("--dt-top-ink",uo(o)),E.style.setProperty("--dt-bottom",s),E.style.setProperty("--dt-bottom-ink",uo(s));const r=Tt.querySelector(".dt-win-tab > span");r&&(r.textContent=Jn()||location.host)};let Fe=0;w.addEventListener("load",()=>{ie()&&(Ke(),w.contentWindow?.addEventListener("scroll",()=>{Fe||(Fe=requestAnimationFrame(()=>{Fe=0,Ke()}))},{passive:!0}))});for(const t of[Tt,Vt])t.addEventListener("click",e=>{const n=e.target.closest("[data-nav]")?.dataset.nav;if(n)try{const o=w.contentWindow?.navigation;if(!ie()||!o)throw new Error("foreign");n==="back"?o.canGoBack&&o.back():n==="fwd"?o.canGoForward&&o.forward():o.reload()}catch{(n==="reload"||n==="back")&&(w.src=location.href)}});Mt.addEventListener("click",()=>{Kt=!Kt,_("dt-bars-min",Kt?"1":"0"),Q()});const Q=()=>{if(v)return;const t=$?Wt($)??null:null;if($&&!t&&($="",localStorage.setItem(yt,"")),!t&&!at){A.hidden=!0,w.removeAttribute("src"),document.documentElement.classList.remove("dt-framing"),f.hidden=!M,xt.innerHTML="",At(),ve.hidden=!0,Mt.hidden=!0,X=null,bt="",xe=[],At(),ze(),M?mt():m();return}if(A.hidden=!1,document.documentElement.classList.add("dt-framing"),f.hidden=!0,w.src||(w.src=location.href),t){const e=bs(t,{host:location.host,title:Jn(),now:new Date,min:Kt,cutout:ns(t)}),{screen:n}=e;A.dataset.mode="device",E.dataset.shell=t.shell,E.dataset.browser=t.browser,E.style.width=`${e.footprint.w}px`,E.style.height=`${e.footprint.h}px`,E.style.setProperty("--dt-r",`${n.r}px`),E.style.setProperty("--dt-rb",`${n.rb}px`),rn.innerHTML=e.shell;const o=(c,u,a,l)=>{c.innerHTML=l,c.style.cssText=`left:${n.x}px;top:${u}px;width:${n.w}px;height:${a}px`};o(Tt,n.y,e.topH,e.top),o(Vt,n.y+n.h-e.bottomH,e.bottomH,e.bottom);const s=n.h-e.topH-e.bottomH;w.style.position="absolute",w.style.left=`${n.x}px`,w.style.top=`${n.y+e.topH}px`,w.style.width=`${n.w}px`,w.style.height=`${s}px`,xt.innerHTML="";const r=Kt&&e.canMinimize;jt=e.scrollbar,bt=`${t.label}${r?" \xB7 bars folded":""}`,X=St(t.w),D({notes:M,scrollbar:jt,device:bt}),Mt.hidden=!e.canMinimize,Mt.setAttribute("aria-pressed",String(r)),Pe(`${t.label} \xB7 page ${t.w}\xD7${s} of ${t.w}\xD7${t.h}${r?" \xB7 bars folded":""} \xB7 ${I.find(c=>c.id===X)?.label??""}`),Ke()}else{const e=es();e||vt(null);const n=e?.w||k||I.find(r=>r.id===et()).ideal;k=n,A.dataset.mode="canvas",delete E.dataset.shell,delete E.dataset.browser,rn.innerHTML=Tt.innerHTML=Vt.innerHTML="",Tt.style.cssText=Vt.style.cssText="",Mt.hidden=!0,jt="overlay",E.style.width=`${n}px`,E.style.height=`${e?.h??innerHeight-84}px`,w.style.position="",w.style.left=w.style.top="",w.style.width="100%",w.style.height="100%",Yn(n),D({notes:M});const o=I.find(r=>r.id===St(n)),s=re();bt=s?`${s.label}${O?.turned?" \xB7 landscape":""}`:"",D({scrollbar:jt,device:bt}),Pe(s&&e?`${s.label} \xB7 ${e.w}\xD7${e.h} \xB7 ${o.label}`:`${n}px \xB7 ${o.label}`),X=St(n)}ve.hidden=!(re()?.rotates&&!t),ze(),je(),At(),M?mt():m()},We=t=>{const e=I.find(n=>n.id===t);$="",localStorage.setItem(yt,""),vt(null),at=t!==ce,k=at?e.ideal:0,X=at?t:null,localStorage.setItem(Oe,at?"1":"0"),localStorage.setItem(ae,String(k)),y=null,W(),Q()};for(const t of be)t.addEventListener("click",()=>We(t.dataset.bp));for(const t of document.querySelectorAll("[data-device]"))t.addEventListener("click",()=>{$=t.dataset.device===$?"":t.dataset.device,localStorage.setItem(yt,$),z.open=!1,Q()});for(const t of document.querySelectorAll("[data-emu]"))t.addEventListener("click",()=>{const e=O?.id===t.dataset.emu&&!$;$="",localStorage.setItem(yt,""),vt(e?null:{id:t.dataset.emu,turned:!1}),at=!e,k=0,localStorage.setItem(Oe,at?"1":"0"),X=null,y=null,W(),z.open=!1,Q()});ve.addEventListener("click",()=>{O&&(vt({...O,turned:!O.turned}),y=null,W(),Q())});const Gn=[...z.querySelectorAll("[data-tab]")],os=[...z.querySelectorAll("[data-panel]")],Xn=t=>{for(const e of Gn)e.setAttribute("aria-selected",String(e.dataset.tab===t));for(const e of os)e.hidden=e.dataset.panel!==t;_("dt-devices-tab",t)};for(const t of Gn)t.addEventListener("click",()=>Xn(t.dataset.tab));Xn(localStorage.getItem("dt-devices-tab")==="devtools"?"devtools":"preview");const _e=z.querySelector(".dt-emu-search");_e.addEventListener("input",()=>{const t=_e.value.trim().toLowerCase();let e=null,n=!1;const o=()=>{e&&(e.hidden=!n)};for(const s of _e.parentElement.children){if(s.classList.contains("dt-devices-group")){o(),e=s,n=!1;continue}s.dataset.emu&&(s.hidden=!!t&&!s.textContent.toLowerCase().includes(t),n||=!s.hidden)}o()});const ss=z.querySelector(".dt-devices-name");function ze(){for(const e of z.querySelectorAll("[data-device]"))e.setAttribute("aria-pressed",String(e.dataset.device===$));const t=!$&&!A.hidden?O?.id:void 0;for(const e of z.querySelectorAll("[data-emu]"))e.setAttribute("aria-pressed",String(e.dataset.emu===t));ss.textContent=$&&Wt($)?.label||t&&re()?.label||"Device"}const Ue=t=>I.find(e=>e.id===t),as=t=>{const e=Ue(X??et());return Math.max(e.min||320,Math.min(Number.isFinite(e.max)?e.max:2560,Math.round(t)))};for(const t of yo){const e=t.dataset.edge==="l"?-1:1;t.addEventListener("pointerdown",n=>{if($)return;n.preventDefault(),O&&(vt(null),Q()),t.setPointerCapture(n.pointerId);const o=n.clientX,s=k,r=Number(E.dataset.scaled||100)/100;A.dataset.dragging="1";const c=a=>{k=as(s+e*(a.clientX-o)*2/r),E.style.width=`${k}px`,Yn(k),Pe(`${k}px \xB7 ${Ue(St(k)).label}`),je()},u=()=>{t.removeEventListener("pointermove",c),t.removeEventListener("pointerup",u),delete A.dataset.dragging,localStorage.setItem(ae,String(k)),Q()};t.addEventListener("pointermove",c),t.addEventListener("pointerup",u)}),t.addEventListener("dblclick",()=>{if($)return;vt(null);const n=Ue(X??et()),o=[n.min||320,Number.isFinite(n.max)?n.max:n.ideal];k=Math.abs(k-o[0])<Math.abs(k-o[1])?o[0]:o[1],localStorage.setItem(ae,String(k)),Q()})}let Zn=et();addEventListener("resize",()=>{At(),et()!==Zn&&(Zn=et(),m()),A.hidden||(!$&&!O&&(E.style.height=`${innerHeight-84}px`),je())});const Qn="dt-studio",to=t=>{ye.setAttribute("aria-pressed",String(t)),document.documentElement.classList.toggle("dt-no-studio",!t),_(Qn,t?"1":"0")};ye.addEventListener("click",()=>to(ye.getAttribute("aria-pressed")!=="true")),to(localStorage.getItem(Qn)!=="0"),an.addEventListener("click",()=>st(!M));const $t=document.querySelector(".devtools"),Ft=document.querySelector(".dt-tab"),eo=t=>{$t.toggleAttribute("data-collapsed",t),Ft.toggleAttribute("data-collapsed",t),Ft.setAttribute("aria-expanded",String(!t)),Ft.setAttribute("aria-label",t?"Show the bar":"Hide the bar");for(const e of $t.querySelectorAll(".dt-group"))e.inert=t;t&&Lt(),_("dt-collapsed",t?"1":"0")};Ft.addEventListener("click",()=>eo(!$t.hasAttribute("data-collapsed")));const Ve=document.querySelector(".dt-keys"),rt=t=>()=>$t.querySelector(t)?.click(),no=t=>()=>{const e=[...document.querySelectorAll(".dt-pages a")];e[e.findIndex(n=>n.hasAttribute("aria-current"))+t]?.click()},le=[{group:"Comments",code:"KeyC",hint:"C",label:"Comment mode",el:".dt-notes-btn",run:rt(".dt-notes-btn")},{group:"Comments",code:"KeyC",shift:!0,hint:"\u21E7C",label:"Comments panel",el:".dt-history-btn",run:rt(".dt-history-btn")},{group:"Comments",code:"KeyR",hint:"R",label:"Show resolved",el:".dt-resolved-btn",run:rt(".dt-resolved-btn")},{group:"Inspect",code:"KeyG",hint:"G",label:"Grid",el:".dt-grid-btn",run:rt(".dt-grid-btn")},{group:"Inspect",code:"KeyP",hint:"P",label:"Spacing",el:".dt-pad-btn",run:rt(".dt-pad-btn")},{group:"Inspect",code:"KeyS",hint:"S",label:"Size",el:".dt-size-btn",run:rt(".dt-size-btn")},{group:"Inspect",code:"KeyT",hint:"T",label:"Typography",el:".dt-type-btn",run:rt(".dt-type-btn")},...b.sanity?[{group:"Inspect",code:"KeyE",hint:"E",label:"Sanity overlay",el:".dt-studio-btn",run:rt(".dt-studio-btn")}]:[],...be.slice(0,9).map((t,e)=>({group:"Breakpoints",code:`Digit${e+1}`,hint:String(e+1),label:t.dataset.tip??t.title,el:`.dt-bp[data-bp="${t.dataset.bp}"]`,run:()=>t.click()})),{group:"View",code:"KeyD",hint:"D",label:"Devices",run:()=>{z.open=!z.open}},{group:"View",code:"BracketLeft",hint:"[",label:"Previous page",run:no(-1)},{group:"View",code:"BracketRight",hint:"]",label:"Next page",run:no(1)},{group:"View",code:"Backslash",hint:"\\",label:"Hide the bar",run:()=>Ft.click()},{group:"View",code:"Slash",shift:!0,hint:"?",label:"This list",el:".dt-keys summary",run:()=>{Ve.open=!Ve.open}}].filter(t=>!b.client||t.group!=="Inspect"),oo=(t,e)=>le.find(n=>n.code===t&&!n.shift==!e),rs=t=>t instanceof HTMLElement&&(t.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(t.tagName)||!!t.closest('[role="menu"], [role="listbox"], [role="dialog"][aria-modal="true"], [role="combobox"]'));if(b.shortcuts){for(const e of le){const n=e.el&&$t.querySelector(e.el);n&&(n.dataset.tip=`${n.dataset.tip??e.label} \xB7 ${e.hint}`,n.setAttribute("aria-keyshortcuts",e.hint.startsWith("\u21E7")?`Shift+${e.hint.slice(1)}`:e.hint))}const t=(e,n)=>`<div class="dt-key-row"><span>${g(e)}</span><kbd>${g(n)}</kbd></div>`;if(Ve.querySelector(".dt-keys-menu").innerHTML='<p class="dt-menu-note">One key, no modifier, in any keyboard layout. Not while you type.</p>'+[...new Set(le.map(e=>e.group))].map(e=>`<p class="dt-devices-group">${e}</p>`+le.filter(n=>n.group===e).map(n=>t(n.label,n.hint)).join("")).join("")+'<p class="dt-devices-group">In a comment</p>'+t("Send","Enter")+t("New line","\u21E7Enter")+t("Close, cancel, back out","Esc"),document.addEventListener("keydown",e=>{if(e.repeat||e.isComposing||e.metaKey||e.ctrlKey||e.altKey||e.defaultPrevented||rs(e.target))return;const n=oo(e.code,e.shiftKey);n&&(e.preventDefault(),v?parent.postMessage({dt:!0,key:[e.code,e.shiftKey]},location.origin):n.run())}),v){const e=()=>parent.postMessage({dt:!0,closeMenus:!0},location.origin);document.addEventListener("pointerdown",e,!0),document.addEventListener("keydown",n=>{n.key==="Escape"&&e()})}}if(!v){eo(localStorage.getItem("dt-collapsed")==="1"),requestAnimationFrame(()=>requestAnimationFrame(()=>$t.setAttribute("data-ready",""))),at||$?Q():ze(),pe(localStorage.getItem(Qe)==="1");const t=localStorage.getItem(on);t&&t in fe&&zt(t),st(localStorage.getItem(cn)==="1")}const so=()=>{try{const t=JSON.parse(localStorage.getItem(ft)||"null");q=(t?.parked??[]).filter(e=>Yt(e)),t?.draft&&document.querySelector(t.draft.selector)?(d=t.draft,!M&&!v&&st(!0)):Yt(t?.draft)&&q.push(t.draft),t?.reply?.text&&(F=t.reply.text,kt=y=t.reply.for??null),(d||q.length||F)&&m()}catch{localStorage.removeItem(ft)}};so();const ao=()=>setTimeout(()=>{const t=ue(location.pathname);t!==K&&(clearTimeout(Jt),we(),K=t,ft=un(),d=null,q=[],F="",kt=null,y=null,S=null,h=[],en(),so(),mt())});for(const t of["pushState","replaceState"]){const e=window.history[t];window.history[t]=function(...n){e.apply(this,n),ao()}}addEventListener("popstate",ao),M||mt(),ne().then(()=>{te()&&ee()}),document.addEventListener("visibilitychange",()=>{document.hidden||Pt()}),addEventListener("focus",Pt),addEventListener("notemend:changed",()=>{v||Pt()});let is=0;v||setInterval(()=>{(!fs.live||++is%6===0)&&Pt()},2e4),v&&parent.postMessage({dt:!0,hello:!0},location.origin)}export{Is as run};
@@ -1 +1 @@
1
- import{readFileSync as R,existsSync as T,statSync as W,readdirSync as z}from"node:fs";import{mask as b}from"../store/mask.mjs";import{join as $,isAbsolute as K}from"node:path";import{isIP as D}from"node:net";import{pathToFileURL as V}from"node:url";import{openStore as Z,retry as Q}from"../store/cloud.mjs";import{mentionsIn as X}from"../store/thread.mjs";import{CATEGORIES as Y}from"../store/categories.mjs";import{BREAKPOINTS as q,DEVICES as tt,ICONS as H,SHELLS as M,BROWSERS as G}from"../presets.mjs";const J={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",webp:"image/webp",gif:"image/gif",svg:"image/svg+xml",webm:"video/webm"},U=t=>t.split(".").slice(0,2).map(Number).reduce((n,u)=>n*100+(Number.isNaN(u)?9999:u),0),et=(t,n)=>{try{const m=R(K(n)?n:$(t,n),"utf8").match(/title="([^"]+)"|\btitle:\s*["'`]([^"'`]+)["'`]/);return(m?.[1]??m?.[2])?.split("\u2014").pop()?.trim()||null}catch{return null}};function vt(t){const n=["app","src/app"].map(c=>$(t,c)).find(T),u=[],m=(c,f)=>{for(const l of z(c,{withFileTypes:!0})){const i=l.name;if(l.isDirectory()){if(/^[_@]|^\(\./.test(i))continue;m($(c,i),/^\(.+\)$/.test(i)?f:[...f,i])}else/^page\.(jsx?|tsx?|mdx?)$/.test(i)&&u.push({origin:"project",type:"page",pattern:"/"+f.join("/"),entrypoint:$(c,i)})}};return n&&m(n,[]),u}const nt=t=>t[0].toUpperCase()+t.slice(1).replace(/[-_]+/g," ");function rt({root:t,options:n,routes:u}){const m=n.pages??{},c=(e,d,O)=>({route:e,name:d,label:d.replace(/^[\d.]+[A-Z]?\.\s*/,""),group:O}),f=u.filter(e=>e.origin==="project"&&e.type==="page"&&!e.pattern.includes("[")).map(e=>({route:e.pattern.replace(/\/+$/,"")||"/",entrypoint:e.entrypoint})),l=new Set(f.map(e=>e.route)),i=[...f,...Object.keys(m).filter(e=>!l.has(e)).map(e=>({route:e}))],N={};for(const{route:e}of i){const d=e.split("/")[1];d&&(N[d]=(N[d]||0)+1)}const k=e=>{const d=e.split("/")[1];return d&&N[d]>1?nt(d):"Pages"},L=n.groups?()=>n.groups[n.groups.length-1]:k,I=i.map(({route:e,entrypoint:d})=>{const[O,C]=m[e]??[];return c(e,O??(d&&et(t,d))??e,C??L(e))}),r=n.groups??[...new Set([...Object.values(m).map(([,e])=>e).filter(Boolean),"Pages",...I.map(e=>e.group).sort()])],g=I.sort((e,d)=>r.indexOf(e.group)-r.indexOf(d.group)||U(e.name)-U(d.name)||e.route.localeCompare(d.route)),s=(n.breakpoints??q).map(e=>({id:e.id,label:e.label,min:e.min,ideal:e.ideal,max:Number.isFinite(e.max)?e.max:null,icon:e.icon??H[e.id]??H.desktop})),o=(n.devices??tt).filter(e=>e.w>0&&e.h>0&&M.includes(e.shell)&&G.includes(e.browser)?!0:(console.warn(`[notemend] device "${e.id}" skipped: it needs w and h, shell (${M.join(", ")}) and browser (${G.join(", ")})${e.frame?"; `frame` pictures were replaced by shell + browser in 0.3":""}`),!1));return{pages:g,groups:r.filter(e=>g.some(d=>d.group===e)),breakpoints:s,devices:o,categories:Y,sanity:!!n.sanity,shortcuts:n.shortcuts!==!1,ignore:n.ignore??[],grid:{container:"container",grid:"grid",columns:12,...n.grid},zIndex:n.zIndex??2000000020}}const st=t=>{const n=$(t,"notemend.config.mjs");let u=0,m={};return async()=>{if(!T(n))return{};const c=W(n).mtimeMs;if(c===u)return m;u=c;try{const{default:f,...l}=await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ `${V(n).href}?t=${c}`);m={...l,...f}}catch(f){console.warn(`[notemend] notemend.config.mjs: ${f.message}`)}return m}},ot=t=>{const n=String(t.headers.host||"").toLowerCase(),u=n.startsWith("[")?n.slice(1,n.indexOf("]")):n.replace(/:\d+$/,"");return u.includes(":")?D(u)===6:!u||!u.includes(".")||D(u)===4||/\.(localhost|local|test|internal|lan|home\.arpa)$/.test(u)},h=(t,n)=>String(t??"").replace(/[\u0000-\u001f\u007f]+/g," ").trim().slice(0,n),at=t=>({route:h(t.route,500),text:String(t.text??"").slice(0,1e4),selector:h(t.selector,2e3),rx:Number.isFinite(t.rx)?t.rx:0,ry:Number.isFinite(t.ry)?t.ry:0,label:h(t.label,200),ctx:h(t.ctx,120),breakpoint:h(t.breakpoint,40),browser:h(t.browser,80),device:h(t.device,80),tag:h(t.tag,40),classes:Array.isArray(t.classes)?t.classes.slice(0,20).map(n=>h(n,80)):[],nth:Number.isInteger(t.nth)?t.nth:null,category:h(t.category,40),viewport:t.viewport&&Number.isFinite(t.viewport.w)&&Number.isFinite(t.viewport.h)?{w:t.viewport.w,h:t.viewport.h}:null,...t.assignee==="claude"||typeof t.assignee=="string"&&/^[^\s@]+@[^\s@]+$/.test(t.assignee)&&t.assignee.length<=200?{assignee:t.assignee.toLowerCase()}:{},...Array.isArray(t.logs)&&t.logs.length?{logs:t.logs.slice(-20).map(n=>({at:h(n?.at,30),kind:["console","error","rejection","network"].includes(n?.kind)?n.kind:"console",text:b(h(n?.text,500))})).filter(n=>n.text)}:{},...t.suggest&&typeof t.suggest.from=="string"&&typeof t.suggest.to=="string"&&t.suggest.to.trim()?{suggest:{from:t.suggest.from.slice(0,2e3),to:t.suggest.to.slice(0,2e3)}}:{}}),it=t=>{const n={};return(t.status==="open"||t.status==="done")&&(n.status=t.status),"doneBy"in t&&(n.doneBy=t.doneBy==="you"?"you":null),typeof t.category=="string"&&(n.category=h(t.category,40)),"assignee"in t&&(n.assignee=t.assignee==="claude"||typeof t.assignee=="string"&&/^[^\s@]+@[^\s@]+$/.test(t.assignee)&&t.assignee.length<=200?t.assignee.toLowerCase():null),n},ct=t=>{const n=t.headers.origin;if(!n)return!1;try{return new URL(n).host!==t.headers.host}catch{return!0}};function lt({root:t,options:n,routes:u,open:m=()=>Z(t),crossOrigin:c=!1}){const f=st(t),l=(r,g=200)=>({status:g,type:"application/json",body:JSON.stringify(r)}),i=(r,g)=>({status:r,type:"text/plain",body:g}),N=async r=>{const g=await r.body();if(g.length>45e5)throw Object.assign(new Error("too large"),{status:413});try{return g.length?JSON.parse(g.toString("utf8")):{}}catch{throw Object.assign(new Error("not JSON"),{status:400})}},k=async(r,g)=>{const s=async o=>{const e=await g(o);if(e.status>=400)throw Object.assign(new Error("not written"),{out:e});return e};try{if(r.cloud)return await Q(r,s);const o=r.load(),e=await s(o);return r.save(o),e}catch(o){if(o.out)return o.out;throw o}},L=async(r,g)=>{if(r.method!=="GET"&&!c&&ct(r))return i(403,"Cross-origin write refused");const s=await m();if(r.method==="GET"){const a=g.searchParams.get("route"),p=s.version?String(await s.version()):null;if(p&&g.searchParams.get("since")===p)return{status:204,type:"text/plain",body:""};const x=await s.load();return l({version:p,comments:a?x.comments.filter(S=>S.route===a):x.comments})}let o=null,e=null;const d=s.cloud&&r.method!=="DELETE"?s.people().then(a=>{o=a,e=a.me},a=>{throw a}).catch(a=>a):Promise.resolve(),O=async()=>{const a=await d;if(a instanceof Error)throw a},C=a=>{if(e&&a){a.by=e.email,a.byName=e.name;const p=X(a.text,o.team.filter(x=>x.email!==e.email));p.length&&(a.mentions=p)}return a};if(r.method==="POST"){const{image:a,images:p,...x}=await N(r),S=at(x);return S.text.trim()?S.route.startsWith("/")?k(s,async A=>{await O();const y=C(s.add(A,S));for(const P of[].concat(p??a??[]))await s.attach(A,y.id,P);return l(y,201)}):l({error:"route must be a path"},400):l({error:"empty comment"},400)}if(r.method==="PATCH"){const{id:a,reply:p,image:x,images:S,removeImage:A,edit:y,...P}=await N(r),w=Number(a);if(!Number.isInteger(w))return l({error:"bad id"},400);const E=it(P);return k(s,async j=>{if(await O(),y){const v=j.comments.find(B=>B.id===Number(w)),_=y.at?v?.replies?.find(B=>B.at===y.at):v;if(e&&_?.by&&_.by!==e.email||!(y.text?.trim?.()&&s.edit(j,w,y.at??null,y.text.trim().slice(0,1e4))))return l({error:`no message of yours to edit in #${w}`},404)}p?.trim?.()&&C(s.reply(j,w,"you",p.trim().slice(0,1e4))?.replies.at(-1));for(const v of[].concat(S??x??[]))await s.attach(j,w,v);for(const v of[].concat(A||[]))await s.detach(j,w,v);e&&E.status==="done"&&Object.assign(E,{confirmedBy:e.email,confirmedAt:new Date().toISOString()}),e&&E.status==="open"&&Object.assign(E,{confirmedBy:null,confirmedAt:null});const F=Object.keys(E).length||!p?s.patch(j,w,E):j.comments.find(v=>v.id===Number(w));return F?l(F):l({error:`no comment #${w}`},404)})}if(r.method==="DELETE"){const a=Number(g.searchParams.get("id"));return k(s,async p=>await s.remove(p,a)?l({ok:!0,id:a}):l({error:`no comment #${a}`},404))}return i(405,"Method not allowed")},I=(r,g)=>{const s=g.replace(/^.*[/\\]/,""),o=s.split(".").pop()?.toLowerCase()??"";if(!/^[\w.-]+$/.test(s)||!J[o])return i(400,"Bad name");const e=$(r,s);return T(e)?{status:200,type:J[o],body:R(e)}:i(404,"Not found")};return async r=>{const g=new URL(r.url,"http://devbar"),s=g.pathname.slice(10);if(!c&&!ot(r))return i(403,"Notemend answers local addresses only");try{if(s==="config"){const o=rt({root:t,options:{...await f(),...n},routes:u()}),e=await m();return e.cloud&&Object.assign(o,await e.people().catch(()=>({}))),l(o)}if(s==="comments")return await L(r,g);if(s==="image"){const o=await m(),e=(g.searchParams.get("name")||"").replace(/^.*[/\\]/,"");return o.cloud&&/^[\w.-]+$/.test(e)&&await o.fetchImage(e).catch(()=>null),I(o.imageDir,e)}return i(404,"Not found")}catch(o){return o.status===400||o.status===413?i(o.status,o.message):(console.error("[notemend]",o),i(500,"Something went wrong \u2014 the dev server log says what."))}}}function St(t){const n=lt(t),u=m=>new Promise((c,f)=>{const l=[];m.on("data",i=>l.push(i)),m.on("end",()=>c(Buffer.concat(l))),m.on("error",f)});return async function(c,f,l){if(!c.url||!c.url.startsWith("/__devbar/"))return l();const i=await n({method:c.method,url:c.url,headers:c.headers,body:()=>u(c)});f.statusCode=i.status,f.setHeader("content-type",i.type),f.setHeader("cache-control","no-store"),f.end(i.body)}}export{rt as buildConfig,lt as notemendHandler,St as notemendMiddleware,vt as scanApp,et as titleOf,nt as titled};
1
+ import{readFileSync as R,existsSync as D,statSync as z,readdirSync as b}from"node:fs";import{mask as K}from"../store/mask.mjs";import{join as I,isAbsolute as V}from"node:path";import{isIP as H}from"node:net";import{pathToFileURL as Z}from"node:url";import{openStore as Q,retry as X}from"../store/cloud.mjs";import{mentionsIn as Y}from"../store/thread.mjs";import{CATEGORIES as q}from"../store/categories.mjs";import{BREAKPOINTS as tt,DEVICES as et,ICONS as M,SHELLS as G,BROWSERS as J}from"../presets.mjs";const U={png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",webp:"image/webp",gif:"image/gif",svg:"image/svg+xml",webm:"video/webm"},W=t=>t.split(".").slice(0,2).map(Number).reduce((n,l)=>n*100+(Number.isNaN(l)?9999:l),0),nt=(t,n)=>{try{const m=R(V(n)?n:I(t,n),"utf8").match(/title="([^"]+)"|\btitle:\s*["'`]([^"'`]+)["'`]/);return(m?.[1]??m?.[2])?.split("\u2014").pop()?.trim()||null}catch{return null}};function vt(t){const n=["app","src/app"].map(u=>I(t,u)).find(D),l=[],m=(u,f)=>{for(const a of b(u,{withFileTypes:!0})){const c=a.name;if(a.isDirectory()){if(/^[_@]|^\(\./.test(c))continue;m(I(u,c),/^\(.+\)$/.test(c)?f:[...f,c])}else/^page\.(jsx?|tsx?|mdx?)$/.test(c)&&l.push({origin:"project",type:"page",pattern:"/"+f.join("/"),entrypoint:I(u,c)})}};return n&&m(n,[]),l}const rt=t=>t[0].toUpperCase()+t.slice(1).replace(/[-_]+/g," ");function ot({root:t,options:n,routes:l}){const m=n.pages??{},u=(e,d,$)=>({route:e,name:d,label:d.replace(/^[\d.]+[A-Z]?\.\s*/,""),group:$}),f=l.filter(e=>e.origin==="project"&&e.type==="page"&&!e.pattern.includes("[")).map(e=>({route:e.pattern.replace(/\/+$/,"")||"/",entrypoint:e.entrypoint})),a=new Set(f.map(e=>e.route)),c=[...f,...Object.keys(m).filter(e=>!a.has(e)).map(e=>({route:e}))],N={};for(const{route:e}of c){const d=e.split("/")[1];d&&(N[d]=(N[d]||0)+1)}const E=e=>{const d=e.split("/")[1];return d&&N[d]>1?rt(d):"Pages"},P=n.groups?()=>n.groups[n.groups.length-1]:E,k=c.map(({route:e,entrypoint:d})=>{const[$,B]=m[e]??[];return u(e,$??(d&&nt(t,d))??e,B??P(e))}),r=n.groups??[...new Set([...Object.values(m).map(([,e])=>e).filter(Boolean),"Pages",...k.map(e=>e.group).sort()])],g=k.sort((e,d)=>r.indexOf(e.group)-r.indexOf(d.group)||W(e.name)-W(d.name)||e.route.localeCompare(d.route)),o=(n.breakpoints??tt).map(e=>({id:e.id,label:e.label,min:e.min,ideal:e.ideal,max:Number.isFinite(e.max)?e.max:null,icon:e.icon??M[e.id]??M.desktop})),i=(n.devices??et).filter(e=>e.w>0&&e.h>0&&G.includes(e.shell)&&J.includes(e.browser)?!0:(console.warn(`[notemend] device "${e.id}" skipped: it needs w and h, shell (${G.join(", ")}) and browser (${J.join(", ")})${e.frame?"; `frame` pictures were replaced by shell + browser in 0.3":""}`),!1));return{pages:g,groups:r.filter(e=>g.some(d=>d.group===e)),breakpoints:o,devices:i,categories:q,sanity:!!n.sanity,shortcuts:n.shortcuts!==!1,ignore:n.ignore??[],grid:{container:"container",grid:"grid",columns:12,...n.grid},zIndex:n.zIndex??2000000020}}const st=t=>{const n=I(t,"notemend.config.mjs");let l=0,m={};return async()=>{if(!D(n))return{};const u=z(n).mtimeMs;if(u===l)return m;l=u;try{const{default:f,...a}=await import(/* webpackIgnore: true */ /* turbopackIgnore: true */ `${Z(n).href}?t=${u}`);m={...a,...f}}catch(f){console.warn(`[notemend] notemend.config.mjs: ${f.message}`)}return m}},it=t=>{const n=String(t.headers.host||"").toLowerCase(),l=n.startsWith("[")?n.slice(1,n.indexOf("]")):n.replace(/:\d+$/,"");return l.includes(":")?H(l)===6:!l||!l.includes(".")||H(l)===4||/\.(localhost|local|test|internal|lan|home\.arpa)$/.test(l)},p=(t,n)=>String(t??"").replace(/[\u0000-\u001f\u007f]+/g," ").trim().slice(0,n),at=t=>({route:p(t.route,500),text:String(t.text??"").slice(0,1e4),selector:p(t.selector,2e3),rx:Number.isFinite(t.rx)?t.rx:0,ry:Number.isFinite(t.ry)?t.ry:0,label:p(t.label,200),ctx:p(t.ctx,120),breakpoint:p(t.breakpoint,40),browser:p(t.browser,80),device:p(t.device,80),tag:p(t.tag,40),classes:Array.isArray(t.classes)?t.classes.slice(0,20).map(n=>p(n,80)):[],nth:Number.isInteger(t.nth)?t.nth:null,category:p(t.category,40),...["urgent","high","low"].includes(t.priority)?{priority:t.priority}:{},viewport:t.viewport&&Number.isFinite(t.viewport.w)&&Number.isFinite(t.viewport.h)?{w:t.viewport.w,h:t.viewport.h}:null,...t.assignee==="claude"||typeof t.assignee=="string"&&/^[^\s@]+@[^\s@]+$/.test(t.assignee)&&t.assignee.length<=200?{assignee:t.assignee.toLowerCase()}:{},...typeof t.host=="string"&&/^[a-z0-9.-]{1,120}(:\d{1,5})?$/i.test(t.host)?{host:t.host.toLowerCase()}:{},...Array.isArray(t.logs)&&t.logs.length?{logs:t.logs.slice(-20).map(n=>({at:p(n?.at,30),kind:["console","error","rejection","network"].includes(n?.kind)?n.kind:"console",text:K(p(n?.text,500))})).filter(n=>n.text)}:{},...t.suggest&&typeof t.suggest.from=="string"&&typeof t.suggest.to=="string"&&t.suggest.to.trim()?{suggest:{from:t.suggest.from.slice(0,2e3),to:t.suggest.to.slice(0,2e3)}}:{}}),ct=t=>{const n={};return(t.status==="open"||t.status==="done")&&(n.status=t.status),"doneBy"in t&&(n.doneBy=t.doneBy==="you"?"you":null),typeof t.category=="string"&&(n.category=p(t.category,40)),"priority"in t&&(n.priority=["urgent","high","low"].includes(t.priority)?t.priority:null),t.fixNow===!0&&(n.fixNow=new Date().toISOString(),n.assignee="claude"),"assignee"in t&&(n.assignee=t.assignee==="claude"||typeof t.assignee=="string"&&/^[^\s@]+@[^\s@]+$/.test(t.assignee)&&t.assignee.length<=200?t.assignee.toLowerCase():null),n},ut=t=>{const n=t.headers.origin;if(!n)return!1;try{return new URL(n).host!==t.headers.host}catch{return!0}};function lt({root:t,options:n,routes:l,open:m=()=>Q(t),crossOrigin:u=!1}){const f=st(t),a=(r,g=200)=>({status:g,type:"application/json",body:JSON.stringify(r)}),c=(r,g)=>({status:r,type:"text/plain",body:g}),N=async r=>{const g=await r.body();if(g.length>45e5)throw Object.assign(new Error("too large"),{status:413});try{return g.length?JSON.parse(g.toString("utf8")):{}}catch{throw Object.assign(new Error("not JSON"),{status:400})}},E=async(r,g)=>{const o=async i=>{const e=await g(i);if(e.status>=400)throw Object.assign(new Error("not written"),{out:e});return e};try{if(r.cloud)return await X(r,o);const i=r.load(),e=await o(i);return r.save(i),e}catch(i){if(i.out)return i.out;throw i}},P=async(r,g)=>{if(r.method!=="GET"&&!u&&ut(r))return c(403,"Cross-origin write refused");const o=await m();if(r.method==="GET"){const s=g.searchParams.get("route"),h=o.version?String(await o.version()):null;if(h&&g.searchParams.get("since")===h)return{status:204,type:"text/plain",body:""};const y=await o.load();return a({version:h,comments:s?y.comments.filter(j=>j.route===s):y.comments,listening:y.listening??null,turbo:y.turbo??null})}let i=null,e=null;const d=o.cloud&&r.method!=="DELETE"?o.people().then(s=>{i=s,e=s.me},s=>{throw s}).catch(s=>s):Promise.resolve(),$=async()=>{const s=await d;if(s instanceof Error)throw s},B=s=>{if(e&&s){s.by=e.email,s.byName=e.name;const h=Y(s.text,i.team.filter(y=>y.email!==e.email));h.length&&(s.mentions=h)}return s};if(r.method==="POST"){const{image:s,images:h,...y}=await N(r),j=at(y);return j.text.trim()?j.route.startsWith("/")?E(o,async C=>{await $();const A=B(o.add(C,j));for(const O of[].concat(h??s??[]))await o.attach(C,A.id,O);return a(A,201)}):a({error:"route must be a path"},400):a({error:"empty comment"},400)}if(r.method==="PATCH"){const s=await N(r);if(s.turbo==="on"||s.turbo==="off")return E(o,async S=>(S.turbo={paused:s.turbo==="off",at:new Date().toISOString()},a({turbo:S.turbo})));const{id:h,reply:y,image:j,images:C,removeImage:A,edit:O,...F}=s,x=Number(h);if(!Number.isInteger(x))return a({error:"bad id"},400);const v=ct(F);return E(o,async S=>{if(await $(),O){const w=S.comments.find(T=>T.id===Number(x)),L=O.at?w?.replies?.find(T=>T.at===O.at):w;if(e&&L?.by&&L.by!==e.email||!(O.text?.trim?.()&&o.edit(S,x,O.at??null,O.text.trim().slice(0,1e4))))return a({error:`no message of yours to edit in #${x}`},404)}y?.trim?.()&&B(o.reply(S,x,"you",y.trim().slice(0,1e4))?.replies.at(-1));for(const w of[].concat(C??j??[]))await o.attach(S,x,w);for(const w of[].concat(A||[]))await o.detach(S,x,w);if(e&&v.status==="done"&&Object.assign(v,{confirmedBy:e.email,confirmedAt:new Date().toISOString()}),e&&v.status==="open"&&Object.assign(v,{confirmedBy:null,confirmedAt:null}),F.archive===!0){const w=S.comments.find(L=>L.id===x);w&&w.status!=="done"&&Object.assign(v,{status:"done",doneBy:"you",working:null}),w?.doneBy==="claude"&&e&&Object.assign(v,{doneBy:"you",confirmedBy:e.email,confirmedAt:new Date().toISOString()}),Object.assign(v,{archivedAt:new Date().toISOString(),...e?{archivedBy:e.email}:{}})}const _=Object.keys(v).length||!y?o.patch(S,x,v):S.comments.find(w=>w.id===Number(x));return _?a(_):a({error:`no comment #${x}`},404)})}if(r.method==="DELETE"){const s=Number(g.searchParams.get("id"));return E(o,async h=>await o.remove(h,s)?a({ok:!0,id:s}):a({error:`no comment #${s}`},404))}return c(405,"Method not allowed")},k=(r,g)=>{const o=g.replace(/^.*[/\\]/,""),i=o.split(".").pop()?.toLowerCase()??"";if(!/^[\w.-]+$/.test(o)||!U[i])return c(400,"Bad name");const e=I(r,o);return D(e)?{status:200,type:U[i],body:R(e)}:c(404,"Not found")};return async r=>{const g=new URL(r.url,"http://devbar"),o=g.pathname.slice(10);if(!u&&!it(r))return c(403,"Notemend answers local addresses only");try{if(o==="config"){const i=ot({root:t,options:{...await f(),...n},routes:l()}),e=await m();return e.cloud&&Object.assign(i,await e.people().catch(()=>({}))),a(i)}if(o==="comments")return await P(r,g);if(o==="image"){const i=await m(),e=(g.searchParams.get("name")||"").replace(/^.*[/\\]/,"");return i.cloud&&/^[\w.-]+$/.test(e)&&await i.fetchImage(e).catch(()=>null),k(i.imageDir,e)}return c(404,"Not found")}catch(i){return i.status===400||i.status===413?c(i.status,i.message):(console.error("[notemend]",i),c(500,"Something went wrong \u2014 the dev server log says what."))}}}function Ot(t){const n=lt(t),l=m=>new Promise((u,f)=>{const a=[];m.on("data",c=>a.push(c)),m.on("end",()=>u(Buffer.concat(a))),m.on("error",f)});return async function(u,f,a){if(!u.url||!u.url.startsWith("/__devbar/"))return a();const c=await n({method:u.method,url:u.url,headers:u.headers,body:()=>l(u)});f.statusCode=c.status,f.setHeader("content-type",c.type),f.setHeader("cache-control","no-store"),f.end(c.body)}}export{ot as buildConfig,lt as notemendHandler,Ot as notemendMiddleware,vt as scanApp,nt as titleOf,rt as titled};