sessiongraph 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-BowMe1f4.js","assets/index-Ci31shU-.js","assets/index-BbP8lcrF.css","assets/index-CRLUUuVS.js"])))=>i.map(i=>d[i]);
2
- import{TimelineScene as X}from"./scene-Cg3ezvud.js";import{i as J,_ as O,c as Y,S as K,p as Z,a as Q,t as ee,s as te,b as B,d as ae,e as oe,f as se,g as re}from"./index-Ci31shU-.js";import"./three-D_1Qt16u.js";const ne="Cosmic Wobbly Disco Sneaky Bouncy Galactic Crispy Dizzy Fuzzy Noodle Groovy Sleepy Spicy Jolly Loopy Squishy Turbo Giggly Velvet Soggy Zippy Fluffy Moonwalking Wiggly Fizzy Snazzy Goofy Jazzy Tiny Chunky Dapper Wacky".split(" "),ie="Wombat Pickle Pancake Badger Potato Narwhal Noodle Goblin Otter Turnip Hamster Comet Dumpling Goose Biscuit Llama Muffin Squid Raccoon Toaster Waffle Penguin Yeti Pudding Walrus Taco Jellybean Platypus Sloth Cactus Donut Mongoose".split(" ");function le(e,t=()=>crypto.getRandomValues(new Uint32Array(1))[0]/2**32){const o=ne.flatMap(s=>ie.map(l=>`${s} ${l}`));for(let s=o.length-1;s>0;s--){const l=Math.floor(t()*(s+1));[o[s],o[l]]=[o[l],o[s]]}return Array.from({length:e},(s,l)=>{const u=Math.floor(l/o.length);return`Project ${"Mega".repeat(u)}${o[l%o.length]}`})}function ce(e){const t=le(e.lanes.length),o=new Map(e.nodes.map((i,a)=>[i.session.id,`session-${a}`])),s=new Map(e.lanes.flatMap((i,a)=>i.nodes.map(r=>[r.session.id,`project-${a}`]))),l=e.nodes.map(i=>{const a=i.session,r={id:o.get(a.id),title:"Session",projectID:s.get(a.id),directory:"",created:a.created,updated:a.created,activity:a.activity&&{firstMessageAt:a.activity.firstMessageAt,lastMessageAt:a.activity.lastMessageAt,userMessages:a.activity.userMessages,untimedUserMessages:a.activity.untimedUserMessages},archived:!1,model:"",provider:"",agent:"",cost:null,source:a.source==="continue"?"continue":a.source==="opencode"||!a.source?"opencode":"unknown",tokens:a.tokens};return a.parentID&&o.has(a.parentID)&&(r.parentID=o.get(a.parentID)),a.forkID&&o.has(a.forkID)&&(r.forkID=o.get(a.forkID)),{session:r,position:[...i.position],startPosition:[...i.startPosition],color:i.color,radius:i.radius}}),u=new Map(l.map(i=>[i.session.id,i]));return{start:e.start,end:e.end,timeFrame:e.timeFrame&&{...e.timeFrame},nodes:l,edges:e.edges.map(i=>({from:o.get(i.from),to:o.get(i.to),kind:i.kind})),lanes:e.lanes.map((i,a)=>({key:`project-${a}`,label:t[a],color:i.color,kind:"directory",y:i.y,z:i.z,nodes:i.nodes.map(r=>u.get(o.get(r.session.id)))}))}}const F={gif:{label:"GIF",description:"GIF animation",mime:"image/gif",filename:"sessiongraph-playback.gif"},mp4:{label:"MP4",description:"MP4 video",mime:"video/mp4",filename:"sessiongraph-playback.mp4"}},_=`My coding sessions, visualized with SessionGraph.
3
- https://github.com/arvindell/sessiongraph`,de=`https://x.com/intent/tweet?text=${encodeURIComponent(_)}`,W=e=>e instanceof Error&&e.name==="AbortError";async function ue(e,t,o){const{label:s,description:l,mime:u,filename:i}=F[o];try{if(J()){const[{save:a},{writeFile:r}]=await Promise.all([O(()=>import("./index-BowMe1f4.js"),__vite__mapDeps([0,1,2])),O(()=>import("./index-CRLUUuVS.js"),__vite__mapDeps([3,1,2]))]),h=await a({title:`Save SessionGraph ${s}`,defaultPath:i,filters:[{name:l,extensions:[o]}]});if(!h)return"cancelled";await r(h,new Uint8Array(await e.arrayBuffer()))}else{const a=window.showSaveFilePicker;if(a){const h=await(await a.call(window,{suggestedName:i,types:[{description:l,accept:{[u]:[`.${o}`]}}]})).createWritable();try{await h.write(e),await h.close()}catch(c){throw await h.abort().catch(()=>{}),c}}else{const r=document.createElement("a");return r.href=t,r.download=i,document.body.append(r),r.click(),r.remove(),"downloaded"}}return"saved"}catch(a){if(W(a))return"cancelled";throw a}}const w=960,T=600,he=e=>Intl.NumberFormat("en",{notation:"compact",maximumFractionDigits:1}).format(e);function pe(e,t,o,s,l,u){const r=T-122,h=Math.max(1,...s);e.fillStyle="#91afa2",e.font='12px "Geist Variable", sans-serif',e.fillText("SessionGraph",28,32);for(let p=0;p<s.length;p++){const f=Math.max(2,s[p]/h*22);e.fillStyle=p/s.length<=o?"#91bfae":"#253d39",e.fillRect(260+p/s.length*440,r-f,440/s.length-2,f)}e.fillStyle="#d6f4e8",e.fillRect(260+440*o,r-27,1,31);const c=t.start+(t.end-t.start)*o,x=l.at(c,o===1).tokens;e.textAlign="center",e.fillStyle="#a0baae",e.font='12px "IBM Plex Mono", monospace',e.fillText(re(c,t.end-t.start),w/2,r+23),e.fillStyle="#e7f5ee",e.font='36px "Geist Variable", sans-serif',e.fillText(u(c,o===1).toLocaleString("en"),w/2-105,r+66),e.fillText(l.recorded?he(x):"—",w/2+105,r+66),e.font='12px "Geist Variable", sans-serif',e.fillStyle="#92b0a3",e.fillText("Sessions",w/2-105,r+87),e.fillText("Burnt tokens",w/2+105,r+87),l.missing&&(e.font='9px "Geist Variable", sans-serif',e.fillStyle="#698477",e.fillText(l.recorded?"Known usage only":"Usage unavailable",w/2+105,r+104)),e.textAlign="left"}async function ye(e,t,o,s,l){s.throwIfAborted();const{label:u,mime:i}=F[o],a=Z(e.nodes.map(b=>b.session)),r=Q(e.nodes.map(b=>b.session)),h=ee(e.nodes.map(b=>te(b.session)),e.start,e.end),c=document.createElement("div");c.className="share-render-host",c.setAttribute("aria-hidden","true"),c.style.cssText=`position:fixed;left:-12000px;top:0;width:${w}px;height:${T}px;pointer-events:none;visibility:hidden`,document.body.append(c);const x=document.createElement("canvas");x.width=w,x.height=T;const p=x.getContext("2d",{willReadFrequently:!0});let f,m;try{if(!p)throw new Error("Canvas export is unavailable.");f=new X(c,{onSelect(){},onHover(){},onPlaybackInterrupt(){},onEvent(){},onEventHover(){}},{manual:!0}),f.applyPreferences({...t,quality:"balanced",motion:"on",labels:!0,focusDimming:!1,trails:t.trails==="selected"?"all":t.trails}),f.setGraph(e,!0),f.prepareCapture(),await document.fonts.ready,s.throwIfAborted(),m=o==="mp4"?new Worker(new URL("/assets/mp4-worker-HFPra5JP.js",import.meta.url),{type:"module"}):new Worker(new URL("/assets/gif-worker-CghHEBpp.js",import.meta.url),{type:"module"});const b=(S,I=[])=>new Promise((C,v)=>{s.throwIfAborted();const k=()=>{clearTimeout(P),s.removeEventListener("abort",g),m.onmessage=null,m.onerror=null},g=()=>{k(),v(s.reason)},P=setTimeout(()=>{k(),v(new Error(`${u} encoding timed out. Please try again.`))},6e4);s.addEventListener("abort",g,{once:!0}),m.onmessage=E=>{k(),E.data.error?v(new Error(E.data.error)):C(E.data)},m.onerror=()=>{k(),v(new Error(`Could not start the ${u} encoder.`))},m.postMessage(S,I)});o==="mp4"&&await b({init:!0,width:w,height:T});for(let S=0;S<B;S++){s.throwIfAborted();const I=ae(S);f.captureFrame(I,1/oe,p,se(S)),pe(p,e,I,h,a,r);const C=p.getImageData(0,0,w,T).data.buffer;await b({rgba:C,width:w,height:T},[C]),l((S+1)/B)}const G=await b({finish:!0});return new Blob([G.bytes],{type:i})}finally{m?.terminate(),f?.dispose(),c.remove()}}function ve(e){const t=document.createElement("dialog");t.className="share-dialog",t.setAttribute("aria-labelledby","share-title"),t.innerHTML=`<h2 id="share-title">SessionGraph</h2><p>Project and sessions names are hidden</p>
4
- <div class="share-formats" role="group" aria-label="Animation format"><button data-format="gif" aria-pressed="true">GIF</button><button data-format="mp4" aria-pressed="false">MP4 video</button></div>
5
- <div class="share-preview"><img alt="SessionGraph playback with hidden project and session names" hidden/><video aria-label="SessionGraph playback with hidden project and session names" muted loop playsinline controls hidden></video><div class="share-progress"><progress max="100" value="0" aria-label="Creating GIF"></progress><span role="status">Creating GIF… 0%</span></div></div>
6
- <p class="share-notice" role="status" hidden></p>
7
- <div class="share-actions"><button class="text-button share-close">Cancel</button><button class="secondary-button share-retry" hidden>Try again</button><a class="secondary-button share-x" target="_blank" rel="noopener noreferrer" hidden>Share in X</a><button class="secondary-button share-system" aria-label="Open share tray" aria-controls="playback-share-tray" aria-expanded="false" hidden>Share…</button><button class="primary-button share-save" hidden>Save GIF</button></div>
8
- <section id="playback-share-tray" class="share-tray" aria-label="Share options" hidden><p>Save the animation to attach it in any app.</p><textarea class="share-caption" aria-label="Share caption" readonly rows="3"></textarea><div><button class="secondary-button share-copy">Copy caption</button><a class="secondary-button share-x" target="_blank" rel="noopener noreferrer">Share in X</a><button class="secondary-button share-tray-save">Save GIF</button></div></section>`,document.body.append(t);const o=t.querySelector("img"),s=t.querySelector("video"),l=t.querySelector("progress"),u=t.querySelector('[role="status"]'),i=t.querySelector(".share-progress"),a=t.querySelector(".share-close"),r=t.querySelector(".share-save"),h=t.querySelector(".share-retry"),c=t.querySelector(".share-system"),x=t.querySelector(".share-actions .share-x"),p=t.querySelector(".share-tray"),f=t.querySelector(".share-notice"),m=t.querySelector(".share-tray-save"),b=t.querySelector(".share-copy"),G=t.querySelector(".share-caption");G.value=_;const S=t.querySelectorAll("[data-format]"),I=Y(K);I.setAttribute("aria-hidden","true"),I.setAttribute("stroke-width","1.5"),c.prepend(I);let C,v,k,g,P,E,$="gif",j=Promise.resolve();const D=new Map,M=n=>{f.textContent=n,f.hidden=!n},q=n=>{p.hidden=!n,c.setAttribute("aria-expanded",String(n)),n&&b.focus()},L=()=>{C?.abort(),C=void 0,o.removeAttribute("src"),s.pause(),s.removeAttribute("src"),s.load(),g&&URL.revokeObjectURL(g),g=void 0,v=void 0,k=void 0,q(!1),M(""),t.setAttribute("aria-busy","false")};for(const n of t.querySelectorAll(".share-x"))n.href=de,n.title="Open an X draft, then attach your saved animation",n.onclick=()=>M(`Attach your saved ${F[$].label} in X to include the animation.`);a.onclick=()=>t.close(),t.addEventListener("cancel",n=>{p.hidden||(n.preventDefault(),q(!1),c.focus())}),t.addEventListener("close",()=>{L(),D.clear(),P=void 0,E=void 0,e()});function H(){L();const n=new AbortController;C=n;const d=$,{label:y,mime:R,filename:N}=F[d];for(const A of S)A.setAttribute("aria-pressed",String(A.dataset.format===d));r.textContent=m.textContent=`Save ${y}`,o.hidden=!0,s.hidden=!0,i.hidden=!1,r.hidden=!0,c.hidden=!0,x.hidden=!0,h.hidden=!0,a.textContent="Cancel",l.hidden=!1,l.value=0,l.setAttribute("aria-label",`Creating ${y}`),u.textContent=`Creating ${y}… 0%`,t.setAttribute("aria-busy","true"),j=j.then(async()=>{if(!n.signal.aborted)try{const A=D.get(d)??await ye(P,E,d,n.signal,V=>{if(n.signal.aborted)return;const U=Math.round(V*100);l.value=U,u.textContent=`Creating ${y}… ${U}%`});if(n.signal.aborted)return;D.set(d,A),v=A,k=new File([A],N,{type:R}),g=URL.createObjectURL(A),d==="mp4"?(s.src=g,s.hidden=!1,s.play().catch(()=>{})):(o.src=g,o.hidden=!1),i.hidden=!0,r.hidden=!1,c.hidden=!1,x.hidden=!1,a.textContent="Done"}catch(A){if(n.signal.aborted)return;l.hidden=!0,u.textContent=A instanceof Error?A.message:`Could not create the ${y}.`,h.hidden=!1,a.textContent="Close"}finally{C===n&&t.setAttribute("aria-busy","false")}})}h.onclick=H;for(const n of S)n.onclick=()=>{const d=n.dataset.format;d!==$&&($=d,H())};const z=async()=>{if(!v||!g||r.disabled)return;const n=v,d=$,{label:y}=F[d];r.disabled=!0,m.disabled=!0,M(`Choose where to save your ${y}…`);try{const R=await ue(n,g,d);v===n&&M(R==="saved"?`${y} saved.`:R==="downloaded"?`${y} download started. Check your downloads.`:`Save cancelled. Your ${y} is still ready.`)}catch{v===n&&M(`Could not save the ${y}. Try choosing another location.`)}finally{r.disabled=!1,m.disabled=!1}};return r.onclick=z,m.onclick=z,c.onclick=async()=>{if(!k||c.disabled)return;const n=k,d={files:[n],title:"SessionGraph",text:_};if(!navigator.share||!navigator.canShare?.({files:[n]})){q(p.hidden);return}c.disabled=!0,M("");try{await navigator.share(d)}catch(y){k===n&&!W(y)&&(q(!0),M("Could not open system sharing. Save the animation or choose an option below."))}finally{c.disabled=!1}},b.onclick=async()=>{try{await navigator.clipboard.writeText(_),M("Caption copied. Attach your saved animation with it.")}catch{G.focus(),G.select(),M("Copy the selected caption, then attach your saved animation.")}},{open(n,d){t.open||(P=ce(n),E={...d},t.showModal(),e(),H())},dispose(){L(),D.clear(),P=void 0,E=void 0,t.remove()}}}export{ve as createPlaybackShare};