wiki-plugin-similarity 0.25.1 → 0.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /* wiki-plugin-similarity - 0.25.1 - Sat, 05 Sep 2026 19:34:16 GMT */
1
+ /* wiki-plugin-similarity - 0.25.2 - Sun, 27 Sep 2026 23:12:58 GMT */
2
2
  (()=>{var ue={high:.78,medium:.68,low:.58},he=ue.medium,je=10,me=e=>{let t=[],n=[],s=[],i=null,a=null,l="search",u=!1,E=!1,f=!1,R=null,O=null,D=null,U=null,p=!1,T=(h,m)=>h===m||h.startsWith(m)&&/^[\s:]/.test(h.slice(m.length)),x=(h,m)=>h.slice(m.length).replace(/^\s*:?\s*/,"").trim();for(let h of e.split(`
3
3
  `)){let m=h.trim();if(!m||m.startsWith("#"))continue;let b=m.toUpperCase();if(T(b,"LIVE")){u=!0;continue}if(T(b,"AUTO")){p=!0;continue}if(T(b,"SUBJECT")){E=!0;continue}if(T(b,"AUTHOR")){!t.length&&l==="search"&&(l="author");continue}if(T(b,"REPORT")){l==="search"&&(l="report");continue}if(T(b,"KEYWORD")){l==="search"&&(l="keyword");continue}if(T(b,"SITES")){l==="search"&&(l="sites");continue}if(T(b,"BUILD")){l==="search"&&(l="build");continue}if(T(b,"FORCE")){f=!0;continue}if(T(b,"GHOST")){R=x(m,"GHOST"),l==="search"&&(l="ghost");continue}if(T(b,"BUTTON")){O=x(m,"BUTTON");continue}if(T(b,"BATCH")){let C=x(m,"BATCH").toLowerCase();D=C==="off"||C==="no"||C==="0"?0:parseInt(C)||100;continue}if(T(b,"ALGORITHM")){U=x(m,"ALGORITHM").replace(/^\[\[|\]\]$/g,"").trim()||"search-algorithm",l==="search"&&!t.length&&(l="algorithm");continue}if(T(b,"ROSTER")){let C=x(m,"ROSTER");C&&n.push(C);continue}if(T(b,"FARM")){let C=x(m,"FARM");C&&s.push(C);continue}if(T(b,"LIST")){!t.length&&l==="search"&&(l="list");continue}if(T(b,"STATUS")){l==="search"&&(l="status");continue}if(T(b,"DOOR")){l==="search"&&(l="door");continue}if(T(b,"SIMILAR")){let C=x(b,"SIMILAR").toLowerCase();i=ue[C]||he,!t.length&&l==="search"&&(l="similar");continue}if(T(b,"THRESHOLD")){let C=x(m,"THRESHOLD");i=ue[C.toLowerCase()]??(parseFloat(C)||he);continue}if(T(b,"LIMIT")){a=parseInt(x(m,"LIMIT"))||je;continue}t.push(["PUBLIC","LOCAL","PRIVATE","GALAXY","SITE"].includes(b)?b:m)}return{mode:l,specs:t,rosterRefs:n,farms:s,threshold:i??he,limit:a??je,live:u,subject:E,force:f,ghostUrl:R,label:O,batch:D,algorithm:U,auto:p,thresholdSet:i!==null}},se=e=>e.includes("*")||e.includes("?"),oe=e=>e==="PUBLIC"||e==="LOCAL"||e==="PRIVATE"||e==="GALAXY";var Ie=e=>e.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,""),pe=new Map,ut=async(e,t)=>{if(pe.has(e))return pe.get(e);let n=`${t}/system/indexed-domains.json?pattern=${encodeURIComponent(e)}`,s=await fetch(n);if(!s.ok)throw new Error(`indexed-domains failed: ${s.status}`);let i=await s.json();return pe.set(e,i),i},te=async(e,t)=>{e.length||(e=[window.location.hostname]);let n=new Set,s=[];for(let i of e)if(i==="*"||se(i)||oe(i))for(let a of await ut(i,t))n.has(a.domain)||(n.add(a.domain),s.push(a));else n.has(i)||(n.add(i),s.push({domain:i,page_count:null}));return s},mt=/^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+|localhost)(:\d+)?$/,pt=/^ROSTER ([A-Za-z0-9.\-:]+\/[a-z0-9-]+)$/,ft=/^REFERENCES ([A-Za-z0-9.\-:]+\/[a-z0-9-]+)$/,Ce=async e=>{let t=e.indexOf("/"),n=await fetch(`//${e.slice(0,t)}/${e.slice(t+1)}.json`);if(!n.ok)throw new Error(`roster page ${e} failed: ${n.status}`);return n.json()},Te=async(e,t,n)=>{if(n.has(e))return;n.add(e);let s;try{s=await Ce(e)}catch(i){console.warn(i.message);return}for(let i of s.story||[])if(i.type==="roster")for(let a of(i.text||"").split(/\r?\n/)){let l=a.trim();if(!l)continue;let u=l.match(mt);if(u){t.add(u[0]);continue}let E=l.match(pt);if(E){await Te(E[1],t,n);continue}let f=l.match(ft);if(f)try{let R=await Ce(f[1]);for(let O of R.story||[])O.type==="reference"&&O.site&&t.add(O.site)}catch(R){console.warn(R.message)}}},gt=async e=>{let t=new Set,n=new Set;for(let s of e)await Te(s,t,n);return[...t]},Ae=async(e,t)=>{let n=typeof window<"u"&&window.location?window.location.hostname:null,s=e.map(i=>i.toUpperCase()==="SITE"&&n?n:i);return t.length?[...s,...await gt(t)]:s};var fe=new Map,wt=e=>`${window.location.origin}/system/semantic-vectors.json?domain=${encodeURIComponent(e)}`,yt=async e=>{if(fe.has(e))return fe.get(e);let t=await fetch(wt(e));if(!t.ok)return[];let n=await t.json();return fe.set(e,n),n},ge=async(e,t)=>{let n=await fetch(`${t}/system/embed.json`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:e})});if(!n.ok)throw new Error(`embed failed: ${n.status}`);return(await n.json()).vector};var we=(e,t,{threshold:n,limit:s,excludeSlug:i,excludeDomain:a})=>{let l=[];for(let{domain:u,pages:E}of t)for(let{slug:f,title:R,vector:O}of E){if(f===i&&u===a)continue;let D=0;for(let U=0;U<e.length;U++)D+=e[U]*O[U];D>=n&&l.push({domain:u,slug:f,title:R,score:D})}return l.sort((u,E)=>E.score-u.score),l.slice(0,s)},ye=async(e,t)=>{let n=await te(e,t);return(await Promise.all(n.map(async({domain:i})=>({domain:i,pages:await yt(i)})))).filter(i=>i.pages.length>0)};var $t=new Set(["selected-plugin-pages","search-tool","like-this-page","semantic-search","search-algorithm","personal-search-demo","search-tool-demo"]),bt=e=>(e.attr("id")||"").split("_rev")[0],Re=e=>{let t=e.parents(".page:first"),n=t.prev(".page");for(;n.length&&$t.has(bt(n));)n=n.prev(".page");let s=n.length?n:t,i=(s.attr("id")||"").split("_rev")[0],a=s.data("site")||window.location.hostname,l=s.data("data")||{},u=l.title||s.find(".title").text().trim()||i,E=[u,...(l.story||[]).filter(f=>f.type==="markdown"||f.type==="paragraph").map(f=>(f.text||"").trim()).filter(Boolean)].join(`
4
4
  `).slice(0,2e3);return{slug:i,site:a,title:u,text:E,isSelf:!n.length}},J=e=>`Subject: ${e.title}${e.isSelf?" (this page)":` @ ${e.site}`}`;var Oe=e=>`sim-cache-${e}`,Me=e=>{try{let t=JSON.parse(localStorage.getItem(Oe(e.id))||"null");return t?.text===(e.text||"")?t:null}catch{return null}},ee=(e,t)=>{try{localStorage.setItem(Oe(e.id),JSON.stringify({text:e.text||"",ts:Date.now(),...t}))}catch{}},$e=e=>{let t=Math.floor((Date.now()-e)/1e3);return t<60?`${t}s ago`:t<3600?`${Math.floor(t/60)}m ago`:t<86400?`${Math.floor(t/3600)}h ago`:`${Math.floor(t/86400)}d ago`};var F=e=>`${e.site} ${e.slug}`,xt=(e,t,n)=>{let s=new Set(e.map(F));return t.slice(0,n).filter(i=>!s.has(F(i))).length},vt=(e,t,n,s)=>{let i=new Map;e.forEach((R,O)=>{s.has(F(R))&&i.set(O,R)});let a=new Set([...i.values()].map(F)),l=t.filter(R=>!a.has(F(R))),u=[],E=0,f=Math.max(n,i.size?Math.max(...i.keys())+1:0);for(let R=0;R<f;R++)i.has(R)?u.push(i.get(R)):E<l.length&&u.push(l[E++]);return u},St=(e,t)=>{let n=new Map(t.map(s=>[F(s),s]));return e.map(s=>n.get(F(s))||s)},kt=()=>{let e=new Set;try{for(let t of Object.keys(window.wiki?.neighborhood||{}))e.add(t);document.querySelectorAll(".page").forEach(t=>{let n=window.$?window.$(t).data("site"):null;e.add(n||window.location.hostname)})}catch{}return[...e]},De=async(e,t)=>{let n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){let s=new Error(`${e.split("/").pop()} failed: ${n.status}`);throw s.status=n.status,s.body=await n.json().catch(()=>({})),s}return n.json()},Lt=(e,t,n)=>{let s=e.slice(0,n).map(F).join("|"),i=t.slice(0,n).map(F).join("|");return s===i},Pe=async e=>{let{origin:t,query:n,seeded:s={},specs:i,limit:a,batch:l,algorithm:u,render:E,resume:f}=e,R=M=>e.status&&e.status(M),O;if(f&&Array.isArray(f.remaining))O={batches:f.remaining,count:f.total,sites:f.sites||[],siteIndex:f.siteIndex||null,unindexed:f.unindexed||[]};else{let M={roster:[...e.roster||[],...u&&u.liked||[]],neighborhood:kt(),followed:!0,...e.prefer||{}};R("Ranking sites\u2026"),O=await De(`${t}/system/site-rank.json`,{query:n,...s,domains:i,prefer:M,algorithm:u||{},batch:l||100})}let D=O.batches||[],U=O.count||D.reduce((M,G)=>M+G.length,0),p={searched:f?.searched||0,total:U,batches:D.length,done:0,stopped:!1,converged:!1,running:!0,unindexed:O.unindexed||[],answered:f?.answered||{local:0},siteIndex:O.siteIndex||null,siteInfo:new Map((O.sites||[]).map(M=>[M.domain,M])),shown:f?.shown||[],pending:0,opened:new Set(f?.opened||[]),resumed:!!f},T=new Map((f?.merged||[]).map(M=>[F(M),M])),x=[...T.values()].sort((M,G)=>G.score-M.score),h=0,m=()=>{p.stopped=!0};p.stop=m;let b=()=>{try{e.save&&e.save(p.snapshot())}catch{}};p.foldIn=()=>{p.shown=vt(p.shown,x,a,p.opened),p.pending=0,E(x,p),b()},p.markOpened=M=>{p.opened.add(M),E(x,p),b()},p.snapshot=()=>({query:n,total:U,searched:p.searched,converged:p.converged,stopped:p.stopped,merged:x.slice(0,150),shown:p.shown,opened:[...p.opened],remaining:D.slice(p.done),answered:p.answered,siteIndex:p.siteIndex,unindexed:p.unindexed,sites:[...p.siteInfo.values()].slice(0,400)});let C=async M=>{let G={query:n,...s,domains:M,limit:Math.max(a*3,30),flat:!0};e.thresholdSet&&(G.threshold=e.threshold);let c=await De(`${t}/system/search-report.json`,G);for(let r of c.results||[]){let o=F(r),g=T.get(o);(!g||g.score<r.score)&&T.set(o,r)}let y=0;for(let r of c.peers||[])p.answered[r.host]=(p.answered[r.host]||0)+(r.domains||0),y+=r.domains||0;p.answered.local+=Math.max(0,(c.stats&&c.stats.domains||0)-y);let d=[...T.values()].sort((r,o)=>o.score-r.score),w=Lt(x,d,a);x=d,p.searched+=M.length,p.done+=1,h=w?h+1:0,p.shown.length?p.shown=St(p.shown,d):p.shown=d.slice(0,a),p.pending=xt(p.shown,d,a)},W=()=>D.slice(p.done),X=async(M=!1)=>{for(p.running=!0,p.stopped=!1;p.done<D.length&&!p.stopped;)if(await C(D[p.done]),E(x,p),b(),!M&&h>=3&&p.done<D.length){p.converged=!0;break}return p.running=!1,E(x,p),b(),x};return p.continueAll=()=>(p.converged=!1,h=-1/0,X(!0)),f&&f.remaining&&!f.remaining.length?(p.running=!1,p.converged=!!f.converged,E(x,p),{results:x,state:p,remaining:W}):(await X(!1),{results:x,state:p,remaining:W})};var ae="similarity:learned",Et=new Set(["liked","visited","neighbourhood","neighborhood","followed","centroid","fresh","reliable","stale"]),ie=/^([a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+|localhost)(:\d+)?$/,be=e=>{let t={weights:{},always:[],never:[],batch:null,trust:null};for(let n of(e||"").split(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-similarity",
3
- "version": "0.25.1",
3
+ "version": "0.25.2",
4
4
  "description": "Federated Wiki plugin — semantic similarity search across wiki domains using prebuilt vector indexes",
5
5
  "keywords": [
6
6
  "wiki",
package/server/server.js CHANGED
@@ -388,6 +388,8 @@ const startServer = ({ argv, app }) => {
388
388
  // indexer host — the similarity server never writes it).
389
389
  app.get('/system/galaxy-registry.json', (req, res) => {
390
390
  cors(res)
391
+ // Galaxy off (WIKI_GALAXY_VECTORS=off): no tree, so no registry either.
392
+ if (!galaxyDir) return res.status(404).json({ error: 'no galaxy registry on this host' })
391
393
  fs.readFile(path.join(galaxyDir, 'registry.json'), 'utf8', (err, data) => {
392
394
  if (err) return res.status(404).json({ error: 'no galaxy registry on this host' })
393
395
  res.type('application/json').send(data)