sessiongraph 0.0.0-stage → 1.0.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.
- package/LICENSE +21 -0
- package/PRIVACY.md +51 -0
- package/README.md +84 -2
- package/bin/sessiongraph.mjs +43 -0
- package/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/dist/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/dist/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/dist/assets/index-8ZjQU4Q7.js +1 -0
- package/dist/assets/index-BiBqLNvd.js +166 -0
- package/dist/assets/index-DCPujd4X.css +1 -0
- package/dist/assets/scene-CjvdEe_z.js +49 -0
- package/dist/assets/three-B4kj4iLH.js +4394 -0
- package/dist/assets/worker-YMPBjASm.js +2 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +19 -0
- package/dist/sources/NOTICE.txt +4 -0
- package/dist/sources/claude.svg +1 -0
- package/dist/sources/cursor.svg +1 -0
- package/dist/sources/generic.svg +1 -0
- package/dist/sources/openai.svg +1 -0
- package/dist/sources/opencode.svg +1 -0
- package/dist-server/server.mjs +32827 -0
- package/docs/guide.md +223 -0
- package/docs/releases.md +34 -0
- package/docs/v1.0.0.md +31 -0
- package/package.json +72 -4
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
(function(){"use strict";const Fe="ENTRIES",de="KEYS",le="VALUES";class G{constructor(e,t){const n=e._tree,r=Array.from(n.keys());this.set=e,this._type=t,this._path=r.length>0?[{node:n,keys:r}]:[]}next(){const e=this.dive();return this.backtrack(),e}dive(){if(this._path.length===0)return{done:!0,value:void 0};const{node:e,keys:t}=C(this._path);if(C(t)==="")return{done:!1,value:this.result()};const n=e.get(C(t));return this._path.push({node:n,keys:Array.from(n.keys())}),this.dive()}backtrack(){if(this._path.length===0)return;const e=C(this._path).keys;e.pop(),!(e.length>0)&&(this._path.pop(),this.backtrack())}key(){return this.set._prefix+this._path.map(({keys:e})=>C(e)).filter(e=>e!=="").join("")}value(){return C(this._path).node.get("")}result(){switch(this._type){case le:return this.value();case de:return this.key();default:return[this.key(),this.value()]}}[Symbol.iterator](){return this}}const C=s=>s[s.length-1],ve=(s,e,t)=>{const n=new Map;if(e===void 0)return n;const r=e.length+1,o=r+t,i=new Uint8Array(o*r).fill(t+1);for(let c=0;c<r;++c)i[c]=c;for(let c=1;c<o;++c)i[c*r]=c;return he(s,e,t,n,i,1,r,""),n},he=(s,e,t,n,r,o,i,c)=>{const a=o*i;e:for(const d of s.keys())if(d===""){const u=r[a-1];u<=t&&n.set(c,[s.get(d),u])}else{let u=o;for(let p=0;p<d.length;++p,++u){const l=d[p],h=i*u,g=h-i;let m=r[h];const f=Math.max(0,u-t-1),_=Math.min(i-1,u+t);for(let w=f;w<_;++w){const V=l!==e[w],R=r[g+w]+ +V,b=r[g+w+1]+1,F=r[h+w]+1,S=r[h+w+1]=Math.min(R,b,F);S<m&&(m=S)}if(m>t)continue e}he(s.get(d),e,t,n,r,u,i,c+d)}};class v{constructor(e=new Map,t=""){this._size=void 0,this._tree=e,this._prefix=t}atPrefix(e){if(!e.startsWith(this._prefix))throw new Error("Mismatched prefix");const[t,n]=W(this._tree,e.slice(this._prefix.length));if(t===void 0){const[r,o]=X(n);for(const i of r.keys())if(i!==""&&i.startsWith(o)){const c=new Map;return c.set(i.slice(o.length),r.get(i)),new v(c,e)}}return new v(t,e)}clear(){this._size=void 0,this._tree.clear()}delete(e){return this._size=void 0,ze(this._tree,e)}entries(){return new G(this,Fe)}forEach(e){for(const[t,n]of this)e(t,n,this)}fuzzyGet(e,t){return ve(this._tree,e,t)}get(e){const t=K(this._tree,e);return t!==void 0?t.get(""):void 0}has(e){const t=K(this._tree,e);return t!==void 0&&t.has("")}keys(){return new G(this,de)}set(e,t){if(typeof e!="string")throw new Error("key must be a string");return this._size=void 0,H(this._tree,e).set("",t),this}get size(){if(this._size)return this._size;this._size=0;const e=this.entries();for(;!e.next().done;)this._size+=1;return this._size}update(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;const n=H(this._tree,e);return n.set("",t(n.get(""))),this}fetch(e,t){if(typeof e!="string")throw new Error("key must be a string");this._size=void 0;const n=H(this._tree,e);let r=n.get("");return r===void 0&&n.set("",r=t()),r}values(){return new G(this,le)}[Symbol.iterator](){return this.entries()}static from(e){const t=new v;for(const[n,r]of e)t.set(n,r);return t}static fromObject(e){return v.from(Object.entries(e))}}const W=(s,e,t=[])=>{if(e.length===0||s==null)return[s,t];for(const n of s.keys())if(n!==""&&e.startsWith(n))return t.push([s,n]),W(s.get(n),e.slice(n.length),t);return t.push([s,e]),W(void 0,"",t)},K=(s,e)=>{if(e.length===0||s==null)return s;for(const t of s.keys())if(t!==""&&e.startsWith(t))return K(s.get(t),e.slice(t.length))},H=(s,e)=>{const t=e.length;e:for(let n=0;s&&n<t;){for(const o of s.keys())if(o!==""&&e[n]===o[0]){const i=Math.min(t-n,o.length);let c=1;for(;c<i&&e[n+c]===o[c];)++c;const a=s.get(o);if(c===o.length)s=a;else{const d=new Map;d.set(o.slice(c),a),s.set(e.slice(n,n+c),d),s.delete(o),s=d}n+=c;continue e}const r=new Map;return s.set(e.slice(n),r),r}return s},ze=(s,e)=>{const[t,n]=W(s,e);if(t!==void 0){if(t.delete(""),t.size===0)ue(n);else if(t.size===1){const[r,o]=t.entries().next().value;fe(n,r,o)}}},ue=s=>{if(s.length===0)return;const[e,t]=X(s);if(e.delete(t),e.size===0)ue(s.slice(0,-1));else if(e.size===1){const[n,r]=e.entries().next().value;n!==""&&fe(s.slice(0,-1),n,r)}},fe=(s,e,t)=>{if(s.length===0)return;const[n,r]=X(s);n.set(r+e,t),n.delete(r)},X=s=>s[s.length-1],Z="or",me="and",ke="and_not";class E{constructor(e){if(e?.fields==null)throw new Error('MiniSearch: option "fields" must be provided');const t=e.autoVacuum==null||e.autoVacuum===!0?ie:e.autoVacuum;this._options={...te,...e,autoVacuum:t,searchOptions:{...pe,...e.searchOptions||{}},autoSuggestOptions:{...De,...e.autoSuggestOptions||{}}},this._index=new v,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldIds={},this._fieldLength=new Map,this._avgFieldLength=[],this._nextId=0,this._storedFields=new Map,this._dirtCount=0,this._currentVacuum=null,this._enqueuedVacuum=null,this._enqueuedVacuumConditions=ne,this.addFields(this._options.fields)}add(e){const{extractField:t,stringifyField:n,tokenize:r,processTerm:o,fields:i,idField:c}=this._options,a=t(e,c);if(a==null)throw new Error(`MiniSearch: document does not have ID field "${c}"`);if(this._idToShortId.has(a))throw new Error(`MiniSearch: duplicate ID ${a}`);const d=this.addDocumentId(a);this.saveStoredFields(d,e);for(const u of i){const p=t(e,u);if(p==null)continue;const l=r(n(p,u),u),h=this._fieldIds[u],g=new Set(l).size;this.addFieldLength(d,h,this._documentCount-1,g);for(const m of l){const f=o(m,u);if(Array.isArray(f))for(const _ of f)this.addTerm(h,d,_);else f&&this.addTerm(h,d,f)}}}addAll(e){for(const t of e)this.add(t)}addAllAsync(e,t={}){const{chunkSize:n=10}=t,r={chunk:[],promise:Promise.resolve()},{chunk:o,promise:i}=e.reduce(({chunk:c,promise:a},d,u)=>(c.push(d),(u+1)%n===0?{chunk:[],promise:a.then(()=>new Promise(p=>setTimeout(p,0))).then(()=>this.addAll(c))}:{chunk:c,promise:a}),r);return i.then(()=>this.addAll(o))}remove(e){const{tokenize:t,processTerm:n,extractField:r,stringifyField:o,fields:i,idField:c}=this._options,a=r(e,c);if(a==null)throw new Error(`MiniSearch: document does not have ID field "${c}"`);const d=this._idToShortId.get(a);if(d==null)throw new Error(`MiniSearch: cannot remove document with ID ${a}: it is not in the index`);for(const u of i){const p=r(e,u);if(p==null)continue;const l=t(o(p,u),u),h=this._fieldIds[u],g=new Set(l).size;this.removeFieldLength(d,h,this._documentCount,g);for(const m of l){const f=n(m,u);if(Array.isArray(f))for(const _ of f)this.removeTerm(h,d,_);else f&&this.removeTerm(h,d,f)}}this._storedFields.delete(d),this._documentIds.delete(d),this._idToShortId.delete(a),this._fieldLength.delete(d),this._documentCount-=1}removeAll(e){if(e)for(const t of e)this.remove(t);else{if(arguments.length>0)throw new Error("Expected documents to be present. Omit the argument to remove all documents.");this._index=new v,this._documentCount=0,this._documentIds=new Map,this._idToShortId=new Map,this._fieldLength=new Map,this._avgFieldLength=[],this._storedFields=new Map,this._nextId=0}}discard(e){const t=this._idToShortId.get(e);if(t==null)throw new Error(`MiniSearch: cannot discard document with ID ${e}: it is not in the index`);this._idToShortId.delete(e),this._documentIds.delete(t),this._storedFields.delete(t),(this._fieldLength.get(t)||[]).forEach((n,r)=>{this.removeFieldLength(t,r,this._documentCount,n)}),this._fieldLength.delete(t),this._documentCount-=1,this._dirtCount+=1,this.maybeAutoVacuum()}maybeAutoVacuum(){if(this._options.autoVacuum===!1)return;const{minDirtFactor:e,minDirtCount:t,batchSize:n,batchWait:r}=this._options.autoVacuum;this.conditionalVacuum({batchSize:n,batchWait:r},{minDirtCount:t,minDirtFactor:e})}discardAll(e){const t=this._options.autoVacuum;try{this._options.autoVacuum=!1;for(const n of e)this.discard(n)}finally{this._options.autoVacuum=t}this.maybeAutoVacuum()}replace(e){const{idField:t,extractField:n}=this._options,r=n(e,t);this.discard(r),this.add(e)}vacuum(e={}){return this.conditionalVacuum(e)}conditionalVacuum(e,t){return this._currentVacuum?(this._enqueuedVacuumConditions=this._enqueuedVacuumConditions&&t,this._enqueuedVacuum!=null?this._enqueuedVacuum:(this._enqueuedVacuum=this._currentVacuum.then(()=>{const n=this._enqueuedVacuumConditions;return this._enqueuedVacuumConditions=ne,this.performVacuuming(e,n)}),this._enqueuedVacuum)):this.vacuumConditionsMet(t)===!1?Promise.resolve():(this._currentVacuum=this.performVacuuming(e),this._currentVacuum)}async performVacuuming(e,t){const n=this._dirtCount;if(this.vacuumConditionsMet(t)){const r=e.batchSize||se.batchSize,o=e.batchWait||se.batchWait;let i=1;for(const[c,a]of this._index){for(const[d,u]of a)for(const[p]of u)this._documentIds.has(p)||(u.size<=1?a.delete(d):u.delete(p));this._index.get(c).size===0&&this._index.delete(c),i%r===0&&await new Promise(d=>setTimeout(d,o)),i+=1}this._dirtCount-=n}await null,this._currentVacuum=this._enqueuedVacuum,this._enqueuedVacuum=null}vacuumConditionsMet(e){if(e==null)return!0;let{minDirtCount:t,minDirtFactor:n}=e;return t=t||ie.minDirtCount,n=n||ie.minDirtFactor,this.dirtCount>=t&&this.dirtFactor>=n}get isVacuuming(){return this._currentVacuum!=null}get dirtCount(){return this._dirtCount}get dirtFactor(){return this._dirtCount/(1+this._documentCount+this._dirtCount)}has(e){return this._idToShortId.has(e)}getStoredFields(e){const t=this._idToShortId.get(e);if(t!=null)return this._storedFields.get(t)}search(e,t={}){const{searchOptions:n}=this._options,r={...n,...t},o=this.executeQuery(e,t),i=[];for(const[c,{score:a,terms:d,match:u}]of o){const p=d.length||1,l={id:this._documentIds.get(c),score:a*p,terms:Object.keys(u),queryTerms:d,match:u};Object.assign(l,this._storedFields.get(c)),(r.filter==null||r.filter(l))&&i.push(l)}return e===E.wildcard&&r.boostDocument==null||i.sort(_e),i}autoSuggest(e,t={}){t={...this._options.autoSuggestOptions,...t};const n=new Map;for(const{score:o,terms:i}of this.search(e,t)){const c=i.join(" "),a=n.get(c);a!=null?(a.score+=o,a.count+=1):n.set(c,{score:o,terms:i,count:1})}const r=[];for(const[o,{score:i,terms:c,count:a}]of n)r.push({suggestion:o,terms:c,score:i/a});return r.sort(_e),r}get documentCount(){return this._documentCount}get termCount(){return this._index.size}static loadJSON(e,t){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJS(JSON.parse(e),t)}static async loadJSONAsync(e,t){if(t==null)throw new Error("MiniSearch: loadJSON should be given the same options used when serializing the index");return this.loadJSAsync(JSON.parse(e),t)}static getDefault(e){if(te.hasOwnProperty(e))return ee(te,e);throw new Error(`MiniSearch: unknown option "${e}"`)}static loadJS(e,t){const{index:n,documentIds:r,fieldLength:o,storedFields:i,serializationVersion:c}=e,a=this.instantiateMiniSearch(e,t);a._documentIds=P(r),a._fieldLength=P(o),a._storedFields=P(i);for(const[d,u]of a._documentIds)a._idToShortId.set(u,d);for(const[d,u]of n){const p=new Map;for(const l of Object.keys(u)){let h=u[l];c===1&&(h=h.ds),p.set(parseInt(l,10),P(h))}a._index.set(d,p)}return a}static async loadJSAsync(e,t){const{index:n,documentIds:r,fieldLength:o,storedFields:i,serializationVersion:c}=e,a=this.instantiateMiniSearch(e,t);a._documentIds=await U(r),a._fieldLength=await U(o),a._storedFields=await U(i);for(const[u,p]of a._documentIds)a._idToShortId.set(p,u);let d=0;for(const[u,p]of n){const l=new Map;for(const h of Object.keys(p)){let g=p[h];c===1&&(g=g.ds),l.set(parseInt(h,10),await U(g))}++d%1e3===0&&await ye(0),a._index.set(u,l)}return a}static instantiateMiniSearch(e,t){const{documentCount:n,nextId:r,fieldIds:o,averageFieldLength:i,dirtCount:c,serializationVersion:a}=e;if(a!==1&&a!==2)throw new Error("MiniSearch: cannot deserialize an index created with an incompatible version");const d=new E(t);return d._documentCount=n,d._nextId=r,d._idToShortId=new Map,d._fieldIds=o,d._avgFieldLength=i,d._dirtCount=c||0,d._index=new v,d}executeQuery(e,t={}){if(e===E.wildcard)return this.executeWildcardQuery(t);if(typeof e!="string"){const l={...t,...e,queries:void 0},h=e.queries.map(g=>this.executeQuery(g,l));return this.combineResults(h,l.combineWith)}const{tokenize:n,processTerm:r,searchOptions:o}=this._options,i={tokenize:n,processTerm:r,...o,...t},{tokenize:c,processTerm:a}=i,p=c(e).flatMap(l=>a(l)).filter(l=>!!l).map(Le(i)).map(l=>this.executeQuerySpec(l,i));return this.combineResults(p,i.combineWith)}executeQuerySpec(e,t){const n={...this._options.searchOptions,...t},r=(n.fields||this._options.fields).reduce((m,f)=>({...m,[f]:ee(n.boost,f)||1}),{}),{boostDocument:o,weights:i,maxFuzzy:c,bm25:a}=n,{fuzzy:d,prefix:u}={...pe.weights,...i},p=this._index.get(e.term),l=this.termResults(e.term,e.term,1,e.termBoost,p,r,o,a);let h,g;if(e.prefix&&(h=this._index.atPrefix(e.term)),e.fuzzy){const m=e.fuzzy===!0?.2:e.fuzzy,f=m<1?Math.min(c,Math.round(e.term.length*m)):m;f&&(g=this._index.fuzzyGet(e.term,f))}if(h)for(const[m,f]of h){const _=m.length-e.term.length;if(!_)continue;g?.delete(m);const w=u*m.length/(m.length+.3*_);this.termResults(e.term,m,w,e.termBoost,f,r,o,a,l)}if(g)for(const m of g.keys()){const[f,_]=g.get(m);if(!_)continue;const w=d*m.length/(m.length+_);this.termResults(e.term,m,w,e.termBoost,f,r,o,a,l)}return l}executeWildcardQuery(e){const t=new Map,n={...this._options.searchOptions,...e};for(const[r,o]of this._documentIds){const i=n.boostDocument?n.boostDocument(o,"",this._storedFields.get(r)):1;t.set(r,{score:i,terms:[],match:{}})}return t}combineResults(e,t=Z){if(e.length===0)return new Map;const n=t.toLowerCase(),r=Me[n];if(!r)throw new Error(`Invalid combination operator: ${t}`);return e.reduce(r)||new Map}toJSON(){const e=[];for(const[t,n]of this._index){const r={};for(const[o,i]of n)r[o]=Object.fromEntries(i);e.push([t,r])}return{documentCount:this._documentCount,nextId:this._nextId,documentIds:Object.fromEntries(this._documentIds),fieldIds:this._fieldIds,fieldLength:Object.fromEntries(this._fieldLength),averageFieldLength:this._avgFieldLength,storedFields:Object.fromEntries(this._storedFields),dirtCount:this._dirtCount,index:e,serializationVersion:2}}termResults(e,t,n,r,o,i,c,a,d=new Map){if(o==null)return d;for(const u of Object.keys(i)){const p=i[u],l=this._fieldIds[u],h=o.get(l);if(h==null)continue;let g=h.size;const m=this._avgFieldLength[l];for(const f of h.keys()){if(!this._documentIds.has(f)){this.removeTerm(l,f,t),g-=1;continue}const _=c?c(this._documentIds.get(f),t,this._storedFields.get(f)):1;if(!_)continue;const w=h.get(f),V=this._fieldLength.get(f)[l],R=Ee(w,g,this._documentCount,V,m,a),b=n*r*p*_*R,F=d.get(f);if(F){F.score+=b,Te(F.terms,e);const S=ee(F.match,t);S?S.push(u):F.match[t]=[u]}else d.set(f,{score:b,terms:[e],match:{[t]:[u]}})}}return d}addTerm(e,t,n){const r=this._index.fetch(n,we);let o=r.get(e);if(o==null)o=new Map,o.set(t,1),r.set(e,o);else{const i=o.get(t);o.set(t,(i||0)+1)}}removeTerm(e,t,n){if(!this._index.has(n)){this.warnDocumentChanged(t,e,n);return}const r=this._index.fetch(n,we),o=r.get(e);o==null||o.get(t)==null?this.warnDocumentChanged(t,e,n):o.get(t)<=1?o.size<=1?r.delete(e):o.delete(t):o.set(t,o.get(t)-1),this._index.get(n).size===0&&this._index.delete(n)}warnDocumentChanged(e,t,n){for(const r of Object.keys(this._fieldIds))if(this._fieldIds[r]===t){this._options.logger("warn",`MiniSearch: document with ID ${this._documentIds.get(e)} has changed before removal: term "${n}" was not present in field "${r}". Removing a document after it has changed can corrupt the index!`,"version_conflict");return}}addDocumentId(e){const t=this._nextId;return this._idToShortId.set(e,t),this._documentIds.set(t,e),this._documentCount+=1,this._nextId+=1,t}addFields(e){for(let t=0;t<e.length;t++)this._fieldIds[e[t]]=t}addFieldLength(e,t,n,r){let o=this._fieldLength.get(e);o==null&&this._fieldLength.set(e,o=[]),o[t]=r;const c=(this._avgFieldLength[t]||0)*n+r;this._avgFieldLength[t]=c/(n+1)}removeFieldLength(e,t,n,r){if(n===1){this._avgFieldLength[t]=0;return}const o=this._avgFieldLength[t]*n-r;this._avgFieldLength[t]=o/(n-1)}saveStoredFields(e,t){const{storeFields:n,extractField:r}=this._options;if(n==null||n.length===0)return;let o=this._storedFields.get(e);o==null&&this._storedFields.set(e,o={});for(const i of n){const c=r(t,i);c!==void 0&&(o[i]=c)}}}E.wildcard=Symbol("*");const ee=(s,e)=>Object.prototype.hasOwnProperty.call(s,e)?s[e]:void 0,Me={[Z]:(s,e)=>{for(const t of e.keys()){const n=s.get(t);if(n==null)s.set(t,e.get(t));else{const{score:r,terms:o,match:i}=e.get(t);n.score=n.score+r,n.match=Object.assign(n.match,i),ge(n.terms,o)}}return s},[me]:(s,e)=>{const t=new Map;for(const n of e.keys()){const r=s.get(n);if(r==null)continue;const{score:o,terms:i,match:c}=e.get(n);ge(r.terms,i),t.set(n,{score:r.score+o,terms:r.terms,match:Object.assign(r.match,c)})}return t},[ke]:(s,e)=>{for(const t of e.keys())s.delete(t);return s}},Ce={k:1.2,b:.7,d:.5},Ee=(s,e,t,n,r,o)=>{const{k:i,b:c,d:a}=o;return Math.log(1+(t-e+.5)/(e+.5))*(a+s*(i+1)/(s+i*(1-c+c*n/r)))},Le=s=>(e,t,n)=>{const r=typeof s.fuzzy=="function"?s.fuzzy(e,t,n):s.fuzzy||!1,o=typeof s.prefix=="function"?s.prefix(e,t,n):s.prefix===!0,i=typeof s.boostTerm=="function"?s.boostTerm(e,t,n):1;return{term:e,fuzzy:r,prefix:o,termBoost:i}},te={idField:"id",extractField:(s,e)=>s[e],stringifyField:(s,e)=>s.toString(),tokenize:s=>s.split(Ae),processTerm:s=>s.toLowerCase(),fields:void 0,searchOptions:void 0,storeFields:[],logger:(s,e)=>{typeof console?.[s]=="function"&&console[s](e)},autoVacuum:!0},pe={combineWith:Z,prefix:!1,fuzzy:!1,maxFuzzy:6,boost:{},weights:{fuzzy:.45,prefix:.375},bm25:Ce},De={combineWith:me,prefix:(s,e,t)=>e===t.length-1},se={batchSize:1e3,batchWait:10},ne={minDirtFactor:.1,minDirtCount:20},ie={...se,...ne},Te=(s,e)=>{s.includes(e)||s.push(e)},ge=(s,e)=>{for(const t of e)s.includes(t)||s.push(t)},_e=({score:s},{score:e})=>e-s,we=()=>new Map,P=s=>{const e=new Map;for(const t of Object.keys(s))e.set(parseInt(t,10),s[t]);return e},U=async s=>{const e=new Map;let t=0;for(const n of Object.keys(s))e.set(parseInt(n,10),s[n]),++t%1e3===0&&await ye(0);return e},ye=s=>new Promise(e=>setTimeout(e,s)),Ae=/[\n\r\p{Z}\p{P}]+/u,z=24e6,J=48e3,Oe=2,L=s=>JSON.stringify([Oe,s.revision,s.updated,s.created,s.projectID,s.directory]);function Ve(s,e){if(!s||!e||s.id!==e.id||s.version!==L(e)||!Number.isInteger(s.pages)||s.pages<1||s.pages>8||!Number.isInteger(s.characters)||s.characters<0||s.characters>J||typeof s.partial!="boolean"||typeof s.complete!="boolean"||typeof s.capped!="boolean"||s.cursor!==void 0&&(typeof s.cursor!="string"||!/^\d{1,9}$/.test(s.cursor))||s.complete&&(s.partial||s.capped||s.cursor)||!s.complete&&!s.capped&&(!s.cursor||s.pages>=8)||!Array.isArray(s.fragments)||s.fragments.length>J)return!1;let t=0;for(const n of s.fragments){if(!n||!["You","Assistant","Tool","File"].includes(n.kind)||typeof n.text!="string"||n.text.length>2e3||!Number.isFinite(n.time))return!1;t+=n.text.length}return t===s.characters}const x=s=>s.normalize("NFKD").replace(new RegExp("\\p{M}","gu"),"").toLowerCase(),oe=s=>x(s).match(/[\p{L}\p{N}]+/gu)||[],re=s=>oe(s).join(" ");function je(s){const e={text:"",terms:[],phrases:[],filters:[]},t=[];for(const n of s.slice(0,300).match(/(?:[^\s"]+|"[^"]*")+/g)||[]){const r=/^(source|project|dir|model|is|after|before|in):(.+)$/i.exec(n);if(r){const i=r[1].toLowerCase(),c=x(r[2].replace(/^"|"$/g,""));if(i==="in"){const a={title:["title"],files:["files"],messages:["body"],tools:["tools"]};e.fields=a[c],e.fields||(e.error="Use in:title, in:files, in:messages, or in:tools.")}else i==="is"&&!["fork","child","root","archived"].includes(c)?e.error="Use is:fork, is:child, is:root, or is:archived.":["after","before"].includes(i)&&(!/^\d{4}-\d{2}-\d{2}$/.test(c)||!Number.isFinite(Date.parse(c))||new Date(c).toISOString().slice(0,10)!==c)?e.error="Use a valid date in YYYY-MM-DD format.":e.filters.push([i,c]);continue}const o=n.replace(/^"|"$/g,"");n.startsWith('"')&&n.endsWith('"')&&e.phrases.push(re(o)),t.push(o)}return e.text=t.join(" "),e.terms=oe(e.text).slice(0,12),e.text=e.terms.join(" "),e}function Ne(s,e,t=220){const n=x(s),r=e.reduce((i,c)=>{const a=n.indexOf(c);return a<0?i:Math.min(i,a)},1/0),o=Number.isFinite(r)?Math.max(0,r-55):0;return`${o?"…":""}${s.slice(o,o+t).replace(/\s+/g," ").trim()}${s.length>o+t?"…":""}`}class $e{index=new E({fields:["title","project","directory","model","sessionID","files","body","tools"],tokenize:oe,processTerm:x,searchOptions:{combineWith:"AND",prefix:!0,boost:{title:12,files:5,project:3,directory:3,model:2,sessionID:12,body:1,tools:.6}}});entries=new Map;cache=new Map;scope=new Set;setData(e,t){const n=new Set(e.map(o=>o.id));for(const[o,i]of this.entries)n.has(o)||(this.index.remove(i.doc),this.entries.delete(o));const r=new Map(t.map(o=>[o.id,o.name]));for(const o of e){const i=this.entries.get(o.id),c=i&&L(i.session)===L(o),a={id:o.id,title:o.title,project:r.get(o.projectID)||"",directory:o.directory,model:o.model,sessionID:o.id,body:c?i.doc.body:"",files:c?i.doc.files:"",tools:c?i.doc.tools:""};if(c&&Object.keys(a).every(d=>i.doc[d]===a[d])){i.session=o;continue}this.entries.set(o.id,{session:o,doc:a,fragments:c?i.fragments:[]}),i&&this.index.remove(i.doc),this.index.add(a)}this.cache.clear()}setScope(e){this.scope=new Set(e),this.cache.clear()}content(e){return this.entries.get(e)?.fragments.slice()||[]}addContent(e,t){const n=this.entries.get(e);if(!n)return;n.fragments.push(...t);const r={...n.doc};for(const o of t){const i=o.kind==="File"?"files":o.kind==="Tool"?"tools":"body";r[i]+=`
|
|
2
|
+
${o.text}`}this.index.remove(n.doc),this.index.add(r),n.doc=r,this.cache.clear()}search(e,t=!1,n=80){const r=`${e}\0${t}\0${n}`,o=this.cache.get(r);if(o)return o;const i=je(e);if(i.error)return{hits:[],total:0,error:i.error};const c=l=>{const{session:h,doc:g}=l;if(t&&!this.scope.has(h.id))return!1;for(const[m,f]of i.filters)if(m==="source"&&!x(h.source||"opencode").includes(f)||m==="project"&&!x(g.project).includes(f)&&!x(h.projectID).includes(f)||m==="dir"&&!x(h.directory).includes(f)||m==="model"&&!x(h.model).includes(f)||m==="after"&&h.created<new Date(`${f}T00:00:00`).getTime()||m==="before"&&h.created>new Date(`${f}T23:59:59.999`).getTime()||m==="is"&&(f==="fork"&&!h.forkID||f==="child"&&(!h.parentID||h.forkID)||f==="root"&&(h.parentID||h.forkID)||f==="archived"&&!h.archived))return!1;if(i.phrases.length){const m=i.fields||["title","body","files","tools","project","directory","model"];if(!i.phrases.every(f=>m.some(_=>re(g[_]).includes(f))))return!1}return!0},d=(i.terms.length?this.index.search(i.text,{fields:i.fields,fuzzy:l=>l.length<4?!1:l.length>7?2:1,filter:l=>c(this.entries.get(String(l.id)))}):[...this.entries.values()].filter(c).map(l=>({id:l.session.id,score:0,terms:[],match:{}}))).map(l=>{const h=this.entries.get(String(l.id)),g=re(h.doc.title),m=new Set(Object.values(l.match).flat()),f=i.text?g.includes(i.text)&&(!i.fields||i.fields.includes("title"))?5:m.has("title")||m.has("sessionID")?4:m.has("files")?3:m.has("body")?2:1:0;return{match:l,entry:h,tier:f}}).sort((l,h)=>h.tier-l.tier||h.match.score-l.match.score||h.entry.session.updated-l.entry.session.updated||l.entry.session.id.localeCompare(h.entry.session.id)),p={hits:d.slice(0,Math.min(250,Math.max(1,n))).map(({match:l,entry:h,tier:g})=>{const m=l.terms.length?l.terms:i.terms,f=h.fragments.filter(b=>!i.fields||i.fields.includes(b.kind==="File"?"files":b.kind==="Tool"?"tools":"body"));let _,w=0;for(const b of f){const F=x(b.text),S=m.reduce((Pe,Ue)=>Pe+Number(F.includes(Ue)),0);if(S>w&&(_=b,w=S),S===m.length&&S>0)break}const V=new Set(Object.values(l.match).flat()),R=g>=4?V.has("sessionID")&&!V.has("title")?"Session ID":"Title":_?_.kind==="File"?"File":_.kind==="Tool"?"Tool":"Message":i.text?"Metadata":"Recent";return{id:h.session.id,score:l.score,source:R,excerpt:_?Ne(_.text,m):"",terms:m}}),total:d.length};return this.cache.size>=30&&this.cache.delete(this.cache.keys().next().value),this.cache.set(r,p),p}}class Re{available=!0;epoch=0;async restore(e,t,n){const r=new Map(t.map(c=>[c.id,c]));let o,i=0;try{do{const c=await fetch(`/api/sessiongraph/index${o?`?after=${encodeURIComponent(o)}`:""}`);if(!c.ok)throw new Error("Index unavailable");const a=await c.json();this.epoch=a.epoch;for(const d of a.records)Ve(d,r.get(d.id))&&i+d.characters<=z&&(i+=d.characters,n(d));o=a.cursor}while(o);try{globalThis.indexedDB?.deleteDatabase("atlas-search")}catch{}}catch{this.available=!1}}async save(e){if(this.available)try{const t=await fetch("/api/sessiongraph/index",{method:"POST",headers:{"Content-Type":"application/json","X-SessionGraph-Action":"index"},body:JSON.stringify({record:e,epoch:this.epoch})});!t.ok&&t.status!==409&&(this.available=!1)}catch{this.available=!1}}async clear(){const e=await fetch("/api/sessiongraph/index",{method:"DELETE",headers:{"X-SessionGraph-Action":"index"}});if(this.available=e.ok,!e.ok)throw new Error("Could not clear saved index.")}}const k=new $e,q=new Re,y=new Map,D=new Set;let T=!1,Q=0,I=0,M=0,B=!1,A,O,xe=[],ce,be=0;const Y=new Set,j=s=>postMessage(s);function N(){if(!O)return;const s=performance.now(),e=k.search(O.text,O.viewOnly,O.limit);xe=e.hits.slice(0,12).map(t=>t.id),j({type:"results",request:O.request,...e,elapsed:performance.now()-s})}function $(){const s=[...y.values()];j({type:"status",status:{indexed:s.filter(e=>e.pages>0).length,complete:s.filter(e=>e.complete).length,total:y.size,characters:I,active:T&&Q>0,limited:I>=z||s.some(e=>e.partial||e.capped),failed:s.filter(e=>e.failed>0).length,restored:D.size,storage:B?A?.sourceID&&q.available?"local":"memory":"restoring"}})}function Se(){ce||(ce=setTimeout(()=>{ce=void 0,N(),$()},200))}function We(){const s=t=>!!(t&&!t.inflight&&!t.complete&&!t.capped&&t.failed<1);for(const t of xe){const n=y.get(t);if(s(n)&&n.pages<2)return n}let e;for(const t of y.values())s(t)&&(!e||t.pages<e.pages)&&(e=t);return e}function ae(){if(!B||!T||I>=z){$();return}for(;Q<2;){const s=We();if(!s)break;s.inflight=!0,Q++;const e=M,t=new AbortController;Y.add(t),(async()=>{try{const n=new URLSearchParams({updated:String(s.session.updated)});s.cursor&&n.set("cursor",s.cursor);const r=await fetch(`/api/sessiongraph/session/${encodeURIComponent(s.session.id)}/content?${n}`,{signal:t.signal});if(!r.ok)throw new Error("Conversation unavailable");const o=await r.json();if(e!==M||t.signal.aborted)return;if(o.id!==s.session.id)throw new Error("Unexpected conversation");const i=Math.min(J,Math.floor(z/Math.max(1,y.size)));let c=Math.min(i-s.characters,z-I);const a=[],d=[...o.fragments].sort((l,h)=>+(h.kind==="File"||h.kind==="You")-+(l.kind==="File"||l.kind==="You")),u=Math.max(160,Math.min(2e3,Math.floor(c/Math.max(1,d.length))));let p=!1;for(const l of d){if(c<=0){p=!0;break}const h=l.text.slice(0,Math.min(c,u));p||=h.length<l.text.length,a.push({...l,text:h}),c-=h.length,s.characters+=h.length,I+=h.length}k.addContent(s.session.id,a),s.pages++,s.partial||=o.truncated||p,s.complete=!o.nextCursor&&!s.partial,s.capped=!s.complete&&(!o.nextCursor||s.characters>=i||s.pages>=8),s.cursor=o.nextCursor||void 0,Se(),A?.sourceID&&await q.save({id:s.session.id,version:L(s.session),fragments:k.content(s.session.id),pages:s.pages,characters:s.characters,partial:s.partial,complete:s.complete,capped:s.capped,cursor:s.cursor})}catch{!t.signal.aborted&&e===M&&s.failed++}finally{s.inflight=!1,Y.delete(t),Q--,T?setTimeout(ae,performance.now()-be<150?150:35):$()}})()}$()}async function Ie(s,e=!1){const t=++M;B=!1,Y.forEach(i=>i.abort());const n=A?.sourceID===s.sourceID&&!e,r=n?new Map(y):new Map;n||(k.setData([],[]),D.clear()),A=s,y.clear(),I=0;for(const i of[...s.sessions].sort((c,a)=>a.updated-c.updated)){const c=r.get(i.id),a=c&&L(c.session)===L(i),d=a?{...c,session:i,inflight:!1}:{session:i,pages:0,characters:0,partial:!1,complete:!1,capped:!1,failed:0,inflight:!1};a||D.delete(i.id),y.set(i.id,d),I+=d.characters}for(const i of D)y.has(i)||D.delete(i);if(k.setData(s.sessions,s.projects),N(),$(),e&&await q.clear(),t!==M||(s.sourceID&&await q.restore(s.sourceID,s.sessions,i=>{if(t!==M)return;const c=y.get(i.id);!c||c.pages||I+i.characters>z||(k.addContent(i.id,i.fragments),Object.assign(c,{pages:i.pages,characters:i.characters,partial:i.partial,complete:i.complete,capped:i.capped,cursor:i.cursor}),I+=i.characters,D.add(i.id),Se())}),t!==M))return;const o=Math.min(J,Math.floor(z/Math.max(1,y.size)));for(const i of y.values())!i.complete&&i.characters>=o&&(i.capped=!0);B=!0,N(),ae()}self.onmessage=s=>{try{const e=s.data;e.type==="data"?Ie(e).catch(()=>j({type:"error",message:"Search index could not load. Reload to retry."})):e.type==="scope"?(k.setScope(e.ids),N()):e.type==="query"?(be=performance.now(),O=e,N()):e.type==="clear-cache"?(T=!1,A&&Ie(A,!0).catch(()=>j({type:"error",message:"Search index could not reset. Reload to retry."}))):(T=e.enabled,T?y.forEach(t=>{t.failed=0}):Y.forEach(t=>t.abort()),ae())}catch(e){j({type:"error",message:e instanceof Error?e.message:"Search unavailable"})}}})();
|
package/dist/favicon.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><rect width="40" height="40" rx="10" fill="#0b1417"/><g fill="none" stroke="#b5efdc" stroke-width="1.7"><path d="m7 28 13-17 13 17M11 24h18M20 11v22"/><circle cx="20" cy="11" r="3" fill="#b5efdc"/><circle cx="7" cy="28" r="2"/><circle cx="33" cy="28" r="2"/></g></svg>
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="theme-color" content="#080c10" />
|
|
7
|
+
<meta
|
|
8
|
+
name="description"
|
|
9
|
+
content="Explore & visualize all your LLM sessions"
|
|
10
|
+
/>
|
|
11
|
+
<title>SessionGraph — Explore & visualize all your LLM sessions</title>
|
|
12
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
13
|
+
<script type="module" crossorigin src="/assets/index-BiBqLNvd.js"></script>
|
|
14
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DCPujd4X.css">
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<div id="app"></div>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
Claude, OpenAI, and OpenCode SVG paths are from Simple Icons (CC0-1.0).
|
|
2
|
+
Claude and OpenCode: https://github.com/simple-icons/simple-icons/tree/develop/icons
|
|
3
|
+
OpenAI: https://github.com/simple-icons/simple-icons/blob/11.15.0/icons/openai.svg
|
|
4
|
+
Brand names and marks belong to their respective owners. SessionGraph is independent.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><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>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m12 1 10 5.8v10.4L12 23 2 17.2V6.8zm0 2.3L4 7.9l8 4.6 8-4.6zM4 10.2v5.9l7 4v-5.9zm9 4v5.9l7-4v-5.9z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="black" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="m12 3 9 5-9 5-9-5zM3 12l9 5 9-5M3 16l9 5 9-5"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22 24H2V0h20zM17 4.8H7v14.4h10z"/></svg>
|