sessiongraph-app-darwin-arm64 1.0.8 → 1.0.10
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/package.json +2 -2
- package/payload/SessionGraph.app/Contents/Info.plist +2 -2
- package/payload/SessionGraph.app/Contents/MacOS/sessiongraph +0 -0
- package/payload/SessionGraph.app/Contents/Resources/icon.icns +0 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/node +2 -2
- package/payload/SessionGraph.app/Contents/Resources/resources/web/apple-touch-icon.png +0 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-B5TXKeav.js → index-BNX-8Jnn.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-CWphmptD.js → index-BcoCDV6F.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-fjc8n25E.css → index-BnhC5gO7.css} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-D-Ue5tsr.js → index-BtLEIWKh.js} +5 -5
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{index-BPR2p22J.js → index-RfmyzBnX.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/publishing-DoHRK4Ea.js +26 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/publishing-VJhUmdPH.css +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/{scene-C2kTsRX_.js → scene-B_CpQ0qP.js} +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/share-DPdu1Hbo.js +8 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/brand/icon.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/brand/lockup-light.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/brand/lockup.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/brand/mark-mono.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/brand/mark.svg +1 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/favicon.ico +0 -0
- package/payload/SessionGraph.app/Contents/Resources/resources/web/favicon.svg +1 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/index.html +4 -2
- package/payload/SessionGraph.app/Contents/Resources/resources/web/sources/gemini.svg +1 -1
- package/payload/SessionGraph.app/Contents/_CodeSignature/CodeResources +123 -46
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/publishing-D6ALMt6w.js +0 -12
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/publishing-DG0jrGoB.css +0 -1
- package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/share-BhzLwRnE.js +0 -8
package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/publishing-D6ALMt6w.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import{m as D,h as N,D as q,j as H}from"./index-D-Ue5tsr.js";import{TimelineScene as F}from"./scene-C2kTsRX_.js";import"./three-D_1Qt16u.js";const R={tokens:"Token counts",timestamps:"Session timestamps",messageCounts:"Message counts",messageTimestamps:"Message timestamps",model:"Model used",harness:"Harness used"},j={tokens:!0,timestamps:!0,messageCounts:!0,messageTimestamps:!0,model:!0,harness:!0};function G(e){const i={...j};if(_(e))for(const n of Object.keys(i))typeof e[n]=="boolean"&&(i[n]=e[n]);return(!i.timestamps||!i.messageCounts)&&(i.messageTimestamps=!1),i}const U=1e4,B=2e6,J=1e5,X="Always excluded: project and session names, messages, code, paths, source IDs, and costs. Anonymous groups and recorded branch links are included. Your GitHub username identifies this profile. Selected timestamps and usage will be public.",Y=/^(?:gpt-[3-6](?:\.[0-9])?(?:-(?:turbo|mini|nano|pro|codex|astra|instant|thinking|chat|latest|preview|[0-9]{4,8}))*|o[1-4](?:-(?:mini|pro|preview|[0-9]{4,8}))*|claude-(?:(?:sonnet|opus|haiku)-[3-5](?:[.-][0-9])?|[3-5](?:-[0-9])?-(?:sonnet|opus|haiku))(?:-(?:latest|thinking|[0-9]{8}))*|gemini-[1-4](?:\.[0-9])?-(?:pro|flash)(?:-(?:lite|preview|exp|latest|[0-9]{2,4}))*|deepseek-(?:chat|reasoner|v[3-4](?:\.[0-9])?|r1)|grok-[2-5](?:\.[0-9])?(?:-(?:fast|code|reasoning|non-reasoning|[0-9]))*|kimi-k[1-3](?:\.[0-9])?(?:-thinking)?|minimax-m[1-3](?:\.[0-9])?)$/i,V=e=>{const i=e.split("/").at(-1)||"";return i.length<=100&&Y.test(i)?i.toLowerCase():null},_=e=>!!e&&typeof e=="object"&&!Array.isArray(e),T=(e,i)=>_(e)&&Object.keys(e).length===i.length&&i.every(n=>Object.hasOwn(e,n)),E=(e,i=Number.MAX_SAFE_INTEGER)=>Number.isSafeInteger(e)&&e>=0&&e<=i,M=e=>E(e,Date.UTC(2100,0,1)),I=e=>e===null||E(e);function z(e){const i=()=>{throw new Error("Invalid anonymous graph. Reopen the publishing preview and try again.")};if(!T(e,["version","settings","sessions"])||e.version!==1||!Array.isArray(e.sessions)||!T(e.settings,Object.keys(j))||Object.values(e.settings).some(l=>typeof l!="boolean"))return i();const n=e.settings;if(n.messageTimestamps&&(!n.timestamps||!n.messageCounts))return i();if(e.sessions.length<1||e.sessions.length>U)throw new Error(`Choose between 1 and ${U.toLocaleString("en")} sessions to publish.`);const s=["id","group","parent","fork",...n.timestamps?["timestamps"]:[],...n.tokens?["tokens"]:[],...n.messageCounts?["messages"]:[],...n.messageTimestamps?["messageTimes"]:[],...n.model?["model"]:[],...n.harness?["harness"]:[]];let o=0;for(let l=0;l<e.sessions.length;l++){const a=e.sessions[l];if(!T(a,s)||a.id!==l||!E(a.group,e.sessions.length-1))return i();for(const r of["parent","fork"])if(a[r]!==null&&(!E(a[r],e.sessions.length-1)||a[r]===l))return i();if(n.timestamps&&(!T(a.timestamps,["created","lastMessageAt"])||!M(a.timestamps.created)||a.timestamps.lastMessageAt!==null&&!M(a.timestamps.lastMessageAt))||n.tokens&&!I(a.tokens)||n.messageCounts&&(!T(a.messages,["count","untimed","partial"])||!I(a.messages.count)||!I(a.messages.untimed)||typeof a.messages.partial!="boolean")||n.messageTimestamps&&(!T(a.messageTimes,["values","limited"])||!Array.isArray(a.messageTimes.values)||a.messageTimes.values.length>2e3||typeof a.messageTimes.limited!="boolean"||a.messageTimes.values.some(r=>!M(r))||(o+=a.messageTimes.values.length,o>J))||n.model&&a.model!==null&&(typeof a.model!="string"||V(a.model)!==a.model)||n.harness&&a.harness!==null&&(typeof a.harness!="string"||!N(a.harness)))return i()}const h=e.sessions,m=new Uint8Array(h.length);for(let l=0;l<h.length;l++){if(m[l])continue;const a=[[l,!1]];for(;a.length;){const[r,k]=a.pop();if(k){m[r]=2;continue}if(m[r]===1)return i();if(m[r]!==2){m[r]=1,a.push([r,!0]);for(const g of[h[r].parent,h[r].fork])g!==null&&a.push([g,!1])}}}if(new TextEncoder().encode(JSON.stringify(e)).length>B)throw new Error("This graph is too large. Choose a smaller date range.");return e}function K(e){const i=z(e),n=i.sessions.map(o=>({id:String(o.id),projectID:String(o.group),title:`Session ${o.id+1}`,directory:"",created:o.timestamps?.created??o.id*36e5,updated:o.timestamps?.created??o.id*36e5,tokens:o.tokens??null,cost:null,archived:!1,model:o.model??"",provider:"",agent:"",source:o.harness??void 0,activity:{firstMessageAt:null,lastMessageAt:o.timestamps?.lastMessageAt??null,userMessages:0,untimedUserMessages:0},...o.parent===null?{}:{parentID:String(o.parent)},...o.fork===null?{}:{forkID:String(o.fork)}})),s=[...new Set(i.sessions.map(o=>o.group))].map(o=>({id:String(o),name:`Group ${o+1}`,directory:"",worktrees:[]}));return D(n,s)}const L=e=>e==null?"Unknown":e.toLocaleString(),$=e=>e===null?"Unknown":new Date(e).toLocaleString();function W(e){const i=[`${e.sessions.length.toLocaleString()} sessions`];if(e.settings.tokens){const n=e.sessions.filter(s=>s.tokens!==null);i.push(`${n.reduce((s,o)=>s+o.tokens,0).toLocaleString()} recorded tokens${n.length<e.sessions.length?" (partial coverage)":""}`)}return e.settings.messageCounts&&i.push(`${e.sessions.reduce((n,s)=>n+(s.messages?.count??0),0).toLocaleString()} recorded messages${e.sessions.some(n=>n.messages?.partial)?" (partial history)":""}`),i.join(" · ")}function Q(e,i){const n=K(i);e.classList.add("public-viewer"),e.innerHTML='<div class="public-canvas" aria-label="Anonymous session graph"></div><div class="public-view-controls"><button type="button" data-view="3d" aria-pressed="true">3D</button><button type="button" data-view="2d" aria-pressed="false">2D</button><button type="button" data-fit>Fit view</button></div><div class="public-session" aria-live="polite"><p>Select a session to inspect its public data.</p></div><div class="public-playback"><button type="button" data-play>Play</button><input type="range" min="0" max="1000" value="1000" aria-label="Graph playback position"><output></output></div>';const s=e.querySelector(".public-canvas"),o=e.querySelector(".public-session"),h=e.querySelector("output"),m=e.querySelector("input"),l=e.querySelector("[data-play]");let a=0,r=1,k=0,g=!1;const b=()=>{cancelAnimationFrame(a),a=0,f?.setPlaying(!1),l.textContent="Play"};let f;function c(d){if(f?.select(d),o.replaceChildren(),d===null){o.textContent="Select a session to inspect its public data.";return}const t=i.sessions[Number(d)],u=document.createElement("h3");u.textContent=`Session ${t.id+1}`,o.append(u);const p=(S,x)=>{const A=document.createElement("p"),O=document.createElement("strong");O.textContent=`${S}: `,A.append(O,x),o.append(A)};if(p("Group",String(t.group+1)),t.timestamps&&(p("Created",$(t.timestamps.created)),p("Last message",$(t.timestamps.lastMessageAt))),"tokens"in t&&p("Tokens",L(t.tokens)),t.messages&&(p("Messages",`${L(t.messages.count)}${t.messages.partial?" · partial history":""}`),p("Without timestamps",L(t.messages.untimed))),"model"in t&&p("Model",t.model??"Unknown or private alias"),"harness"in t&&p("Harness",t.harness?H(t.harness):"Unknown"),t.messageTimes){p("Message timestamps",`${t.messageTimes.values.length.toLocaleString()}${t.messageTimes.limited?" · limited":""}`);const S=document.createElement("details"),x=document.createElement("summary");x.textContent="View timestamps",S.append(x);const A=document.createElement("pre");A.textContent=t.messageTimes.values.map($).join(`
|
|
2
|
-
`)||"No recorded timestamps.",S.append(A),o.append(S)}const P=(t.messageTimes?.values??[]).map((S,x)=>({id:`public-${x}`,ordinal:x,kind:"message",name:"Message",role:"user",time:S,timeSource:"recorded",preview:""}));f?.setEvents(P)}try{f=new F(s,{onSelect:c,onHover(){},onPlaybackInterrupt:b,onEvent(){},onEventHover(){}}),f.applyPreferences({...q,muted:!0,clickSounds:!1,focusDimming:!1,messageDots:i.settings.messageTimestamps}),f.setGraph(n,!0)}catch{s.textContent="3D rendering is unavailable. Use the session list below to inspect the published data.",e.querySelector(".public-view-controls").hidden=!0}const w=()=>{f?.setCutoff(r),m.value=String(Math.round(r*1e3)),h.textContent=i.settings.timestamps?new Date(n.start+(n.end-n.start)*r).toLocaleDateString():"Timestamps hidden"},y=d=>{g||(r=Math.min(1,r+Math.min(d-k,100)/35e3),k=d,w(),r===1?b():a=requestAnimationFrame(y))};l.onclick=()=>{if(a)return b();r>=1&&(r=0),k=performance.now(),f?.setPlaying(!0),l.textContent="Pause",a=requestAnimationFrame(y)},m.oninput=()=>{b(),r=Number(m.value)/1e3,w()};for(const d of e.querySelectorAll("[data-view]"))d.onclick=()=>{f?.setFlat(d.dataset.view==="2d");for(const t of e.querySelectorAll("[data-view]"))t.setAttribute("aria-pressed",String(t===d))};e.querySelector("[data-fit]").onclick=()=>f?.reset();const C=document.createElement("label");C.className="public-session-picker",C.textContent="Inspect session ";const v=document.createElement("select");return v.setAttribute("aria-label","Inspect anonymous session"),v.append(new Option("Choose a session","")),i.sessions.forEach(d=>v.append(new Option(`Session ${d.id+1} · Group ${d.group+1}`,String(d.id)))),v.onchange=()=>c(v.value||null),C.append(v),e.append(C),w(),{dispose(){g=!0,b(),f?.dispose(),e.replaceChildren()}}}function se(e,i){const n=document.createElement("dialog");n.className="publishing-dialog",n.setAttribute("aria-labelledby","publishing-title"),n.innerHTML=`<header><h2 id="publishing-title">Publish SessionGraph</h2><button class="text-button" data-close aria-label="Close publishing">Close</button></header>
|
|
3
|
-
<p class="publishing-disclosure"></p><p class="publishing-scope"></p>
|
|
4
|
-
<fieldset class="publishing-fields"><legend>Publishing settings</legend>${Object.entries(R).map(([t,u])=>`<label><input type="checkbox" data-field="${t}"><span>${u}</span></label>`).join("")}</fieldset>
|
|
5
|
-
<p class="publishing-note">Message timestamps require session timestamps and message counts. Models show the last recorded public model ID; private aliases stay hidden. Changes apply when you publish again.</p>
|
|
6
|
-
<div class="publishing-preview"></div><p class="publishing-summary"></p>
|
|
7
|
-
<div class="publishing-account"><span data-account>Not signed in</span><button class="secondary-button" data-login>Sign in with GitHub</button><button class="text-button" data-logout hidden>Sign out</button><a class="secondary-button" href="https://sessiongraph.ai/account" target="_blank" rel="noopener noreferrer" data-manage hidden>Account & organizations ↗</a></div>
|
|
8
|
-
<div class="publishing-connect" hidden><p>Confirm this code in your browser: <strong data-code></strong></p><a class="secondary-button" data-connect target="_blank" rel="noopener noreferrer">Continue in browser ↗</a><button class="text-button" data-check>Check login</button></div>
|
|
9
|
-
<p role="status" class="publishing-status"></p>
|
|
10
|
-
<label class="publishing-confirm"><input type="checkbox" data-confirm><span>I reviewed this preview and want to make the selected data public under my GitHub username.</span></label>
|
|
11
|
-
<footer><button class="text-button" data-animation>Export animation instead</button><button class="text-button" data-json disabled>View exact JSON</button><button class="secondary-button" data-remove hidden>Unpublish</button><button class="primary-button" data-publish disabled>Publish graph</button></footer>
|
|
12
|
-
<a class="publishing-link" target="_blank" rel="noopener noreferrer" hidden></a><pre class="publishing-json" hidden></pre>`,document.body.append(n);const s=t=>n.querySelector(t);s(".publishing-disclosure").textContent=X;let o=[],h={...j},m,l,a=null,r=!1,k=0,g=!1,b=0,f=!1;const c=t=>{s(".publishing-status").textContent=t},w=async(t,u="GET",p)=>{const P=await fetch(`/api/sessiongraph/publishing/${t}`,{method:u,headers:{"Content-Type":"application/json","x-sessiongraph-action":"1"},...p===void 0?{}:{body:JSON.stringify(p)}}),S=await P.json();if(!P.ok)throw new Error(S.error||"Please try again.");return S};function y(){s("[data-publish]").disabled=g||!l||!a||!s("[data-confirm]").checked,s("[data-publish]").textContent=r?"Update public graph":"Publish graph",s("[data-remove]").hidden=!r,s("[data-remove]").disabled=g,s("[data-login]").hidden=!!a,s("[data-logout]").hidden=!a,s("[data-logout]").disabled=g,s("[data-manage]").hidden=!a,s("[data-account]").textContent=a?`Signed in as @${a}`:"Not signed in",s("[data-json]").disabled=!l;for(const u of n.querySelectorAll("[data-field]")){const p=u.dataset.field;u.checked=h[p],u.disabled=g||p==="messageTimestamps"&&(!h.timestamps||!h.messageCounts)}const t=s(".publishing-link");t.hidden=!a||!r,a&&(t.href=`https://sessiongraph.ai/@${a}`,t.textContent=t.href)}async function C(){const t=++k;if(l=void 0,s("[data-confirm]").checked=!1,m?.dispose(),m=void 0,s(".publishing-json").hidden=!0,s(".publishing-json").textContent="",y(),!o.length){s(".publishing-preview").textContent="Select sessions on the map to preview a public graph.";return}s(".publishing-preview").textContent="Preparing local preview…";try{const u=await w("preview","POST",{ids:o,settings:h});if(!n.open||t!==k)return;l=u,h=u.graph.settings,m=Q(s(".publishing-preview"),u.graph),s(".publishing-summary").textContent=W(u.graph),c("Preview prepared locally. Nothing has been uploaded.")}catch(u){t===k&&(s(".publishing-preview").textContent="",c(u.message))}y()}async function v(){const t=await w("status");n.open&&(a=t.username??null,r=!!t.publication,y())}async function d(){if(!(f||!n.open)){f=!0;try{(await w("poll","POST",{})).username&&(window.clearInterval(b),b=0,s(".publishing-connect").hidden=!0,await v(),c("Signed in. Review the preview before publishing."))}catch(t){window.clearInterval(b),b=0,c(t.message)}finally{f=!1}}}s("[data-login]").onclick=async()=>{try{const t=await w("login","POST",{});s("[data-code]").textContent=t.code,s("[data-connect]").href=t.url,s(".publishing-connect").hidden=!1,window.clearInterval(b),b=window.setInterval(()=>{d()},4e3),s("[data-connect]").focus(),c("Continue in your browser to connect this app.")}catch(t){c(t.message)}},s("[data-check]").onclick=()=>{d()},s("[data-logout]").onclick=async()=>{g=!0,y();try{await w("logout","POST",{}),a=null,r=!1,l=void 0,c("Signed out. Your published graph stays online until you unpublish it.")}catch(t){c(t.message)}finally{g=!1,y()}};for(const t of n.querySelectorAll("[data-field]"))t.onchange=()=>{h=G({...h,[t.dataset.field]:t.checked}),C()};return s("[data-confirm]").onchange=y,s("[data-publish]").onclick=async()=>{if(!(!l||!s("[data-confirm]").checked)){g=!0,y(),c("Publishing…");try{await w("publish","POST",{id:l.id,confirmed:!0}),r=!0,l=void 0,s("[data-confirm]").checked=!1,c("Published. Future imports stay local. Publish again to update this snapshot.")}catch(t){c(t.message)}finally{g=!1,y()}}},s("[data-remove]").onclick=async()=>{g=!0,y();try{await w("unpublish","POST",{}),r=!1,c("Unpublished. Your public graph has been removed.")}catch(t){c(t.message)}finally{g=!1,y()}},s("[data-json]").onclick=()=>{const t=s(".publishing-json");t.hidden=!t.hidden,t.textContent=l?JSON.stringify(l.graph,null,2):""},s("[data-animation]").onclick=()=>{n.close(),i()},s("[data-close]").onclick=()=>n.close(),n.addEventListener("close",()=>{k++,window.clearInterval(b),b=0,m?.dispose(),m=void 0,l=void 0,e()}),{async open(t){if(n.open)return;o=[...t],a=null,r=!1,l=void 0,c(""),s(".publishing-connect").hidden=!0,s(".publishing-scope").textContent=`${o.length.toLocaleString()} sessions in the current filtered view. Change filters on the map to choose what you publish.`,n.showModal(),e(),y();const u=v().catch(p=>c(p.message));try{h=G(await w("settings")),await C()}catch(p){c(p.message)}await u},dispose(){window.clearInterval(b),m?.dispose(),n.remove()}}}export{se as createPublishing};
|
package/payload/SessionGraph.app/Contents/Resources/resources/web/assets/publishing-DG0jrGoB.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.public-viewer{position:relative;min-width:0;border:1px solid #c9e3db1a;border-radius:10px;background:#080e13;overflow:hidden;color:#dbe7e3}.public-canvas{position:relative;height:min(62vh,620px);min-height:320px}.public-canvas canvas{display:block}.public-view-controls{position:absolute;top:14px;left:14px;display:flex;gap:5px}.public-viewer button,.public-session-picker select{border:1px solid #c9e3db30;border-radius:5px;background:#101c21;color:#dbe7e3;padding:8px 12px;font:inherit;font-size:12px;cursor:pointer}.public-viewer button[aria-pressed=true]{color:#b0e9d6;border-color:#b0e9d680}.public-session{position:absolute;right:12px;top:12px;max-width:min(280px,50%);max-height:calc(100% - 125px);overflow:auto;padding:14px;background:#0b141ae8;border:1px solid #c9e3db1a;border-radius:6px;font-size:12px}.public-session h3{margin:0 0 10px;font-size:15px;font-weight:500}.public-session p{margin:5px 0;line-height:1.6;color:#a1b6ad;overflow-wrap:anywhere}.public-session strong{font-weight:500;color:#dbe7e3}.public-session pre{white-space:pre-wrap;font-size:10px}.public-session details{margin-top:8px}.public-playback{display:flex;align-items:center;gap:14px;padding:12px 16px;border-top:1px solid #c9e3db1a}.public-playback input{flex:1;min-width:40px;accent-color:#b0e9d6}.public-playback output{font-size:12px;min-width:105px;text-align:right}.public-session-picker{display:flex;align-items:center;gap:12px;padding:0 16px 14px;font-size:12px}.public-session-picker select{flex:1;min-width:0}.public-viewer .scene-labels{position:absolute;inset:0;pointer-events:none;overflow:hidden}.public-viewer .scene-label{position:absolute;left:0;top:0;max-width:155px;padding:5px 8px;font:10px monospace;color:var(--label-color);opacity:0;background:#080f1266;border-radius:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.public-viewer .scene-label.visible{opacity:.55}@media(max-width:600px){.public-session{position:static;max-width:none;max-height:180px;border-radius:0;border-inline:0}.public-playback{gap:8px;padding-inline:10px}.public-playback output{min-width:85px;font-size:10px}}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-BPR2p22J.js","assets/index-D-Ue5tsr.js","assets/index-fjc8n25E.css","assets/index-B5TXKeav.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{TimelineScene as X}from"./scene-C2kTsRX_.js";import{i as J,_ as O,c as Y,S as Z,p as K,a as Q,t as ee,s as te,b as B,d as ae,e as oe,f as re,g as se}from"./index-D-Ue5tsr.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(r=>ie.map(l=>`${r} ${l}`));for(let r=o.length-1;r>0;r--){const l=Math.floor(t()*(r+1));[o[r],o[l]]=[o[l],o[r]]}return Array.from({length:e},(r,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}`])),r=new Map(e.lanes.flatMap((i,a)=>i.nodes.map(s=>[s.session.id,`project-${a}`]))),l=e.nodes.map(i=>{const a=i.session,s={id:o.get(a.id),title:"Session",projectID:r.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)&&(s.parentID=o.get(a.parentID)),a.forkID&&o.has(a.forkID)&&(s.forkID=o.get(a.forkID)),{session:s,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(s=>u.get(o.get(s.session.id)))}))}}const G={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:r,description:l,mime:u,filename:i}=G[o];try{if(J()){const[{save:a},{writeFile:s}]=await Promise.all([O(()=>import("./index-BPR2p22J.js"),__vite__mapDeps([0,1,2])),O(()=>import("./index-B5TXKeav.js"),__vite__mapDeps([3,1,2]))]),h=await a({title:`Save SessionGraph ${r}`,defaultPath:i,filters:[{name:l,extensions:[o]}]});if(!h)return"cancelled";await s(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 s=document.createElement("a");return s.href=t,s.download=i,document.body.append(s),s.click(),s.remove(),"downloaded"}}return"saved"}catch(a){if(W(a))return"cancelled";throw a}}const A=960,T=600,he=e=>Intl.NumberFormat("en",{notation:"compact",maximumFractionDigits:1}).format(e);function pe(e,t,o,r,l,u){const s=T-122,h=Math.max(1,...r);e.fillStyle="#91afa2",e.font='12px "Geist Variable", sans-serif',e.fillText("SessionGraph",28,32);for(let p=0;p<r.length;p++){const m=Math.max(2,r[p]/h*22);e.fillStyle=p/r.length<=o?"#91bfae":"#253d39",e.fillRect(260+p/r.length*440,s-m,440/r.length-2,m)}e.fillStyle="#d6f4e8",e.fillRect(260+440*o,s-27,1,31);const c=t.start+(t.end-t.start)*o,M=l.at(c,o===1).tokens;e.textAlign="center",e.fillStyle="#a0baae",e.font='12px "IBM Plex Mono", monospace',e.fillText(se(c,t.end-t.start),A/2,s+23),e.fillStyle="#e7f5ee",e.font='36px "Geist Variable", sans-serif',e.fillText(u(c,o===1).toLocaleString("en"),A/2-105,s+66),e.fillText(l.recorded?he(M):"—",A/2+105,s+66),e.font='12px "Geist Variable", sans-serif',e.fillStyle="#92b0a3",e.fillText("Sessions",A/2-105,s+87),e.fillText("Burnt tokens",A/2+105,s+87),e.textAlign="left"}async function ye(e,t,o,r,l){r.throwIfAborted();const{label:u,mime:i}=G[o],a=K(e.nodes.map(b=>b.session)),s=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:${A}px;height:${T}px;pointer-events:none;visibility:hidden`,document.body.append(c);const M=document.createElement("canvas");M.width=A,M.height=T;const p=M.getContext("2d",{willReadFrequently:!0});let m,f;try{if(!p)throw new Error("Canvas export is unavailable.");m=new X(c,{onSelect(){},onHover(){},onPlaybackInterrupt(){},onEvent(){},onEventHover(){}},{manual:!0}),m.applyPreferences({...t,quality:"balanced",motion:"on",labels:!0,focusDimming:!1,trails:t.trails==="selected"?"all":t.trails}),m.setGraph(e,!0),m.prepareCapture(),await document.fonts.ready,r.throwIfAborted(),f=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=(w,I=[])=>new Promise((C,v)=>{r.throwIfAborted();const S=()=>{clearTimeout(P),r.removeEventListener("abort",g),f.onmessage=null,f.onerror=null},g=()=>{S(),v(r.reason)},P=setTimeout(()=>{S(),v(new Error(`${u} encoding timed out. Please try again.`))},6e4);r.addEventListener("abort",g,{once:!0}),f.onmessage=E=>{S(),E.data.error?v(new Error(E.data.error)):C(E.data)},f.onerror=()=>{S(),v(new Error(`Could not start the ${u} encoder.`))},f.postMessage(w,I)});o==="mp4"&&await b({init:!0,width:A,height:T});for(let w=0;w<B;w++){r.throwIfAborted();const I=ae(w);m.captureFrame(I,1/oe,p,re(w)),pe(p,e,I,h,a,s);const C=p.getImageData(0,0,A,T).data.buffer;await b({rgba:C,width:A,height:T},[C]),l((w+1)/B)}const $=await b({finish:!0});return new Blob([$.bytes],{type:i})}finally{f?.terminate(),m?.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"),r=t.querySelector("video"),l=t.querySelector("progress"),u=t.querySelector('[role="status"]'),i=t.querySelector(".share-progress"),a=t.querySelector(".share-close"),s=t.querySelector(".share-save"),h=t.querySelector(".share-retry"),c=t.querySelector(".share-system"),M=t.querySelector(".share-actions .share-x"),p=t.querySelector(".share-tray"),m=t.querySelector(".share-notice"),f=t.querySelector(".share-tray-save"),b=t.querySelector(".share-copy"),$=t.querySelector(".share-caption");$.value=_;const w=t.querySelectorAll("[data-format]"),I=Y(Z);I.setAttribute("aria-hidden","true"),I.setAttribute("stroke-width","1.5"),c.prepend(I);let C,v,S,g,P,E,F="gif",j=Promise.resolve();const D=new Map,x=n=>{m.textContent=n,m.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"),r.pause(),r.removeAttribute("src"),r.load(),g&&URL.revokeObjectURL(g),g=void 0,v=void 0,S=void 0,q(!1),x(""),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=()=>x(`Attach your saved ${G[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=F,{label:y,mime:R,filename:N}=G[d];for(const k of w)k.setAttribute("aria-pressed",String(k.dataset.format===d));s.textContent=f.textContent=`Save ${y}`,o.hidden=!0,r.hidden=!0,i.hidden=!1,s.hidden=!0,c.hidden=!0,M.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 k=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,k),v=k,S=new File([k],N,{type:R}),g=URL.createObjectURL(k),d==="mp4"?(r.src=g,r.hidden=!1,r.play().catch(()=>{})):(o.src=g,o.hidden=!1),i.hidden=!0,s.hidden=!1,c.hidden=!1,M.hidden=!1,a.textContent="Done"}catch(k){if(n.signal.aborted)return;l.hidden=!0,u.textContent=k instanceof Error?k.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 w)n.onclick=()=>{const d=n.dataset.format;d!==F&&(F=d,H())};const z=async()=>{if(!v||!g||s.disabled)return;const n=v,d=F,{label:y}=G[d];s.disabled=!0,f.disabled=!0,x(`Choose where to save your ${y}…`);try{const R=await ue(n,g,d);v===n&&x(R==="saved"?`${y} saved.`:R==="downloaded"?`${y} download started. Check your downloads.`:`Save cancelled. Your ${y} is still ready.`)}catch{v===n&&x(`Could not save the ${y}. Try choosing another location.`)}finally{s.disabled=!1,f.disabled=!1}};return s.onclick=z,f.onclick=z,c.onclick=async()=>{if(!S||c.disabled)return;const n=S,d={files:[n],title:"SessionGraph",text:_};if(!navigator.share||!navigator.canShare?.({files:[n]})){q(p.hidden);return}c.disabled=!0,x("");try{await navigator.share(d)}catch(y){S===n&&!W(y)&&(q(!0),x("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(_),x("Caption copied. Attach your saved animation with it.")}catch{$.focus(),$.select(),x("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};
|