wiki-plugin-similarity 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
- /* wiki-plugin-similarity - 0.17.0 - Thu, 03 Sep 2026 23:17:35 GMT */
2
- (()=>{var G={high:.78,medium:.68,low:.58},B=G.medium,X=10,V=t=>{let e=[],n=[],s=[],h=null,b=null,m="search",x=!1,L=!1,S=!1,R=null,T=null,v=(a,c)=>a===c||a.startsWith(c)&&/^[\s:]/.test(a.slice(c.length)),y=(a,c)=>a.slice(c.length).replace(/^\s*:?\s*/,"").trim();for(let a of t.split(`
3
- `)){let c=a.trim();if(!c||c.startsWith("#"))continue;let g=c.toUpperCase();if(v(g,"LIVE")){x=!0;continue}if(v(g,"SUBJECT")){L=!0;continue}if(v(g,"AUTHOR")){!e.length&&m==="search"&&(m="author");continue}if(v(g,"REPORT")){m==="search"&&(m="report");continue}if(v(g,"KEYWORD")){m==="search"&&(m="keyword");continue}if(v(g,"SITES")){m==="search"&&(m="sites");continue}if(v(g,"BUILD")){m==="search"&&(m="build");continue}if(v(g,"FORCE")){S=!0;continue}if(v(g,"GHOST")){R=y(c,"GHOST"),m==="search"&&(m="ghost");continue}if(v(g,"BUTTON")){T=y(c,"BUTTON");continue}if(v(g,"ROSTER")){let E=y(c,"ROSTER");E&&n.push(E);continue}if(v(g,"FARM")){let E=y(c,"FARM");E&&s.push(E);continue}if(v(g,"LIST")){!e.length&&m==="search"&&(m="list");continue}if(v(g,"STATUS")){m==="search"&&(m="status");continue}if(v(g,"SIMILAR")){let E=y(g,"SIMILAR").toLowerCase();h=G[E]||B,!e.length&&m==="search"&&(m="similar");continue}if(v(g,"THRESHOLD")){let E=y(c,"THRESHOLD");h=G[E.toLowerCase()]??(parseFloat(E)||B);continue}if(v(g,"LIMIT")){b=parseInt(y(c,"LIMIT"))||X;continue}e.push(["PUBLIC","LOCAL","PRIVATE","GALAXY","SITE"].includes(g)?g:c)}return{mode:m,specs:e,rosterRefs:n,farms:s,threshold:h??B,limit:b??X,live:x,subject:L,force:S,ghostUrl:R,label:T,thresholdSet:h!==null}},Q=t=>t.includes("*")||t.includes("?"),tt=t=>t==="PUBLIC"||t==="LOCAL"||t==="PRIVATE"||t==="GALAXY";var nt=t=>t.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),K=new Map,yt=async(t,e)=>{if(K.has(t))return K.get(t);let n=`${e}/system/indexed-domains.json?pattern=${encodeURIComponent(t)}`,s=await fetch(n);if(!s.ok)throw new Error(`indexed-domains failed: ${s.status}`);let h=await s.json();return K.set(t,h),h},U=async(t,e)=>{t.length||(t=[window.location.hostname]);let n=new Set,s=[];for(let h of t)if(h==="*"||Q(h)||tt(h))for(let b of await yt(h,e))n.has(b.domain)||(n.add(b.domain),s.push(b));else n.has(h)||(n.add(h),s.push({domain:h,page_count:null}));return s},xt=/^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+|localhost)(:\d+)?$/,bt=/^ROSTER ([A-Za-z0-9.\-:]+\/[a-z0-9-]+)$/,vt=/^REFERENCES ([A-Za-z0-9.\-:]+\/[a-z0-9-]+)$/,et=async t=>{let e=t.indexOf("/"),n=await fetch(`//${t.slice(0,e)}/${t.slice(e+1)}.json`);if(!n.ok)throw new Error(`roster page ${t} failed: ${n.status}`);return n.json()},st=async(t,e,n)=>{if(n.has(t))return;n.add(t);let s;try{s=await et(t)}catch(h){console.warn(h.message);return}for(let h of s.story||[])if(h.type==="roster")for(let b of(h.text||"").split(/\r?\n/)){let m=b.trim();if(!m)continue;let x=m.match(xt);if(x){e.add(x[0]);continue}let L=m.match(bt);if(L){await st(L[1],e,n);continue}let S=m.match(vt);if(S)try{let R=await et(S[1]);for(let T of R.story||[])T.type==="reference"&&T.site&&e.add(T.site)}catch(R){console.warn(R.message)}}},St=async t=>{let e=new Set,n=new Set;for(let s of t)await st(s,e,n);return[...e]},it=async(t,e)=>{let n=typeof window<"u"&&window.location?window.location.hostname:null,s=t.map(h=>h.toUpperCase()==="SITE"&&n?n:h);return e.length?[...s,...await St(e)]:s};var J=new Map,kt=t=>`${window.location.origin}/system/semantic-vectors.json?domain=${encodeURIComponent(t)}`,ot=async t=>{if(J.has(t))return J.get(t);let e=await fetch(kt(t));if(!e.ok)return[];let n=await e.json();return J.set(t,n),n},N=async(t,e)=>{let n=await fetch(`${e}/system/embed.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:t})});if(!n.ok)throw new Error(`embed failed: ${n.status}`);return(await n.json()).vector},at=async(t,e)=>{let s=(await ot(e)).find(h=>h.slug===t);return s?s.vector:null},q=(t,e,{threshold:n,limit:s,excludeSlug:h,excludeDomain:b})=>{let m=[];for(let{domain:x,pages:L}of e)for(let{slug:S,title:R,vector:T}of L){if(S===h&&x===b)continue;let v=0;for(let y=0;y<t.length;y++)v+=t[y]*T[y];v>=n&&m.push({domain:x,slug:S,title:R,score:v})}return m.sort((x,L)=>L.score-x.score),m.slice(0,s)},z=async(t,e)=>{let n=await U(t,e);return(await Promise.all(n.map(async({domain:h})=>({domain:h,pages:await ot(h)})))).filter(h=>h.pages.length>0)};var rt=t=>{let e=t.parents(".page:first"),n=e.prev(".page"),s=n.length?n:e,h=(s.attr("id")||"").split("_rev")[0],b=s.data("site")||window.location.hostname,m=s.data("data")||{},x=m.title||s.find(".title").text().trim()||h,L=[x,...(m.story||[]).filter(S=>S.type==="markdown"||S.type==="paragraph").map(S=>(S.text||"").trim()).filter(Boolean)].join(`
4
- `).slice(0,2e3);return{slug:h,site:b,title:x,text:L,isSelf:!n.length}},O=t=>`Subject: ${t.title}${t.isSelf?" (this page)":` @ ${t.site}`}`;var lt=t=>`sim-cache-${t}`,ct=t=>{try{let e=JSON.parse(localStorage.getItem(lt(t.id))||"null");return e?.text===(t.text||"")?e:null}catch{return null}},M=(t,e)=>{try{localStorage.setItem(lt(t.id),JSON.stringify({text:t.text||"",ts:Date.now(),...e}))}catch{}},dt=t=>{let e=Math.floor((Date.now()-t)/1e3);return e<60?`${e}s ago`:e<3600?`${Math.floor(e/60)}m ago`:e<86400?`${Math.floor(e/3600)}h ago`:`${Math.floor(e/86400)}d ago`};var P=`
1
+ /* wiki-plugin-similarity - 0.18.0 - Fri, 04 Sep 2026 07:13:10 GMT */
2
+ (()=>{var V={high:.78,medium:.68,low:.58},G=V.medium,Q=10,K=t=>{let e=[],n=[],o=[],p=null,b=null,m="search",x=!1,C=!1,k=!1,R=null,T=null,v=(r,c)=>r===c||r.startsWith(c)&&/^[\s:]/.test(r.slice(c.length)),y=(r,c)=>r.slice(c.length).replace(/^\s*:?\s*/,"").trim();for(let r of t.split(`
3
+ `)){let c=r.trim();if(!c||c.startsWith("#"))continue;let g=c.toUpperCase();if(v(g,"LIVE")){x=!0;continue}if(v(g,"SUBJECT")){C=!0;continue}if(v(g,"AUTHOR")){!e.length&&m==="search"&&(m="author");continue}if(v(g,"REPORT")){m==="search"&&(m="report");continue}if(v(g,"KEYWORD")){m==="search"&&(m="keyword");continue}if(v(g,"SITES")){m==="search"&&(m="sites");continue}if(v(g,"BUILD")){m==="search"&&(m="build");continue}if(v(g,"FORCE")){k=!0;continue}if(v(g,"GHOST")){R=y(c,"GHOST"),m==="search"&&(m="ghost");continue}if(v(g,"BUTTON")){T=y(c,"BUTTON");continue}if(v(g,"ROSTER")){let j=y(c,"ROSTER");j&&n.push(j);continue}if(v(g,"FARM")){let j=y(c,"FARM");j&&o.push(j);continue}if(v(g,"LIST")){!e.length&&m==="search"&&(m="list");continue}if(v(g,"STATUS")){m==="search"&&(m="status");continue}if(v(g,"SIMILAR")){let j=y(g,"SIMILAR").toLowerCase();p=V[j]||G,!e.length&&m==="search"&&(m="similar");continue}if(v(g,"THRESHOLD")){let j=y(c,"THRESHOLD");p=V[j.toLowerCase()]??(parseFloat(j)||G);continue}if(v(g,"LIMIT")){b=parseInt(y(c,"LIMIT"))||Q;continue}e.push(["PUBLIC","LOCAL","PRIVATE","GALAXY","SITE"].includes(g)?g:c)}return{mode:m,specs:e,rosterRefs:n,farms:o,threshold:p??G,limit:b??Q,live:x,subject:C,force:k,ghostUrl:R,label:T,thresholdSet:p!==null}},tt=t=>t.includes("*")||t.includes("?"),et=t=>t==="PUBLIC"||t==="LOCAL"||t==="PRIVATE"||t==="GALAXY";var st=t=>t.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),J=new Map,yt=async(t,e)=>{if(J.has(t))return J.get(t);let n=`${e}/system/indexed-domains.json?pattern=${encodeURIComponent(t)}`,o=await fetch(n);if(!o.ok)throw new Error(`indexed-domains failed: ${o.status}`);let p=await o.json();return J.set(t,p),p},M=async(t,e)=>{t.length||(t=[window.location.hostname]);let n=new Set,o=[];for(let p of t)if(p==="*"||tt(p)||et(p))for(let b of await yt(p,e))n.has(b.domain)||(n.add(b.domain),o.push(b));else n.has(p)||(n.add(p),o.push({domain:p,page_count:null}));return o},xt=/^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+|localhost)(:\d+)?$/,bt=/^ROSTER ([A-Za-z0-9.\-:]+\/[a-z0-9-]+)$/,vt=/^REFERENCES ([A-Za-z0-9.\-:]+\/[a-z0-9-]+)$/,nt=async t=>{let e=t.indexOf("/"),n=await fetch(`//${t.slice(0,e)}/${t.slice(e+1)}.json`);if(!n.ok)throw new Error(`roster page ${t} failed: ${n.status}`);return n.json()},ot=async(t,e,n)=>{if(n.has(t))return;n.add(t);let o;try{o=await nt(t)}catch(p){console.warn(p.message);return}for(let p of o.story||[])if(p.type==="roster")for(let b of(p.text||"").split(/\r?\n/)){let m=b.trim();if(!m)continue;let x=m.match(xt);if(x){e.add(x[0]);continue}let C=m.match(bt);if(C){await ot(C[1],e,n);continue}let k=m.match(vt);if(k)try{let R=await nt(k[1]);for(let T of R.story||[])T.type==="reference"&&T.site&&e.add(T.site)}catch(R){console.warn(R.message)}}},St=async t=>{let e=new Set,n=new Set;for(let o of t)await ot(o,e,n);return[...e]},it=async(t,e)=>{let n=typeof window<"u"&&window.location?window.location.hostname:null,o=t.map(p=>p.toUpperCase()==="SITE"&&n?n:p);return e.length?[...o,...await St(e)]:o};var W=new Map,kt=t=>`${window.location.origin}/system/semantic-vectors.json?domain=${encodeURIComponent(t)}`,at=async t=>{if(W.has(t))return W.get(t);let e=await fetch(kt(t));if(!e.ok)return[];let n=await e.json();return W.set(t,n),n},q=async(t,e)=>{let n=await fetch(`${e}/system/embed.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:t})});if(!n.ok)throw new Error(`embed failed: ${n.status}`);return(await n.json()).vector},rt=async(t,e)=>{let o=(await at(e)).find(p=>p.slug===t);return o?o.vector:null},N=(t,e,{threshold:n,limit:o,excludeSlug:p,excludeDomain:b})=>{let m=[];for(let{domain:x,pages:C}of e)for(let{slug:k,title:R,vector:T}of C){if(k===p&&x===b)continue;let v=0;for(let y=0;y<t.length;y++)v+=t[y]*T[y];v>=n&&m.push({domain:x,slug:k,title:R,score:v})}return m.sort((x,C)=>C.score-x.score),m.slice(0,o)},z=async(t,e)=>{let n=await M(t,e);return(await Promise.all(n.map(async({domain:p})=>({domain:p,pages:await at(p)})))).filter(p=>p.pages.length>0)};var lt=t=>{let e=t.parents(".page:first"),n=e.prev(".page"),o=n.length?n:e,p=(o.attr("id")||"").split("_rev")[0],b=o.data("site")||window.location.hostname,m=o.data("data")||{},x=m.title||o.find(".title").text().trim()||p,C=[x,...(m.story||[]).filter(k=>k.type==="markdown"||k.type==="paragraph").map(k=>(k.text||"").trim()).filter(Boolean)].join(`
4
+ `).slice(0,2e3);return{slug:p,site:b,title:x,text:C,isSelf:!n.length}},D=t=>`Subject: ${t.title}${t.isSelf?" (this page)":` @ ${t.site}`}`;var ct=t=>`sim-cache-${t}`,dt=t=>{try{let e=JSON.parse(localStorage.getItem(ct(t.id))||"null");return e?.text===(t.text||"")?e:null}catch{return null}},A=(t,e)=>{try{localStorage.setItem(ct(t.id),JSON.stringify({text:t.text||"",ts:Date.now(),...e}))}catch{}},ut=t=>{let e=Math.floor((Date.now()-t)/1e3);return e<60?`${e}s ago`:e<3600?`${Math.floor(e/60)}m ago`:e<86400?`${Math.floor(e/3600)}h ago`:`${Math.floor(e/86400)}d ago`};var O=`
5
5
  .sim-form { display:flex; gap:6px; margin-bottom:8px; }
6
6
  .sim-input { flex:1; padding:6px 8px; font-size:14px; border:1px solid #ccc; border-radius:3px; }
7
7
  .sim-btn { padding:6px 14px; background:#c4561d; color:white; border:none;
@@ -25,80 +25,81 @@
25
25
  .sim-list td { padding:3px 8px 3px 0; border-bottom:1px solid #f0f0f0; vertical-align:middle; }
26
26
  .sim-list td:last-child { text-align:right; color:#999; font-size:11px; }
27
27
  .sim-list .sim-flag { margin-right:6px; }
28
- `,ut=(t,e)=>`<img class="sim-flag remote" src="${window.wiki.site(t).flag()}"
28
+ `,ft=(t,e)=>`<img class="sim-flag remote" src="${window.wiki.site(t).flag()}"
29
29
  title="${t} \u2014 score ${e.toFixed(3)}"
30
- data-site="${t}">`;var Et="Search Tool",Lt="search-tool",F=null,jt=()=>fetch(`/${Lt}.json`,{method:"GET"}).then(t=>{F=t.ok}).catch(()=>{F=!1}),Ct=t=>{let e=window.$(t).parents(".page");return e.length?e:null},ft=(t,e)=>{window.wiki.doInternalLink(Et,e?null:t)},mt=()=>{typeof document>"u"||!window.wiki||!window.$||(jt(),document.addEventListener("click",t=>{if(F!==!0)return;let e=t.target&&t.target.closest&&t.target.closest("a.search");if(!e)return;let n=Ct(e);n&&(t.preventDefault(),t.stopPropagation(),ft(n,t.shiftKey))},!0),document.addEventListener("keydown",t=>{if(F!==!0||t.key!=="Enter")return;let e=t.target;if(!e||!e.classList||!e.classList.contains("search")||!e.closest(".searchbox"))return;let n=(e.value||"").trim();n&&(t.preventDefault(),t.stopPropagation(),window.$(".incremental-search").remove(),e.value="",Tt(n),ft(window.$(".page").last(),!1))},!0))},W=null,Tt=t=>{W=t},ht=()=>{let t=W;return W=null,t};var Y=(t,e,n,s)=>`<a class="sim-link" data-title="${n}" data-slug="${e}" data-site="${t}" href="#">${ut(t,s)} ${n}</a>`,Rt=(t,e)=>{let{mode:n,specs:s,threshold:h,limit:b,force:m,ghostUrl:x,label:L}=V(e?.text||"");if(n==="ghost")t.html(`
31
- <style>${P}</style>
32
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
30
+ data-site="${t}">`;var Et="Search Tool",Lt="search-tool",F=null,jt=()=>fetch(`/${Lt}.json`,{method:"GET"}).then(t=>{F=t.ok}).catch(()=>{F=!1}),Ct=t=>{let e=window.$(t).parents(".page");return e.length?e:null},mt=(t,e)=>{window.wiki.doInternalLink(Et,e?null:t)},pt=()=>{typeof document>"u"||!window.wiki||!window.$||(jt(),document.addEventListener("click",t=>{if(F!==!0)return;let e=t.target&&t.target.closest&&t.target.closest("a.search");if(!e)return;let n=Ct(e);n&&(t.preventDefault(),t.stopPropagation(),mt(n,t.shiftKey))},!0),document.addEventListener("keydown",t=>{if(F!==!0||t.key!=="Enter")return;let e=t.target;if(!e||!e.classList||!e.classList.contains("search")||!e.closest(".searchbox"))return;let n=(e.value||"").trim();n&&(t.preventDefault(),t.stopPropagation(),window.$(".incremental-search").remove(),e.value="",Tt(n),mt(window.$(".page").last(),!1))},!0))},Y=null,Tt=t=>{Y=t},ht=()=>{let t=Y;return Y=null,t};var Z=(t,e,n,o)=>`<a class="sim-link" data-title="${n}" data-slug="${e}" data-site="${t}" href="#">${ft(t,o)} ${n}</a>`,Rt=(t,e)=>{let{mode:n,specs:o,threshold:p,limit:b,force:m,ghostUrl:x,label:C}=K(e?.text||"");if(n==="ghost")t.html(`
31
+ <style>${O}</style>
32
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
33
33
  <div class="sim-form">
34
- <button class="sim-btn">${L||"Open"}</button>
34
+ <button class="sim-btn">${C||"Open"}</button>
35
35
  </div>
36
36
  <div class="sim-status"></div>
37
37
  </div>`);else if(n==="build")t.html(`
38
- <style>${P}</style>
39
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
38
+ <style>${O}</style>
39
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
40
40
  <div class="sim-form">
41
- <button class="sim-btn">${L||`Index ${s.length?s.join(", "):"*"}${m?" (force)":""}`}</button>
41
+ <button class="sim-btn">${C||`Index ${o.length?o.join(", "):"*"}${m?" (force)":""}`}</button>
42
42
  </div>
43
43
  <div class="sim-status"></div>
44
- </div>`);else if(n==="list"){let S=s.length?s.join(", "):"*";t.html(`
45
- <style>${P}</style>
46
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
47
- <div class="sim-status">Loading indexed domains (${S})\u2026</div>
44
+ </div>`);else if(n==="list"){let k=o.length?o.join(", "):"*";t.html(`
45
+ <style>${O}</style>
46
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
47
+ <div class="sim-status">Loading indexed domains (${k})\u2026</div>
48
48
  <div class="sim-list"></div>
49
49
  </div>`)}else if(n==="status")t.html(`
50
- <style>${P}</style>
51
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
50
+ <style>${O}</style>
51
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
52
52
  <div class="sim-status">Reading the state of the index\u2026</div>
53
53
  <div class="sim-list"></div>
54
- </div>`);else if(n==="similar"){let S=s.length?s.join(", "):"current domain";t.html(`
55
- <style>${P}</style>
56
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
57
- <div class="sim-status">Finding similar pages across ${S}\u2026</div>
54
+ </div>`);else if(n==="similar"){let k=o.length?o.join(", "):"current domain";t.html(`
55
+ <style>${O}</style>
56
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
57
+ <div class="sim-status">Finding similar pages across ${k}\u2026</div>
58
58
  <div class="sim-results"></div>
59
- </div>`)}else if(n==="author"||n==="report"||n==="keyword"||n==="sites"){let S=s.length?s.join(", "):"(current domain)",R=n==="report"?"Report":n==="keyword"?"Keyword":n==="sites"?"Sites":"Author",T=n==="sites"?"Where should this page go? Title + first paragraph\u2026":"Search wiki pages\u2026";t.html(`
60
- <style>${P}</style>
61
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
59
+ </div>`)}else if(n==="author"||n==="report"||n==="keyword"||n==="sites"){let k=o.length?o.join(", "):"(current domain)",R=n==="report"?"Report":n==="keyword"?"Keyword":n==="sites"?"Sites":"Author",T=n==="sites"?"Where should this page go? Title + first paragraph\u2026":"Search wiki pages\u2026";t.html(`
60
+ <style>${O}</style>
61
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
62
62
  <div class="sim-form">
63
63
  <input class="sim-input" type="text" placeholder="${T}" />
64
64
  <button class="sim-btn">${R}</button>
65
65
  </div>
66
- <div class="sim-status">Domains: ${S}</div>
66
+ <div class="sim-status">Domains: ${k}</div>
67
67
  <div class="sim-results"></div>
68
- </div>`)}else{let S=s.length?s.join(", "):"(current domain)";t.html(`
69
- <style>${P}</style>
70
- <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${s.join(",")||""}">
68
+ </div>`)}else{let k=o.length?o.join(", "):"(current domain)";t.html(`
69
+ <style>${O}</style>
70
+ <div class="similarity" data-id="${e.id}" data-mode="${n}" data-scope="${o.join(",")||""}">
71
71
  <div class="sim-form">
72
72
  <input class="sim-input" type="text" placeholder="Search wiki pages\u2026" />
73
73
  <button class="sim-btn">Search</button>
74
74
  </div>
75
- <div class="sim-status">Domains: ${S}</div>
75
+ <div class="sim-status">Domains: ${k}</div>
76
76
  <div class="sim-results"></div>
77
- </div>`)}},It=(t,e)=>{let{mode:n,specs:s,rosterRefs:h,farms:b,threshold:m,limit:x,live:L,subject:S,force:R,ghostUrl:T,thresholdSet:v}=V(e?.text||""),y=window.location.origin,a=t.find(".sim-status")[0],c=S?rt(t):null,g=L||c?null:ct(e),E=it(s,h),Z=()=>c?{seed:{site:c.site,slug:c.slug},text:c.text,excludePage:{site:c.site,slug:c.slug}}:{},H=(d,p,i)=>{let r=p>0?`${p.toLocaleString()} pages across ${i} domains`:`${i} domain${i===1?"":"s"}`,u=[`${d} \u2014 ${r}`];return v&&u.push(`threshold ${m}`),u.push(`limit ${x}`),L&&u.push("LIVE"),u.join(" \xB7 ")};t.on("dblclick",d=>{$(d.target).closest(".sim-input").length||window.wiki.textEditor(t,e)}),t.on("click",".sim-link",function(d){d.preventDefault();let p=$(this),i=d.shiftKey?null:t.parents(".page");window.wiki.doInternalLink(p.data("title"),i,p.data("site"))});let pt=!s.length||s.length===1&&s[0]==="*"?"on farm":s.length===1?`on ${s[0]}`:"in domains",_=d=>d?` \xB7 cached ${dt(d)}`:"";if(n==="status"){let d=t.find(".sim-list")[0],p=r=>{if(!r)return"unknown";let u=(Date.now()-new Date(r))/864e5;return u<1?"today":u<2?"yesterday":`${Math.floor(u)} days ago`},i=r=>r?new Date(r).toISOString().slice(0,10):"\u2014";(async()=>{try{let r=()=>fetch(`${y}/system/embed.json?text=ping`).then(async C=>C.ok?{ok:!0}:{ok:!1,detail:((await C.json().catch(()=>({}))).error||`status ${C.status}`).replace(/^embedding unavailable: /,"")}).catch(C=>({ok:!1,detail:C.message})),[u,o,l]=await Promise.all([fetch(`${y}/system/similarity-health.json`).then(C=>C.json()),fetch(`${y}/system/indexed-domains.json`).then(C=>C.ok?C.json():[]),r()]),f=u.embedder||{},w=o.map(C=>C.built).filter(Boolean).sort(),j=o.reduce((C,I)=>C+(I.page_count||0),0),k=!l.ok,D=k?`<strong>Semantic search is down</strong> \u2014 a query cannot be turned into a vector right now (${l.detail}), so searches on this page will answer by keyword instead.`:"Semantic search is <strong>up</strong> \u2014 checked just now by embedding a word.",A=f.via==="url"?`delegated to <code>${f.url}</code> (from ${f.source||"config"})`:f.via==="semindex"?"in this process, via the SemIndex plugin":"in this process, in a supervised child";a.style.display="none",d.innerHTML=`<h3>The Index Behind These Answers</h3>
78
- <p>${D}</p>
77
+ </div>`)}},It=(t,e)=>{let{mode:n,specs:o,rosterRefs:p,farms:b,threshold:m,limit:x,live:C,subject:k,force:R,ghostUrl:T,thresholdSet:v}=K(e?.text||""),y=window.location.origin,r=t.find(".sim-status")[0],c=k?lt(t):null,g=C||c?null:dt(e),j=it(o,p),X=()=>c?{seed:{site:c.site,slug:c.slug},text:c.text,excludePage:{site:c.site,slug:c.slug}}:{},U=(d,h,i)=>{let u=h>0?`${h.toLocaleString()} pages across ${i} domains`:`${i} domain${i===1?"":"s"}`,l=[`${d} \u2014 ${u}`];return v&&l.push(`threshold ${m}`),l.push(`limit ${x}`),C&&l.push("LIVE"),l.join(" \xB7 ")};t.on("dblclick",d=>{$(d.target).closest(".sim-input").length||window.wiki.textEditor(t,e)}),t.on("click",".sim-link",function(d){d.preventDefault();let h=$(this),i=d.shiftKey?null:t.parents(".page");window.wiki.doInternalLink(h.data("title"),i,h.data("site"))});let gt=!o.length||o.length===1&&o[0]==="*"?"on farm":o.length===1?`on ${o[0]}`:"in domains",B=d=>d?` \xB7 cached ${ut(d)}`:"";if(n==="status"){let d=t.find(".sim-list")[0],h=l=>{if(!l)return"unknown";let s=(Date.now()-new Date(l))/864e5;return s<1?"today":s<2?"yesterday":`${Math.floor(s)} days ago`},i=l=>l?new Date(l).toISOString().slice(0,10):"\u2014",u=l=>{if(!l||!l.warm)return"";let s=l.warm,a=Math.round((l.bytes||0)/1e6),f=s.state==="warm"?`warm \u2014 ${s.done.toLocaleString()} sites resident in ${Math.round(s.ms/1e3)} s`:s.state==="warming"?`warming \u2014 ${s.done.toLocaleString()} of ${s.total.toLocaleString()} sites so far`:"not warmed",w=s.capped?" \xB7 <strong>cap reached</strong>, some sites re-parse per query":"";return`<tr><th>Vector store</th><td>${(l.pages||0).toLocaleString()} pages \xB7 ${a} MB of ${Math.round((l.capBytes||0)/1e6)} MB \xB7 ${f}${w}</td></tr>`};(async()=>{try{let l=()=>fetch(`${y}/system/embed.json?text=ping`).then(async S=>S.ok?{ok:!0}:{ok:!1,detail:((await S.json().catch(()=>({}))).error||`status ${S.status}`).replace(/^embedding unavailable: /,"")}).catch(S=>({ok:!1,detail:S.message})),[s,a,f]=await Promise.all([fetch(`${y}/system/similarity-health.json`).then(S=>S.json()),fetch(`${y}/system/indexed-domains.json`).then(S=>S.ok?S.json():[]),l()]),w=s.embedder||{},E=a.map(S=>S.built).filter(Boolean).sort(),L=a.reduce((S,_)=>S+(_.page_count||0),0),I=!f.ok,P=I?`<strong>Semantic search is down</strong> \u2014 a query cannot be turned into a vector right now (${f.detail}), so searches on this page will answer by keyword instead.`:"Semantic search is <strong>up</strong> \u2014 checked just now by embedding a word.",H=w.via==="url"?`delegated to <code>${w.url}</code> (from ${w.source||"config"})`:w.via==="semindex"?"in this process, via the SemIndex plugin":"in this process, in a supervised child";r.style.display="none",d.innerHTML=`<h3>The Index Behind These Answers</h3>
78
+ <p>${P}</p>
79
79
  <table>
80
- <tr><th>Model</th><td>${u.model||"\u2014"} \xB7 ${u.dim||"\u2014"} dimensions</td></tr>
81
- <tr><th>Embedder</th><td>${A}${k?" \u2014 <strong>currently down</strong>":""}</td></tr>
82
- <tr><th>Indexed</th><td>${o.length.toLocaleString()} domains \xB7 ${j.toLocaleString()} pages</td></tr>
83
- <tr><th>Newest page vectors</th><td>${i(w[w.length-1])} (${p(w[w.length-1])})</td></tr>
84
- <tr><th>Oldest page vectors</th><td>${i(w[0])} (${p(w[0])})</td></tr>
85
- <tr><th>Plugin</th><td>wiki-plugin-similarity ${u.version||"\u2014"}</td></tr>
80
+ <tr><th>Model</th><td>${s.model||"\u2014"} \xB7 ${s.dim||"\u2014"} dimensions</td></tr>
81
+ <tr><th>Embedder</th><td>${H}${I?" \u2014 <strong>currently down</strong>":""}</td></tr>
82
+ <tr><th>Indexed</th><td>${a.length.toLocaleString()} domains \xB7 ${L.toLocaleString()} pages</td></tr>
83
+ <tr><th>Newest page vectors</th><td>${i(E[E.length-1])} (${h(E[E.length-1])})</td></tr>
84
+ <tr><th>Oldest page vectors</th><td>${i(E[0])} (${h(E[0])})</td></tr>
85
+ <tr><th>Plugin</th><td>wiki-plugin-similarity ${s.version||"\u2014"}</td></tr>
86
+ ${u(s.store)}
86
87
  </table>
87
88
  <p class="sim-count">A domain's vectors are only rebuilt when its pages change, so an old
88
89
  date means a quiet site, not a broken one. Pages saved since the last build are findable
89
- by keyword but not yet by meaning.</p>`}catch(r){a.textContent=`Index state unavailable: ${r.message}`}})()}else if(n==="list"){let d=t.find(".sim-list")[0],p=(i,r)=>{let u=i.reduce((o,l)=>o+(l.page_count||0),0);a.style.display="none",d.innerHTML=`<h3>Indexed Farm Domains</h3>
90
+ by keyword but not yet by meaning.</p>`}catch(l){r.textContent=`Index state unavailable: ${l.message}`}})()}else if(n==="list"){let d=t.find(".sim-list")[0],h=(i,u)=>{let l=i.reduce((s,a)=>s+(a.page_count||0),0);r.style.display="none",d.innerHTML=`<h3>Indexed Farm Domains</h3>
90
91
  <table>
91
92
  <tr><th>Domain</th><th>Pages</th></tr>
92
- ${i.map(({domain:o,page_count:l})=>`
93
+ ${i.map(({domain:s,page_count:a})=>`
93
94
  <tr>
94
- <td><img class="sim-flag remote" src="${window.wiki.site(o).flag()}"
95
- title="${o}" data-site="${o}"> ${o}</td>
96
- <td>${l!=null?l.toLocaleString():"\u2014"}</td>
95
+ <td><img class="sim-flag remote" src="${window.wiki.site(s).flag()}"
96
+ title="${s}" data-site="${s}"> ${s}</td>
97
+ <td>${a!=null?a.toLocaleString():"\u2014"}</td>
97
98
  </tr>`).join("")}
98
99
  </table>
99
- <p class="sim-count">${i.length} domains \u2014 ${u.toLocaleString()} pages${_(r)}</p>`};g?.domains?p(g.domains,g.ts):(async()=>{try{let i=await E,r=i.length?i.join(","):"*",u=`${y}/system/indexed-domains.json?pattern=${encodeURIComponent(r)}&limit=${x}`,o=await fetch(u);if(!o.ok)throw new Error(`indexed-domains failed: ${o.status}`);let l=await o.json();if(!l.length){a.textContent="No indexed domains found";return}p(l,null),M(e,{domains:l})}catch(i){a.textContent=`Error: ${i.message}`}})()}else if(n==="similar"){let d=t.find(".sim-results")[0],p=(i,r)=>{if(!i.length){a.textContent=`No similar pages found above threshold ${m}`;return}d.innerHTML=`<h3>Similar Pages</h3><ul>${i.map(({domain:u,slug:o,title:l,score:f})=>`<li>${Y(u,o,l,f)}</li>`).join("")}</ul><p class="sim-count">${i.length} found ${pt}${_(r)}</p>`,a.style.display="none"};g?.scored?p(g.scored,g.ts):(async()=>{try{let i=t.parents(".page"),r=c||(()=>{let w=i.find(".title").text().trim()||document.title;return{slug:nt(w),site:window.location.hostname,title:w,text:null,isSelf:!0}})(),u=await z(await E,y),o=u.reduce((w,j)=>w+j.pages.length,0);a.textContent=(c?`${O(r)} \xB7 `:"")+`Searching ${o.toLocaleString()} pages\u2026`;let l=await at(r.slug,r.site);if(!l){a.textContent="Embedding page (not yet indexed)\u2026";let w=r.text||i.find(".item").map((j,k)=>$(k).text().trim()).get().filter(Boolean).join(`
100
- `);l=await N(w||r.title,y)}let f=q(l,u,{threshold:m,limit:x,excludeSlug:r.slug,excludeDomain:r.site});p(f,null),c&&(a.textContent=O(r),a.style.display=""),f.length&&!c&&M(e,{scored:f})}catch(i){a.textContent=`Error: ${i.message}`}})()}else if(n==="ghost"){let d=t.find(".sim-btn")[0],p=async()=>{if(!T){a.textContent="No URL \u2014 GHOST needs a page-json URL";return}d.disabled=!0,a.textContent="Fetching\u2026";try{let i=await fetch(T);if(!i.ok)throw new Error(`fetch failed: ${i.status}`);let r=await i.json();window.wiki.showResult(window.wiki.newPage(r),{$page:t.parents(".page")}),a.textContent=""}catch(i){a.textContent=`Error: ${i.message}`}finally{d.disabled=!1}};d.addEventListener("click",p)}else if(n==="build"){let d=t.find(".sim-btn")[0],p=async()=>{d.disabled=!0,a.textContent="Building index\u2026 (may take a while for large scopes)";try{let i=encodeURIComponent((s.length?s:["*"]).join(",")),r=await fetch(`${y}/system/build-index.json?domains=${i}&force=${R?1:0}`);if(r.status===501){let o=await r.json().catch(()=>({}));throw new Error(o.hint||"indexing runs on the farm indexer, not this server")}if(!r.ok)throw new Error(`build-index failed: ${r.status}`);let u=await r.json();window.wiki.showResult(window.wiki.newPage(u),{$page:t.parents(".page")}),a.textContent=""}catch(i){a.textContent=`Error: ${i.message}`}finally{d.disabled=!1}};d.addEventListener("click",p)}else if(n==="report"){let d=t.find(".sim-input")[0],p=t.find(".sim-btn")[0],i=`Domains: ${s.length?s.join(", "):"*"}`;c&&!d.value&&(d.value=c.title),(async()=>{try{let l=await E,f=await U(l.length?l:["*"],y),w=f.reduce((j,k)=>j+(k.page_count||0),0);i=H("Report ready",w,f.length),b.length&&(i+=` \xB7 +${b.length} peer farm${b.length>1?"s":""}`),c&&(i=`${O(c)} \xB7 ${i}`),a.textContent=i}catch(l){a.textContent=`Domain listing unavailable: ${l.message}`}})();let r=new Set([502,503]),u=async(l,f)=>{let w=encodeURIComponent((f.length?f:["*"]).join(",")),j=b.length?`&farms=${encodeURIComponent(b.join(","))}`:"",k=await fetch(`${y}/system/farm-search.json?q=${encodeURIComponent(l)}&pattern=${w}&limit=${x}${j}`);if(!k.ok)throw new Error(`keyword search also failed: ${k.status}`);let D=await k.json();window.wiki.showResult(window.wiki.newPage(D),{$page:t.parents(".page")})},o=async()=>{let l=d.value.trim();if(l){p.disabled=!0,a.textContent=b.length?"Generating report (asking peer farms)\u2026":"Generating report\u2026";try{let f=await E,w=c&&l===c.title?Z():{},j={query:l,domains:f.length?f:["*"],limit:x,live:L,...w};b.length&&(j.farms=b),v&&(j.threshold=m);let k=await fetch(`${y}/system/search-report.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(j)});if(r.has(k.status)){let I=((await k.json().catch(()=>({}))).error||`status ${k.status}`).replace(/^embedding unavailable: /,"");a.textContent="Semantic search unavailable \u2014 searching by keyword instead\u2026",await u(l,f),a.textContent=`Semantic search unavailable (${I}) \u2014 these are keyword matches, ranked by word not meaning.`;return}if(!k.ok)throw new Error(`search-report failed: ${k.status}`);let D=await k.json(),A=window.wiki.newPage(D);window.wiki.showResult(A,{$page:t.parents(".page")}),a.textContent=i}catch(f){a.textContent=`Error: ${f.message}`}finally{p.disabled=!1}}};if(p.addEventListener("click",o),d.addEventListener("keydown",l=>{l.key==="Enter"&&o()}),n==="report"&&s.join(",")==="*"){let l=ht();l&&(d.value=l,o())}}else if(n==="sites"){let d=t.find(".sim-input")[0],p=t.find(".sim-btn")[0],i=`Domains: ${s.length?s.join(", "):"*"}`;c&&!d.value&&(d.value=c.title),(async()=>{try{let u=await E,o=await U(u.length?u:["*"],y),l=o.reduce((f,w)=>f+(w.page_count||0),0);i=H("Site report ready",l,o.length),c&&(i=`${O(c)} \xB7 ${i}`),a.textContent=i}catch(u){a.textContent=`Domain listing unavailable: ${u.message}`}})();let r=async()=>{let u=d.value.trim();if(u){p.disabled=!0,a.textContent="Ranking sites\u2026";try{let o=await E,l=c&&u===c.title?Z():{},f=await fetch(`${y}/system/site-report.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:u,domains:o.length?o:["*"],limit:x,...l})});if(!f.ok)throw new Error(`site-report failed: ${f.status}`);let w=await f.json();window.wiki.showResult(window.wiki.newPage(w),{$page:t.parents(".page")}),a.textContent=i}catch(o){a.textContent=`Error: ${o.message}`}finally{p.disabled=!1}}};p.addEventListener("click",r),d.addEventListener("keydown",u=>{u.key==="Enter"&&r()})}else if(n==="keyword"){let d=t.find(".sim-input")[0],p=t.find(".sim-btn")[0];c&&!d.value&&(d.value=c.title),a.textContent=(c?`${O(c)} \xB7 `:"")+`Keyword search ready \u2014 domains: ${s.length?s.join(", "):"*"} \xB7 limit ${x}`;let i=async()=>{let r=d.value.trim();if(r){p.disabled=!0,a.textContent="Searching live site indexes\u2026";try{let u=await E,o=encodeURIComponent((u.length?u:["*"]).join(",")),l=b.length?`&farms=${encodeURIComponent(b.join(","))}`:"",f=await fetch(`${y}/system/farm-search.json?q=${encodeURIComponent(r)}&pattern=${o}&limit=${x}${l}`);if(!f.ok)throw new Error(`farm-search failed: ${f.status}`);let w=await f.json();window.wiki.showResult(window.wiki.newPage(w),{$page:t.parents(".page")}),a.textContent=`Keyword search ready \u2014 domains: ${s.length?s.join(", "):"*"} \xB7 limit ${x}`}catch(u){a.textContent=`Error: ${u.message}`}finally{p.disabled=!1}}};p.addEventListener("click",i),d.addEventListener("keydown",r=>{r.key==="Enter"&&i()})}else if(n==="author"){let d=t.find(".sim-input")[0],p=t.find(".sim-btn")[0],i=t.find(".sim-results")[0],r=null;c&&!d.value&&(d.value=c.title),(async()=>{try{g||(a.textContent="Resolving domains\u2026"),r=await z(await E,y);let o=r.reduce((l,f)=>l+f.pages.length,0);a.textContent=(c?`${O(c)} \xB7 `:"")+H("Author ready",o,r.length)}catch(o){a.textContent=`Load error: ${o.message}`}})();let u=async()=>{let o=d.value.trim();if(!(!o||!r)){p.disabled=!0,a.textContent="Embedding query\u2026",i.innerHTML="";try{let l=await N(o,y),f=q(l,r,{threshold:m,limit:x,excludeSlug:null,excludeDomain:null}),w=new Set,j=[];for(let{title:I}of f)w.has(I)||(w.add(I),j.push(I));let k=()=>Math.floor(Math.random()*18446744073709552e3).toString(16).padStart(16,"0"),D=j.map(I=>`- [[${I}]]`).join(`
101
- `),A=[{type:"markdown",id:k(),text:`# Similar Pages
100
+ <p class="sim-count">${i.length} domains \u2014 ${l.toLocaleString()} pages${B(u)}</p>`};g?.domains?h(g.domains,g.ts):(async()=>{try{let i=await j,u=i.length?i.join(","):"*",l=`${y}/system/indexed-domains.json?pattern=${encodeURIComponent(u)}&limit=${x}`,s=await fetch(l);if(!s.ok)throw new Error(`indexed-domains failed: ${s.status}`);let a=await s.json();if(!a.length){r.textContent="No indexed domains found";return}h(a,null),A(e,{domains:a})}catch(i){r.textContent=`Error: ${i.message}`}})()}else if(n==="similar"){let d=t.find(".sim-results")[0],h=(i,u)=>{if(!i.length){r.textContent=`No similar pages found above threshold ${m}`;return}d.innerHTML=`<h3>Similar Pages</h3><ul>${i.map(({domain:l,slug:s,title:a,score:f})=>`<li>${Z(l,s,a,f)}</li>`).join("")}</ul><p class="sim-count">${i.length} found ${gt}${B(u)}</p>`,r.style.display="none"};g?.scored?h(g.scored,g.ts):(async()=>{try{let i=t.parents(".page"),u=c||(()=>{let w=i.find(".title").text().trim()||document.title;return{slug:st(w),site:window.location.hostname,title:w,text:null,isSelf:!0}})(),l=await z(await j,y),s=l.reduce((w,E)=>w+E.pages.length,0);r.textContent=(c?`${D(u)} \xB7 `:"")+`Searching ${s.toLocaleString()} pages\u2026`;let a=await rt(u.slug,u.site);if(!a){r.textContent="Embedding page (not yet indexed)\u2026";let w=u.text||i.find(".item").map((E,L)=>$(L).text().trim()).get().filter(Boolean).join(`
101
+ `);a=await q(w||u.title,y)}let f=N(a,l,{threshold:m,limit:x,excludeSlug:u.slug,excludeDomain:u.site});h(f,null),c&&(r.textContent=D(u),r.style.display=""),f.length&&!c&&A(e,{scored:f})}catch(i){r.textContent=`Error: ${i.message}`}})()}else if(n==="ghost"){let d=t.find(".sim-btn")[0],h=async()=>{if(!T){r.textContent="No URL \u2014 GHOST needs a page-json URL";return}d.disabled=!0,r.textContent="Fetching\u2026";try{let i=await fetch(T);if(!i.ok)throw new Error(`fetch failed: ${i.status}`);let u=await i.json();window.wiki.showResult(window.wiki.newPage(u),{$page:t.parents(".page")}),r.textContent=""}catch(i){r.textContent=`Error: ${i.message}`}finally{d.disabled=!1}};d.addEventListener("click",h)}else if(n==="build"){let d=t.find(".sim-btn")[0],h=async()=>{d.disabled=!0,r.textContent="Building index\u2026 (may take a while for large scopes)";try{let i=encodeURIComponent((o.length?o:["*"]).join(",")),u=await fetch(`${y}/system/build-index.json?domains=${i}&force=${R?1:0}`);if(u.status===501){let s=await u.json().catch(()=>({}));throw new Error(s.hint||"indexing runs on the farm indexer, not this server")}if(!u.ok)throw new Error(`build-index failed: ${u.status}`);let l=await u.json();window.wiki.showResult(window.wiki.newPage(l),{$page:t.parents(".page")}),r.textContent=""}catch(i){r.textContent=`Error: ${i.message}`}finally{d.disabled=!1}};d.addEventListener("click",h)}else if(n==="report"){let d=t.find(".sim-input")[0],h=t.find(".sim-btn")[0],i=`Domains: ${o.length?o.join(", "):"*"}`;c&&!d.value&&(d.value=c.title),(async()=>{try{let a=await j,f=await M(a.length?a:["*"],y),w=f.reduce((E,L)=>E+(L.page_count||0),0);i=U("Report ready",w,f.length),b.length&&(i+=` \xB7 +${b.length} peer farm${b.length>1?"s":""}`),c&&(i=`${D(c)} \xB7 ${i}`),r.textContent=i}catch(a){r.textContent=`Domain listing unavailable: ${a.message}`}})();let u=new Set([502,503]),l=async(a,f)=>{let w=encodeURIComponent((f.length?f:["*"]).join(",")),E=b.length?`&farms=${encodeURIComponent(b.join(","))}`:"",L=await fetch(`${y}/system/farm-search.json?q=${encodeURIComponent(a)}&pattern=${w}&limit=${x}${E}`);if(!L.ok)throw new Error(`keyword search also failed: ${L.status}`);let I=await L.json();window.wiki.showResult(window.wiki.newPage(I),{$page:t.parents(".page")})},s=async()=>{let a=d.value.trim();if(a){h.disabled=!0,r.textContent=b.length?"Generating report (asking peer farms)\u2026":"Generating report\u2026";try{let f=await j,w=c&&a===c.title?X():{},E={query:a,domains:f.length?f:["*"],limit:x,live:C,...w};b.length&&(E.farms=b),v&&(E.threshold=m);let L=await fetch(`${y}/system/search-report.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(E)});if(u.has(L.status)){let S=((await L.json().catch(()=>({}))).error||`status ${L.status}`).replace(/^embedding unavailable: /,"");r.textContent="Semantic search unavailable \u2014 searching by keyword instead\u2026",await l(a,f),r.textContent=`Semantic search unavailable (${S}) \u2014 these are keyword matches, ranked by word not meaning.`;return}if(!L.ok)throw new Error(`search-report failed: ${L.status}`);let I=await L.json(),P=window.wiki.newPage(I);window.wiki.showResult(P,{$page:t.parents(".page")}),r.textContent=i}catch(f){r.textContent=`Error: ${f.message}`}finally{h.disabled=!1}}};if(h.addEventListener("click",s),d.addEventListener("keydown",a=>{a.key==="Enter"&&s()}),n==="report"&&o.join(",")==="*"){let a=ht();a&&(d.value=a,s())}}else if(n==="sites"){let d=t.find(".sim-input")[0],h=t.find(".sim-btn")[0],i=`Domains: ${o.length?o.join(", "):"*"}`;c&&!d.value&&(d.value=c.title),(async()=>{try{let l=await j,s=await M(l.length?l:["*"],y),a=s.reduce((f,w)=>f+(w.page_count||0),0);i=U("Site report ready",a,s.length),c&&(i=`${D(c)} \xB7 ${i}`),r.textContent=i}catch(l){r.textContent=`Domain listing unavailable: ${l.message}`}})();let u=async()=>{let l=d.value.trim();if(l){h.disabled=!0,r.textContent="Ranking sites\u2026";try{let s=await j,a=c&&l===c.title?X():{},f=await fetch(`${y}/system/site-report.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:l,domains:s.length?s:["*"],limit:x,...a})});if(!f.ok)throw new Error(`site-report failed: ${f.status}`);let w=await f.json();window.wiki.showResult(window.wiki.newPage(w),{$page:t.parents(".page")}),r.textContent=i}catch(s){r.textContent=`Error: ${s.message}`}finally{h.disabled=!1}}};h.addEventListener("click",u),d.addEventListener("keydown",l=>{l.key==="Enter"&&u()})}else if(n==="keyword"){let d=t.find(".sim-input")[0],h=t.find(".sim-btn")[0];c&&!d.value&&(d.value=c.title),r.textContent=(c?`${D(c)} \xB7 `:"")+`Keyword search ready \u2014 domains: ${o.length?o.join(", "):"*"} \xB7 limit ${x}`;let i=async()=>{let u=d.value.trim();if(u){h.disabled=!0,r.textContent="Searching live site indexes\u2026";try{let l=await j,s=encodeURIComponent((l.length?l:["*"]).join(",")),a=b.length?`&farms=${encodeURIComponent(b.join(","))}`:"",f=await fetch(`${y}/system/farm-search.json?q=${encodeURIComponent(u)}&pattern=${s}&limit=${x}${a}`);if(!f.ok)throw new Error(`farm-search failed: ${f.status}`);let w=await f.json();window.wiki.showResult(window.wiki.newPage(w),{$page:t.parents(".page")}),r.textContent=`Keyword search ready \u2014 domains: ${o.length?o.join(", "):"*"} \xB7 limit ${x}`}catch(l){r.textContent=`Error: ${l.message}`}finally{h.disabled=!1}}};h.addEventListener("click",i),d.addEventListener("keydown",u=>{u.key==="Enter"&&i()})}else if(n==="author"){let d=t.find(".sim-input")[0],h=t.find(".sim-btn")[0],i=t.find(".sim-results")[0],u=null;c&&!d.value&&(d.value=c.title),(async()=>{try{g||(r.textContent="Resolving domains\u2026"),u=await z(await j,y);let s=u.reduce((a,f)=>a+f.pages.length,0);r.textContent=(c?`${D(c)} \xB7 `:"")+U("Author ready",s,u.length)}catch(s){r.textContent=`Load error: ${s.message}`}})();let l=async()=>{let s=d.value.trim();if(!(!s||!u)){h.disabled=!0,r.textContent="Embedding query\u2026",i.innerHTML="";try{let a=await q(s,y),f=N(a,u,{threshold:m,limit:x,excludeSlug:null,excludeDomain:null}),w=new Set,E=[];for(let{title:S}of f)w.has(S)||(w.add(S),E.push(S));let L=()=>Math.floor(Math.random()*18446744073709552e3).toString(16).padStart(16,"0"),I=E.map(S=>`- [[${S}]]`).join(`
102
+ `),P=[{type:"markdown",id:L(),text:`# Similar Pages
102
103
 
103
- ${D}`},{type:"markdown",id:k(),text:"# Reference Links"},...f.map(({domain:I,slug:gt,title:wt,score:$t})=>({type:"reference",id:k(),site:I,slug:gt,title:wt,text:`score ${$t.toFixed(3)}`}))],C=window.wiki.newPage({title:`${o} Results`,story:A,journal:[]});window.wiki.showResult(C,{$page:t.parents(".page")}),a.textContent=`${f.length} pages found`,M(e,{scored:f,query:o})}catch(l){a.textContent=`Error: ${l.message}`}finally{p.disabled=!1}}};p.addEventListener("click",u),d.addEventListener("keydown",o=>{o.key==="Enter"&&u()})}else{let d=t.find(".sim-input")[0],p=t.find(".sim-btn")[0],i=t.find(".sim-results")[0],r=null;g?.scored&&(d.value=g.query||"",i.innerHTML=g.scored.map(({domain:o,slug:l,title:f,score:w})=>`<div class="sim-result">${Y(o,l,f,w)}</div>`).join("")+`<p class="sim-count">Top ${g.scored.length} for "${g.query||""}"${_(g.ts)}</p>`,a.textContent=""),c&&!d.value&&(d.value=c.title),(async()=>{try{g||(a.textContent="Resolving domains\u2026"),r=await z(await E,y);let o=r.reduce((l,f)=>l+f.pages.length,0);a.textContent=(c?`${O(c)} \xB7 `:"")+H("Search ready",o,r.length)}catch(o){a.textContent=`Load error: ${o.message}`}})();let u=async()=>{let o=d.value.trim();if(!(!o||!r)){p.disabled=!0,a.textContent="Embedding query\u2026",i.innerHTML="";try{let l=await N(o,y),f=q(l,r,{threshold:m,limit:x,excludeSlug:null,excludeDomain:null});i.innerHTML=f.map(({domain:w,slug:j,title:k,score:D})=>`<div class="sim-result">${Y(w,j,k,D)}</div>`).join("")+`<p class="sim-count">Top ${f.length} for "${o}"</p>`,a.textContent="",M(e,{scored:f,query:o})}catch(l){a.textContent=`Error: ${l.message}`}finally{p.disabled=!1}}};p.addEventListener("click",u),d.addEventListener("keydown",o=>{o.key==="Enter"&&u()})}};typeof window<"u"&&(window.plugins=window.plugins||{},window.plugins.similarity={emit:Rt,bind:It,editor:(t,e)=>window.wiki.textEditor(t,e)},mt());})();
104
+ ${I}`},{type:"markdown",id:L(),text:"# Reference Links"},...f.map(({domain:S,slug:_,title:wt,score:$t})=>({type:"reference",id:L(),site:S,slug:_,title:wt,text:`score ${$t.toFixed(3)}`}))],H=window.wiki.newPage({title:`${s} Results`,story:P,journal:[]});window.wiki.showResult(H,{$page:t.parents(".page")}),r.textContent=`${f.length} pages found`,A(e,{scored:f,query:s})}catch(a){r.textContent=`Error: ${a.message}`}finally{h.disabled=!1}}};h.addEventListener("click",l),d.addEventListener("keydown",s=>{s.key==="Enter"&&l()})}else{let d=t.find(".sim-input")[0],h=t.find(".sim-btn")[0],i=t.find(".sim-results")[0],u=null;g?.scored&&(d.value=g.query||"",i.innerHTML=g.scored.map(({domain:s,slug:a,title:f,score:w})=>`<div class="sim-result">${Z(s,a,f,w)}</div>`).join("")+`<p class="sim-count">Top ${g.scored.length} for "${g.query||""}"${B(g.ts)}</p>`,r.textContent=""),c&&!d.value&&(d.value=c.title),(async()=>{try{g||(r.textContent="Resolving domains\u2026"),u=await z(await j,y);let s=u.reduce((a,f)=>a+f.pages.length,0);r.textContent=(c?`${D(c)} \xB7 `:"")+U("Search ready",s,u.length)}catch(s){r.textContent=`Load error: ${s.message}`}})();let l=async()=>{let s=d.value.trim();if(!(!s||!u)){h.disabled=!0,r.textContent="Embedding query\u2026",i.innerHTML="";try{let a=await q(s,y),f=N(a,u,{threshold:m,limit:x,excludeSlug:null,excludeDomain:null});i.innerHTML=f.map(({domain:w,slug:E,title:L,score:I})=>`<div class="sim-result">${Z(w,E,L,I)}</div>`).join("")+`<p class="sim-count">Top ${f.length} for "${s}"</p>`,r.textContent="",A(e,{scored:f,query:s})}catch(a){r.textContent=`Error: ${a.message}`}finally{h.disabled=!1}}};h.addEventListener("click",l),d.addEventListener("keydown",s=>{s.key==="Enter"&&l()})}};typeof window<"u"&&(window.plugins=window.plugins||{},window.plugins.similarity={emit:Rt,bind:It,editor:(t,e)=>window.wiki.textEditor(t,e)},pt());})();
104
105
  //# sourceMappingURL=similarity.js.map